├── manifest-translated.ini.tpl ├── .gitignore ├── changelog.md ├── manifest.ini.tpl ├── .gitattributes ├── updateVersion.py ├── style.css ├── developerNotes.md ├── addon ├── installTasks.py ├── locale │ ├── tr │ │ └── LC_MESSAGES │ │ │ └── nvda.po │ └── es │ │ └── LC_MESSAGES │ │ └── nvda.po ├── doc │ ├── tr │ │ └── readme.md │ └── es │ │ └── readme.md └── globalPlugins │ └── beepKeyboard │ ├── beepKeyboardUtils.py │ └── __init__.py ├── site_scons └── site_tools │ └── gettexttool │ └── __init__.py ├── beepKeyboard.code-workspace ├── .github └── workflows │ └── release-on-tag.yaml ├── addonReadme.md ├── readme.md ├── beepKeyboard.pot ├── sconstruct ├── COPYING.txt └── LICENSE /manifest-translated.ini.tpl: -------------------------------------------------------------------------------- 1 | summary = "{addon_summary}" 2 | description = """{addon_description}""" 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | addon/doc/*.css 2 | addon/doc/en/ 3 | *_docHandler.py 4 | *.html 5 | *.ini 6 | *.mo 7 | *.py[co] 8 | *.nvda-addon 9 | .sconsign.dblite 10 | *.code-workspace 11 | *.json -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # version 24.1.1. 2 | 3 | * added support for NVDA 2024.2. 4 | * added spanish locale strings. 5 | * added a donation dialog to support the author. 6 | 7 | # Version 1.7-dev. 8 | 9 | * Updated manifest to add compatibility with NVDA 2021.3.1. 10 | * Updated readme files. 11 | -------------------------------------------------------------------------------- /manifest.ini.tpl: -------------------------------------------------------------------------------- 1 | name = {addon_name} 2 | summary = "{addon_summary}" 3 | description = """{addon_description}""" 4 | author = "{addon_author}" 5 | url = {addon_url} 6 | version = {addon_version} 7 | docFileName = {addon_docFileName} 8 | minimumNVDAVersion = {addon_minimumNVDAVersion} 9 | lastTestedNVDAVersion = {addon_lastTestedNVDAVersion} 10 | updateChannel = {addon_updateChannel} 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Try to ensure that po files in the repo does not include 5 | # source code line numbers. 6 | # Every person expected to commit po files should change their personal config file as described here: 7 | # https://mail.gnome.org/archives/kupfer-list/2010-June/msg00002.html 8 | *.po filter=cleanpo 9 | -------------------------------------------------------------------------------- /updateVersion.py: -------------------------------------------------------------------------------- 1 | import re, sys 2 | 3 | if len(sys.argv) < 2: 4 | print("the version was not detected") 5 | exit(1) 6 | version = sys.argv[1] 7 | print(f"the version recognized is: {version}") 8 | with open("buildVars.py", 'r+', encoding='utf-8') as f: 9 | text = f.read() 10 | text = re.sub('"addon_version" *:.*,', f'"addon_version" : "{version}",', text) 11 | f.seek(0) 12 | f.write(text) 13 | f.truncate() 14 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | body { 3 | font-family : Verdana, Arial, Helvetica, Sans-serif; 4 | line-height: 1.2em; 5 | } 6 | h1, h2 {text-align: center} 7 | dt { 8 | font-weight : bold; 9 | float : left; 10 | width: 10%; 11 | clear: left 12 | } 13 | dd { 14 | margin : 0 0 0.4em 0; 15 | float : left; 16 | width: 90%; 17 | display: block; 18 | } 19 | p { clear : both; 20 | } 21 | a { text-decoration : underline; 22 | } 23 | :active { 24 | text-decoration : none; 25 | } 26 | a:focus, a:hover {outline: solid} 27 | -------------------------------------------------------------------------------- /developerNotes.md: -------------------------------------------------------------------------------- 1 | # Beep keyboard NVDA Add-on # 2 | This add-on allows the user to configure NVDA to beeps with some keyboard events. 3 | 4 | Copyright (C) 2019 David CM 5 | 6 | This package is distributed under the terms of the GNU General Public License, version 2 or later. 7 | 8 | ## Packaging it for distribution 9 | Open a command line, change to the Add-on root folder and run the scons command. The created add-on, if there were no errors, is placed in the root directory. 10 | 11 | ## Notes 12 | * scons and gettext tools on this project are compatible with python 3 only. Doesn't work with python 2.7. -------------------------------------------------------------------------------- /addon/installTasks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # Copyright (C) 2024 David CM, released under the GPL. 3 | # Author: David CM . 4 | 5 | import sys, os, wx, gui, addonHandler 6 | 7 | addonDir = os.path.abspath(os.path.join(os.path.dirname(__file__), "globalPlugins", "beepKeyboard")) 8 | sys.path.append(addonDir) 9 | from beepKeyboardUtils import showDonationsDialog 10 | sys.path.remove(sys.path[-1]) 11 | 12 | addonHandler.initTranslation() 13 | 14 | 15 | DONATE_METHODS = ( 16 | { 17 | 'label': _('Using Paypal'), 18 | 'url': 'https://paypal.me/davicm' 19 | }, 20 | { 21 | 'label': _('using Co-fi'), 22 | 'url': 'https://ko-fi.com/davidacm' 23 | }, 24 | { 25 | 'label': _('See more methods on my github Page'), 26 | 'url': 'https://davidacm.github.io/donations/' 27 | } 28 | ) 29 | 30 | 31 | def onInstall(): 32 | gui.mainFrame.prePopup() 33 | wx.CallAfter(showDonationsDialog, gui.mainFrame, "Beep Keyboard", DONATE_METHODS) 34 | gui.mainFrame.postPopup() 35 | -------------------------------------------------------------------------------- /site_scons/site_tools/gettexttool/__init__.py: -------------------------------------------------------------------------------- 1 | """ This tool allows generation of gettext .mo compiled files, pot files from source code files 2 | and pot files for merging. 3 | 4 | Three new builders are added into the constructed environment: 5 | 6 | - gettextMoFile: generates .mo file from .pot file using msgfmt. 7 | - gettextPotFile: Generates .pot file from source code files. 8 | - gettextMergePotFile: Creates a .pot file appropriate for merging into existing .po files. 9 | 10 | To properly configure get text, define the following variables: 11 | 12 | - gettext_package_bugs_address 13 | - gettext_package_name 14 | - gettext_package_version 15 | 16 | 17 | """ 18 | from SCons.Action import Action 19 | 20 | def exists(env): 21 | return True 22 | 23 | XGETTEXT_COMMON_ARGS = ( 24 | "--msgid-bugs-address='$gettext_package_bugs_address' " 25 | "--package-name='$gettext_package_name' " 26 | "--package-version='$gettext_package_version' " 27 | "-c -o $TARGET $SOURCES" 28 | ) 29 | 30 | def generate(env): 31 | env.SetDefault(gettext_package_bugs_address="example@example.com") 32 | env.SetDefault(gettext_package_name="") 33 | env.SetDefault(gettext_package_version="") 34 | 35 | env['BUILDERS']['gettextMoFile']=env.Builder( 36 | action=Action("msgfmt -o $TARGET $SOURCE", "Compiling translation $SOURCE"), 37 | suffix=".mo", 38 | src_suffix=".po" 39 | ) 40 | 41 | env['BUILDERS']['gettextPotFile']=env.Builder( 42 | action=Action("xgettext " + XGETTEXT_COMMON_ARGS, "Generating pot file $TARGET"), 43 | suffix=".pot") 44 | 45 | env['BUILDERS']['gettextMergePotFile']=env.Builder( 46 | action=Action("xgettext " + "--omit-header --no-location " + XGETTEXT_COMMON_ARGS, 47 | "Generating pot file $TARGET"), 48 | suffix=".pot") 49 | 50 | -------------------------------------------------------------------------------- /beepKeyboard.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "editor.accessibilitySupport": "on", 9 | "python.linting.enabled": true, 10 | "python.linting.maxNumberOfProblems": 10000, 11 | "python.linting.flake8Args": [ 12 | "--config=..\\..\\nvda\\tests\\lint\\flake8.ini", 13 | "--use-flake8-tabs=true" 14 | ], 15 | "python.linting.flake8Enabled": true, 16 | "python.linting.pylintEnabled": false, 17 | "python.autoComplete.extraPaths": [ 18 | "addon", 19 | "../../nvda/source", 20 | "../../nvda/include/comtypes", 21 | "../../nvda/include/configobj/src", 22 | "../../nvda/include/pyserial", 23 | "../../nvda/include/wxPython", 24 | "../../nvda/miscDeps/python" 25 | ], 26 | "files.insertFinalNewline": true, 27 | "files.trimFinalNewlines": true, 28 | "editor.insertSpaces": false, 29 | "python.testing.unittestArgs": [ 30 | "-v", 31 | "-s", 32 | "tests.unit", 33 | "-p", 34 | "test_*.py" 35 | ], 36 | "python.testing.pytestEnabled": false, 37 | "python.testing.nosetestsEnabled": false, 38 | "python.testing.unittestEnabled": false, 39 | "python.analysis.extraPaths": [ 40 | "addon", 41 | "../../nvda/source", 42 | "../../nvda/include/comtypes", 43 | "../../nvda/include/configobj/src", 44 | "../../nvda/include/pyserial", 45 | "../../nvda/include/wxPython", 46 | "../../nvda/miscDeps/python" 47 | ] 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /.github/workflows/release-on-tag.yaml: -------------------------------------------------------------------------------- 1 | permissions: 2 | contents: write 3 | name: Upload on new tags 4 | on: 5 | push: 6 | tags: 7 | ['*'] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v3 16 | - run: echo -e "scons\nmarkdown">requirements.txt 17 | - name: Set up Python 18 | uses: actions/setup-python@v4 19 | with: 20 | python-version: 3.11 21 | cache: 'pip' 22 | - name: Install dependencies 23 | run: | 24 | pip install scons markdown 25 | sudo apt update 26 | sudo apt install gettext 27 | 28 | - name: Set add-on version from tag 29 | run: | 30 | import re 31 | with open("buildVars.py", 'r+', encoding='utf-8') as f: 32 | text = f.read() 33 | version = "${{ github.ref }}".split("/")[-1] 34 | text = re.sub('"addon_version" *:.*,', '"addon_version" : "%s",' % version, text) 35 | f.seek(0) 36 | f.write(text) 37 | f.truncate() 38 | shell: python 39 | 40 | - name: Build add-on 41 | run: scons 42 | - name: load latest changes from changelog 43 | run: awk '/^# / && !flag {flag=1; next} /^# / && flag {exit} flag && NF' changelog.md > newChanges.md 44 | - name: Calculate sha256 45 | run: sha256sum *.nvda-addon >> newChanges.md 46 | - uses: actions/upload-artifact@v3 47 | with: 48 | name: packaged_addon 49 | path: | 50 | ./*.nvda-addon 51 | ./newChanges.md 52 | 53 | upload_release: 54 | runs-on: ubuntu-latest 55 | if: ${{ startsWith(github.ref, 'refs/tags/') }} 56 | needs: ["build"] 57 | steps: 58 | - name: download releases files 59 | uses: actions/download-artifact@v3 60 | - name: Display structure of downloaded files 61 | run: ls -R 62 | 63 | - name: Release 64 | uses: softprops/action-gh-release@v1 65 | with: 66 | body_path: packaged_addon/newChanges.md 67 | files: packaged_addon/*.nvda-addon 68 | fail_on_unmatched_files: true 69 | prerelease: ${{ contains(github.ref, '-') }} 70 | -------------------------------------------------------------------------------- /addonReadme.md: -------------------------------------------------------------------------------- 1 | # Beep keyboard NVDA Add-on # 2 | 3 | This add-on allows the user to configure NVDA to beeps with some keyboard events. 4 | 5 | Copyright (C) 2019 - 2023 David CM 6 | 7 | This package is distributed under the terms of the GNU General Public License, version 2 or later. 8 | 9 | ## Features 10 | 11 | This add-on provides the following features you can use to adapt NVDA keyboard behavior: 12 | 13 | * Beep for uppercases when caps lock is on: if this feature is enabled, NVDA will beep when you typing an uppercase and caps lock is on. Don't make any more uppercase mistakes! 14 | * Beep for typed characters when shift is pressed: with this feature NVDA will beep if you type a character with shift key pressed. 15 | * Beep for toggle keys changes: with this feature, NVDA will beep higher if a toggle key goes on, and lower tone if it goes off. Please note that Windows has a toggle keis beep function built-in on Ease of Access Center. This native feature works well if you don't use laptop keyboard layout setting. 16 | * Announce toggle keys changes: just when "Beep for toggle keys changes" is on. You can enable or disable NVDA to announce toggle key status. 17 | * Beep for specified characters: NVDA will beep for all characters that you set in advanced settings. 18 | * Disable beeping on password fields: this feature is enabled by default to aboid security risks. Disable it if you want to hear beeps on password fields. 19 | 20 | ## Requirements 21 | You need NVDA 2018.2 or later. 22 | 23 | ## Installation 24 | Just install it as a NVDA add-on. 25 | 26 | ## Usage 27 | To enable or disable features, go to NVDA settings and select beep keyboard category. In that category you can configure all supported features by this add-on. 28 | 29 | "Beep for uppercases when caps lock is on" is enabled by default. 30 | If you need more settings, open the advanced settings dialog that contains the following options: 31 | 32 | * Ignored characters with shift pressed: all characters here will be ignored to beeping when shift is pressed. Escape Sequences are allowed, e.g. "\t" for tab, "\r" for carriage return. 33 | * Beep always for the following characters: set here all characters that you want NVDA beeps for. Escape Sequences are allowed, e.g. "\t" for tab, "\r" for carriage return. 34 | * Select tone to configure: you can configure parameters for all tones. Select one here, and set the parameters in the next text boxes. When change selection, NVDA will beep for the current selected tone with the current parameters set in the dialog. 35 | * Tone pitch: tone pitch for the current selected tone. 36 | * Tone length: tone length for the current selected tone. 37 | * Tone volume: tone volume for the current selected tone. 38 | * Test tone: this button lets you to play a test with the current set parameters. 39 | * Press OK button to save settings or cancel to discard. 40 | 41 | ## contributions, reports and donations 42 | 43 | If you like my project or this software is useful for you in your daily life and you would like to contribute in some way, you can donate via the following methods: 44 | 45 | * [PayPal.](https://paypal.me/davicm) 46 | * [Ko-fi.](https://ko-fi.com/davidacm) 47 | * [cryptocurrencies and other methods.](https://davidacm.github.io/donations/) 48 | 49 | If you want to fix bugs, report problems or new features, you can contact me at: . 50 | 51 | Or in the github repository of this project: 52 | [Beep keyboard on GitHub](https://github.com/davidacm/beepKeyboard) 53 | 54 | You can get the latest release of this add-on in that repository. 55 | -------------------------------------------------------------------------------- /addon/locale/tr/LC_MESSAGES/nvda.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: Bip Klavye 1.9\n" 4 | "POT-Creation-Date: 2023-04-15 12:18+0300\n" 5 | "PO-Revision-Date: 2023-04-15 12:33+0300\n" 6 | "Last-Translator: Umut KORKMAZ \n" 7 | "Language-Team: Umut KORKMAZ \n" 8 | "Language: tr_TR\n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 13 | "X-Generator: Poedit 3.2.2\n" 14 | "X-Poedit-Basepath: ../../../globalPlugins\n" 15 | "X-Poedit-SearchPath-0: .\n" 16 | 17 | #: beepKeyboard/__init__.py:59 18 | msgid "Beep keyboard" 19 | msgstr "Bip klavye" 20 | 21 | #: beepKeyboard/__init__.py:64 22 | msgid "Beep for uppercases when &caps lock is on" 23 | msgstr "Büyük harf kilidi açıkken büyük harfler için bip sesi &çal" 24 | 25 | #: beepKeyboard/__init__.py:67 26 | msgid "Beep for typed characters when &shift is pressed" 27 | msgstr "&Shift tuşuna basıldığında yazılan karakterler için bip sesi çal" 28 | 29 | #: beepKeyboard/__init__.py:70 30 | msgid "Beep for &toggle keys changes" 31 | msgstr "&Geçiş tuşları değişikliği için bip sesi çal" 32 | 33 | #: beepKeyboard/__init__.py:73 34 | msgid "" 35 | "&Announce toggle keys changes (if Beep for toggle keys changes is disabled " 36 | "NVDA will have the original behavior)" 37 | msgstr "" 38 | "&Geçiş tuşları değişikliklerini duyur. (geçiş tuşları değişiklikleri için " 39 | "Bip sesi devre dışı bırakılırsa, NVDA orijinal davranışa sahip olacaktır)" 40 | 41 | #: beepKeyboard/__init__.py:76 42 | msgid "&disable beeping on password fields" 43 | msgstr "Şifre alanlarında bip sesini &devre dışı bırak" 44 | 45 | #: beepKeyboard/__init__.py:80 46 | msgid "&Open advanced options" 47 | msgstr "Gelişmiş seçenekleri &aç" 48 | 49 | #: beepKeyboard/__init__.py:97 50 | msgid "Advanced settings - Keyboard beep" 51 | msgstr "Gelişmiş ayarlar - Klavye bip sesi" 52 | 53 | #: beepKeyboard/__init__.py:102 54 | msgid "&Ignored characters with shift pressed" 55 | msgstr "Shift basılıyken yok say&ılan karakterler" 56 | 57 | #: beepKeyboard/__init__.py:105 58 | msgid "Beep &always for the following characters" 59 | msgstr "&Aşağıdaki karakterler için daima bip sesi" 60 | 61 | #: beepKeyboard/__init__.py:109 62 | msgid "&Select tone to configure" 63 | msgstr "&Yapılandırmak için ton seç" 64 | 65 | #: beepKeyboard/__init__.py:111 66 | msgid "Typed characters with shift pressed" 67 | msgstr "Shift basılıyken yazılan karakterler" 68 | 69 | #: beepKeyboard/__init__.py:113 70 | msgid "Custom characters" 71 | msgstr "Özel karakterler" 72 | 73 | #: beepKeyboard/__init__.py:115 74 | msgid "Typed characters when caps lock is on" 75 | msgstr "Büyük harf kilidi açıkken yazılan karakterler" 76 | 77 | #: beepKeyboard/__init__.py:117 78 | msgid "Toggle key goes off" 79 | msgstr "Geçiş tuşu kapalı" 80 | 81 | #: beepKeyboard/__init__.py:119 82 | msgid "Toggle key goes on" 83 | msgstr "Geçiş tuşu açık" 84 | 85 | #: beepKeyboard/__init__.py:124 86 | msgid "Tone &pitch" 87 | msgstr "ton &perdesi" 88 | 89 | #: beepKeyboard/__init__.py:127 90 | msgid "Tone &length" 91 | msgstr "Ton &uzunluğu" 92 | 93 | #: beepKeyboard/__init__.py:130 94 | msgid "Tone &volume" 95 | msgstr "ton &ses değeri" 96 | 97 | #: beepKeyboard/__init__.py:133 98 | msgid "&Test tone" 99 | msgstr "&Tonu Test Et" 100 | 101 | #: beepKeyboard/__init__.py:148 102 | msgid "You entered a wrong value. Please correct it or discard changes." 103 | msgstr "" 104 | "Yanlış bir değer girdiniz. Lütfen düzeltin veya değişiklikleri iptal edin." 105 | -------------------------------------------------------------------------------- /addon/doc/tr/readme.md: -------------------------------------------------------------------------------- 1 | # Bip klavye NVDA Eklentisi # 2 | Bu eklenti, kullanıcının NVDA'yı bazı klavye olaylarıyla bip sesi çıkaracak şekilde yapılandırmasına olanak tanır. 3 | 4 | Telif Hakkı (C) 2019 - 2023 David CM 5 | 6 | Bu paket, GNU Genel Kamu Lisansı, sürüm 2 veya sonraki koşulları altında dağıtılmaktadır. 7 | 8 | ## Özellikler: 9 | 10 | Bu eklenti, NVDA klavye davranışını yapılandırmak için kullanabileceğiniz aşağıdaki özellikleri sağlar: 11 | 12 | * Büyük harf kilidi açıkken büyük harfler için bip sesi: Bu özellik etkinleştirilirse, büyük harf yazdığınızda ve büyük harf kilidi açıkken NVDA bip sesi çıkarır. Daha fazla büyük harf hatası yapmayın! 13 | * Shift'e basıldığında yazılan karakterler için bip sesi: bu özellikle, shift tuşuna basılıyken bir karakter yazarsanız NVDA bip sesi çıkarır. 14 | * Geçiş tuşları değişiklikleri için bip sesi: Bu özellikle, NVDA bir geçiş tuşu açıldığında daha yüksek, kapandığında daha düşük bip sesi çıkarır. Lütfen Windows'un Erişim Kolaylığı Merkezi'nde yerleşik bir bip sesi açma/kapatma işlevine sahip olduğunu unutmayın. Bu yerel özellik, dizüstü bilgisayar klavye düzeni ayarını kullanmıyorsanız iyi çalışır. 15 | * Geçiş tuşları değişikliklerini duyur: "Geçiş tuşları değişiklikleri için bip sesi" açıkken. Geçiş anahtarı durumunu duyurmak için NVDA'yı etkinleştirebilir veya devre dışı bırakabilirsiniz. 16 | * Belirtilen karakterler için bip sesi: NVDA, gelişmiş ayarlarda belirlediğiniz tüm karakterler için bip sesi çıkarır. 17 | * Şifre alanlarında bip sesini devre dışı bırak: bu özellik, güvenlik risklerini önlemek için varsayılan olarak etkindir. Parola alanlarında bip sesleri duymak istiyorsanız devre dışı bırakın. 18 | 19 | ## Gereksinimler: 20 | 21 | NVDA 2018.2 veya sonrasına ihtiyacınız var. 22 | 23 | ## Kurulum: 24 | 25 | Sadece bir NVDA eklentisi olarak kurun. 26 | 27 | ## kullanım: 28 | 29 | Özellikleri etkinleştirmek veya devre dışı bırakmak için NVDA ayarlarına gidin ve bip klavye kategorisini seçin. Bu kategoride, desteklenen tüm özellikleri bu eklenti ile yapılandırabilirsiniz. 30 | "Büyük harf kilidi açıkken büyük harfler için bip sesi" varsayılan olarak etkindir. 31 | Daha fazla ayara ihtiyacınız varsa, aşağıdaki seçenekleri içeren gelişmiş ayarlar iletişim kutusunu açın: 32 | 33 | * Shift'e basıldığında yok sayılan karakterler: Shift'e basıldığında bip sesi çıkarmak için buradaki tüm karakterler yok sayılır. Kaçış Dizilerine izin verilir, örn. Sekme için "\t", satırbaşı için "\r". 34 | * Aşağıdaki karakterler için her zaman bip sesi çıkar: NVDA'nın bip sesi çıkarmasını istediğiniz tüm karakterleri burada ayarlayın. Kaçış Dizilerine izin verilir, örn. Sekme için "\t", satırbaşı için "\r". 35 | * Yapılandırılacak tonu seç: tüm tonlar için parametreleri yapılandırabilirsiniz. Burada bir tane seçin ve sonraki metin kutularında parametreleri ayarlayın. Seçimi değiştirdiğinizde, NVDA iletişim kutusunda ayarlanan geçerli parametrelerle birlikte seçili olan geçerli ton için bip sesi çıkaracaktır. 36 | * Ton perdesi: geçerli seçili ton için ton perdesi. 37 | * Ton uzunluğu: geçerli seçili ton için ton uzunluğu. 38 | * Ton ses seviyesi: mevcut seçili ton için ton ses seviyesi. 39 | * Tonu test et: bu düğme, geçerli ayarlanmış parametrelerle bir test yürütmenizi sağlar. 40 | * Ayarları kaydetmek için Tamam düğmesine, iptal için Escape veya iptal tuşuna basın. 41 | 42 | ## katkılar, raporlar ve bağışlar: 43 | 44 | Projemi beğendiyseniz veya bu yazılım günlük hayatınızda işinize yararsa ve bir şekilde katkıda bulunmak isterseniz aşağıdaki yöntemlerle bağışta bulunabilirsiniz: 45 | 46 | * [PayPal.](https://paypal.me/davicm) 47 | * [Ko-fi.](https://ko-fi.com/davidacm) 48 | * [kripto para birimleri ve diğer yöntemler.](https://davidacm.github.io/donations/) 49 | 50 | Hataları düzeltmek, sorunları bildirmek veya yeni özellikler istiyorsanız benimle adresinden iletişime geçebilirsiniz. 51 | 52 | Veya bu projenin github deposunda: 53 | [GitHub'da bip klavye](https://github.com/davidacm/beepKeyboard) 54 | 55 | Bu eklentinin en son sürümünü bu depodan edinebilirsiniz. 56 | -------------------------------------------------------------------------------- /addon/doc/es/readme.md: -------------------------------------------------------------------------------- 1 | # Complemento Beep Keyboard para NVDA # 2 | 3 | Este complemento permite al usuario configurar NVDA para que emita pitidos con algunos eventos del teclado. 4 | 5 | Copyright (C) 2019 - 2023 David CM 6 | 7 | Este paquete se distribuye bajo los términos de la Licencia Pública General GNU, versión 2 o posterior. 8 | 9 | ## Características 10 | 11 | Este complemento proporciona las siguientes funciones que puedes usar para adaptar el comportamiento del teclado de NVDA: 12 | 13 | * Beep para mayúsculas cuando el bloqueo de mayúsculas está activado: si esta característica está habilitada, NVDA emitirá un pitido cuando escribas caracteres y el bloqueo de mayúsculas se encuentre activado. Es útil por ejemplo, si se activó el bloqueo mayúsculas sin querer. ¡No cometas más errores con mayúsculas! 14 | * Pitido para caracteres escritos cuando se presiona shift: con esta función, NVDA emitirá un pitido si escribe un carácter con la tecla shift presionada. 15 | * Pitido para cambios de teclas de alternancia: con esta función, NVDA emitirá un pitido más alto si se activa una tecla de alternancia, y un tono más bajo si se apaga. Tenga en cuenta que Windows tiene una función de cambio de pitido keis incorporada en el Centro de facilidad de acceso. Esta característica nativa funciona bien si no utiliza la configuración de distribución del teclado de la computadora portátil. 16 | * Anunciar cambios de teclas de alternancia: justo cuando está activado el "Bip para cambios de teclas de alternancia". Puedes habilitar o deshabilitar NVDA para anunciar el estado de la tecla de alternancia. 17 | * Pitido para caracteres específicos: NVDA emitirá un pitido para todos los caracteres que configures en la configuración avanzada. 18 | * Deshabilitar el pitido en los campos de contraseña: esta función está habilitada de forma predeterminada para evitar riesgos de seguridad. Desactívelo si desea escuchar pitidos en los campos de contraseña. 19 | 20 | ## Requisitos 21 | Necesitas NVDA 2018.2 o posterior. 22 | 23 | ## Instalación 24 | Solo instálalo como un complemento de NVDA. 25 | 26 | ## Uso 27 | Para habilitar o deshabilitar funciones, ve a la configuración de NVDA y selecciona la categoría de teclado de pitidos. En esa categoría puede configurar todas las funciones compatibles con este complemento. 28 | 29 | "Beep para mayúsculas cuando el bloqueo de mayúsculas está activado" está habilitado de forma predeterminada. 30 | Si necesita más configuraciones, abra el cuadro de diálogo de configuración avanzada que contiene las siguientes opciones: 31 | 32 | * Caracteres ignorados con shift presionado: todos los caracteres aquí serán ignorados y emitirán un pitido cuando se presione shift. Las secuencias de escape están permitidas, p. "\t" para tabulador, "\r" para retorno de carro. 33 | * Pitar siempre para los siguientes caracteres: configura aquí todos los caracteres para los que quieras pitidos de NVDA. Las secuencias de escape están permitidas, p. "\t" para tabulador, "\r" para retorno de carro. 34 | * Seleccionar tono a configurar: puede configurar parámetros para todos los tonos. Seleccione uno aquí y establezca los parámetros en los siguientes cuadros de texto. Cuando cambie la selección, NVDA emitirá un pitido para el tono seleccionado actual con los parámetros actuales establecidos en el diálogo. 35 | * Tono de tono: tono de tono para el tono seleccionado actual. 36 | * Duración del tono: duración del tono para el tono seleccionado actualmente. 37 | * Volumen de tono: volumen de tono para el tono seleccionado actualmente. 38 | * Tono de prueba: este botón le permite reproducir una prueba con los parámetros establecidos actualmente. 39 | * Presione el botón OK para guardar la configuración o cancelar para descartar. 40 | 41 | ## contribuciones, informes y donaciones 42 | 43 | Si te gusta mi proyecto o este software te es útil en tu vida diaria y te gustaría contribuir de alguna manera, puedes donar a través de los siguientes métodos: 44 | 45 | * [PayPal.](https://paypal.yo/davicm) 46 | * [Ko-fi.](https://ko-fi.com/davidacm) 47 | * [criptomonedas y otros métodos.](https://davidacm.github.io/donations/) 48 | 49 | Si desea corregir errores, informar problemas o nuevas funciones, puede contactarme en: . 50 | 51 | O en el repositorio github de este proyecto: 52 | [Beep teclado en GitHub](https://github.com/davidacm/beepKeyboard) 53 | 54 | Puede obtener la última versión de este complemento en ese repositorio. 55 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Beep keyboard NVDA Add-on # 2 | This add-on allows the user to configure NVDA to beeps with some keyboard events. 3 | 4 | Copyright (C) 2019 - 2023 David CM 5 | 6 | This package is distributed under the terms of the GNU General Public License, version 2 or later. 7 | 8 | ## Features 9 | This add-on provides the following features you can use to adapt NVDA keyboard behavior: 10 | 11 | * Beep for uppercases when caps lock is on: if this feature is enabled, NVDA will beep when you typing an uppercase and caps lock is on. Don't make any more uppercase mistakes! 12 | * Beep for typed characters when shift is pressed: with this feature NVDA will beep if you type a character with shift key pressed. 13 | * Beep for toggle keys changes: with this feature, NVDA will beep higher if a toggle key goes on, and lower tone if it goes off. Please note that Windows has a toggle keis beep function built-in on Ease of Access Center. This native feature works well if you don't use laptop keyboard layout setting. 14 | * Announce toggle keys changes: just when "Beep for toggle keys changes" is on. You can enable or disable NVDA to announce toggle key status. 15 | * Beep for specified characters: NVDA will beep for all characters that you set in advanced settings. 16 | * Disable beeping on password fields: this feature is enabled by default to aboid security risks. Disable it if you want to hear beeps on password fields. 17 | 18 | ## Requirements 19 | You need NVDA 2018.2 or later. 20 | 21 | ## Installation 22 | Just install it as a NVDA add-on. 23 | 24 | ## Usage 25 | To enable or disable features, go to NVDA settings and select beep keyboard category. In that category you can configure all supported features by this add-on. 26 | "Beep for uppercases when caps lock is on" is enabled by default. 27 | If you need more settings, open the advanced settings dialog that contains the following options: 28 | 29 | * Ignored characters with shift pressed: all characters here will be ignored to beeping when shift is pressed. Escape Sequences are allowed, e.g. "\t" for tab, "\r" for carriage return. 30 | * Beep always for the following characters: set here all characters that you want NVDA beeps for. Escape Sequences are allowed, e.g. "\t" for tab, "\r" for carriage return. 31 | * Select tone to configure: you can configure parameters for all tones. Select one here, and set the parameters in the next text boxes. When change selection, NVDA will beep for the current selected tone with the current parameters set in the dialog. 32 | * Tone pitch: tone pitch for the current selected tone. 33 | * Tone length: tone length for the current selected tone. 34 | * Tone volume: tone volume for the current selected tone. 35 | * Test tone: this button lets you to play a test with the current set parameters. 36 | * Press OK button to save settings or cancel to discard. 37 | 38 | ## Download. 39 | The latest release is available to [download in this link](https://davidacm.github.io/getlatest/gh/davidacm/beepKeyboard/?index=1) 40 | 41 | ## Contributing with the project. 42 | ### Donations. 43 | If you like my project or this software is useful for you in your daily life and you would like to contribute in some way, you can donate via the following methods. 44 | 45 | * [PayPal.](https://paypal.me/davicm) 46 | * [Ko-fi.](https://ko-fi.com/davidacm) 47 | * [cryptocurrencies and other methods.](https://davidacm.github.io/donations/) 48 | 49 | 50 | ### fixing bugs and new features. 51 | If you want to fix a bug or add new feature, You will need to fork this repository. 52 | 53 | #### Forking the repository. 54 | If this is your first contribution, you will first need to "fork" the BeepKeyboard repository on GitHub: 55 | 56 | 1. Fork this repo in your github account. 57 | 2. Clone your forked repo locally: "git clone yourRepoUrl". 58 | 3. Add this repo in your forked repo from the command line: 59 | "git remote add davidacm https://github.com/davidacm/beepKeyboard.git". 60 | 4. fetch my branches: 61 | "git fetch davidacm". 62 | 5. Switch to the local master branch: "git checkout master". 63 | 6. Set the local master to use the davidacm master as its upstream: 64 | "git branch -u davidacm/master". 65 | 66 | #### Steps before coding. 67 | You must use a separate "topic" branch for each issue or feature. All code should usually be based on the latest commit in the official master branch at the time you start the work. 68 | So, before begin to work, do the following: 69 | 70 | 1. Remember the steps of "Forking the repository" section. 71 | 2. Checkout to master branch: "git checkout master". 72 | 3. Update the local master: "git pull". 73 | 4. Create a new branch based on the updated master branch: "git checkout -b YourNewBranch". 74 | 5. write your code. 75 | 6. Add your work to be commited (clean unwanted files first): git "add ." 76 | 7. create a commit: "git commit" and write the commit message. 77 | 8. push your branch in your repository: "git push". if the branch doesn't exist, git will tell you how to deal with this. 78 | 9. Request a pull request on my repository. 79 | -------------------------------------------------------------------------------- /addon/globalPlugins/beepKeyboard/beepKeyboardUtils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | #globalPlugins/beepKeyboard/_beepKeyboardUtils.py 3 | # Copyright (C) 2022 - 2024 David CM 4 | 5 | import os, gui, wx, config, addonHandler 6 | 7 | addonHandler.initTranslation() 8 | 9 | 10 | def getConfigValue(path, optName): 11 | """ this function helps to accessing config values. 12 | params 13 | @path: the path to the option. 14 | @optName: the option name 15 | """ 16 | ops = config.conf[path[0]] 17 | for k in path[1:]: 18 | ops = ops[k] 19 | return ops[optName] 20 | 21 | 22 | def setConfigValue(path, optName, value): 23 | """ this function helps to accessing and set config values. 24 | params 25 | @path: the path to the option. 26 | @optName: the option name 27 | @value: the value to set. 28 | """ 29 | ops = config.conf[path[0]] 30 | for k in path[1:]: 31 | ops = ops[k] 32 | ops[optName] = value 33 | 34 | 35 | def registerConfig(clsSpec, path=None): 36 | AF = clsSpec(path) 37 | config.conf.spec[AF.__path__[0]] = AF.createSpec() 38 | AF.returnValue = True 39 | return AF 40 | 41 | 42 | class OptConfig: 43 | """ just a helper descriptor to create the main class to accesing config values. 44 | the option name will be taken from the declared variable. 45 | """ 46 | def __init__(self, desc): 47 | """ 48 | params: 49 | @desc: the spec description. 50 | """ 51 | self.desc = desc 52 | 53 | def __set_name__(self, owner, name): 54 | self.name = name 55 | owner.__confOpts__.append(name) 56 | 57 | def __get__(self, obj, type=None): 58 | if obj.returnValue: 59 | return getConfigValue(obj.__path__, self.name) 60 | return self.name, self.desc 61 | 62 | def __set__(self, obj, value): 63 | setConfigValue(obj.__path__, self.name, value) 64 | 65 | 66 | class BaseConfig: 67 | """ this class will help to get and set config values. 68 | the idea behind this is to generalize the config path and config names. 69 | sometimes, a mistake in the dict to access the values can produce an undetectable bug. 70 | if returnValue attribute is set to False, this will return the option name instead of the value. 71 | by default this value is False, to help to create the configuration spec first. 72 | Set it to true after creating this spec. 73 | """ 74 | __path__ = None 75 | def __init__(self, path=None): 76 | self.returnValue = False 77 | if not path: 78 | path = self.__class__.__path__ 79 | if not path: 80 | raise Exception("Path for the config is not defined") 81 | if isinstance(path, list): 82 | self.__path__ = path 83 | else: 84 | self.__path__ = [path] 85 | 86 | def createSpec(self): 87 | """ this method creates a config spec with the provided attributes in the class 88 | """ 89 | s = {} 90 | for k in self.__class__.__confOpts__: 91 | k = self.__getattribute__(k) 92 | s[k[0]] = k[1] 93 | return s 94 | # an array of the available options. 95 | __confOpts__ = [] 96 | 97 | 98 | def configSpec(pathOrCls): 99 | """ a decorator to help with the generation of the class config spec. 100 | adds a get and set descriptor for eatch attribute in the config class. 101 | except the attributes starting with "__". 102 | params: 103 | @pathOrCls: the config path, 104 | or if the decorator is called without params, then the decorated class. 105 | path as an argument in the decorator has a higher priority than the __path__ declared in the class. 106 | """ 107 | def configDecorator(cls): 108 | class ConfigSpec(BaseConfig): 109 | pass 110 | 111 | for k in cls.__dict__: 112 | if k == '__path__': 113 | ConfigSpec.__path__ = cls.__path__ 114 | if k.startswith("__"): continue 115 | v = getattr(cls, k) 116 | d = OptConfig(v) 117 | d.__set_name__(ConfigSpec, k) 118 | setattr(ConfigSpec, k, d) 119 | if isinstance(pathOrCls, str): 120 | ConfigSpec.__path__ = pathOrCls 121 | return ConfigSpec 122 | if isinstance(pathOrCls, str): 123 | return configDecorator 124 | else: 125 | return configDecorator(pathOrCls) 126 | 127 | 128 | class DonationDialog(gui.nvdaControls.MessageDialog): 129 | def __init__(self, parent, title, message, donateOptions): 130 | self.donateOptions = donateOptions 131 | super().__init__(parent, title, message, dialogType=gui.nvdaControls.MessageDialog.DIALOG_TYPE_WARNING) 132 | 133 | def _addButtons(self, buttonHelper): 134 | for k in self.donateOptions: 135 | btn = buttonHelper.addButton(self, label=k['label'], name=k['url']) 136 | btn.Bind(wx.EVT_BUTTON, self.onDonate) 137 | cancelBtn = buttonHelper.addButton(self, id=wx.ID_CANCEL, label=_("&Not now")) 138 | cancelBtn.Bind(wx.EVT_BUTTON, lambda evt: self.EndModal(wx.CANCEL)) 139 | 140 | def onDonate(self, evt): 141 | donateBtn = evt.GetEventObject() 142 | donateUrl = donateBtn.Name 143 | os.startfile(donateUrl) 144 | self.EndModal(wx.OK) 145 | 146 | 147 | def showDonationsDialog(parentWindow, addonName, donateOptions): 148 | title = _("Request for contributions to %s") % addonName 149 | message = _("""Creating add-ons demands substantial time and effort. With limited job prospects in my country, your donations could significantly aid in dedicating more time to developing free plugins for the community. 150 | Your contribution would support the development of this and other free projects. 151 | Would you like to contribute to this cause? Select from our available payment methods below. You will be redirected to the corresponding website to complete your donation. 152 | Thank you for your support and generosity.""") 153 | return DonationDialog(parentWindow, title, message, donateOptions).ShowModal() 154 | -------------------------------------------------------------------------------- /beepKeyboard.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the 'beepKeyboard' package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: 'beepKeyboard' '1.8'\n" 10 | "Report-Msgid-Bugs-To: 'nvda-translations@groups.io'\n" 11 | "POT-Creation-Date: 2024-01-04 14:35-0600\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=CHARSET\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: addon\globalPlugins\beepKeyboard\__init__.py:59 21 | msgid "Using Paypal" 22 | msgstr "" 23 | 24 | #: addon\globalPlugins\beepKeyboard\__init__.py:63 25 | msgid "using Co-fi" 26 | msgstr "" 27 | 28 | #: addon\globalPlugins\beepKeyboard\__init__.py:67 29 | msgid "See more methods on my github Page" 30 | msgstr "" 31 | 32 | #. Translators: This is the label for the beepKeyboard settings category in NVDA Settings screen. 33 | #. Add-on summary, usually the user visible name of the addon. 34 | #. Translators: Summary for this add-on to be shown on installation and add-on information. 35 | #: addon\globalPlugins\beepKeyboard\__init__.py:75 buildVars.py:17 36 | msgid "Beep keyboard" 37 | msgstr "" 38 | 39 | #. Translators: label for a checkbox option in the settings panel. 40 | #: addon\globalPlugins\beepKeyboard\__init__.py:80 41 | msgid "Beep for uppercases when &caps lock is on" 42 | msgstr "" 43 | 44 | #. Translators: label for a checkbox option in the settings panel. 45 | #: addon\globalPlugins\beepKeyboard\__init__.py:83 46 | msgid "Beep for typed characters when &shift is pressed" 47 | msgstr "" 48 | 49 | #. Translators: label for a checkbox option in the settings panel. 50 | #: addon\globalPlugins\beepKeyboard\__init__.py:86 51 | msgid "Beep for &toggle keys changes" 52 | msgstr "" 53 | 54 | #. Translators: label for a checkbox option in the settings panel. 55 | #: addon\globalPlugins\beepKeyboard\__init__.py:89 56 | msgid "" 57 | "&Announce toggle keys changes (if Beep for toggle keys changes is disabled " 58 | "NVDA will have the original behavior)" 59 | msgstr "" 60 | 61 | #. Translators: label for a checkbox option in the settings panel. 62 | #: addon\globalPlugins\beepKeyboard\__init__.py:92 63 | msgid "&disable beeping on password fields" 64 | msgstr "" 65 | 66 | #. Translators: label for a button to open advanced settings dialog in the settings panel. 67 | #: addon\globalPlugins\beepKeyboard\__init__.py:96 68 | msgid "&Open advanced options" 69 | msgstr "" 70 | 71 | #: addon\globalPlugins\beepKeyboard\__init__.py:98 72 | msgid "&Support beep keyboard add-on" 73 | msgstr "" 74 | 75 | #. Translators: This is the label for the beep keyboard advanced settings dialog 76 | #: addon\globalPlugins\beepKeyboard\__init__.py:115 77 | msgid "Advanced settings - Keyboard beep" 78 | msgstr "" 79 | 80 | #. Translators: label for an edit text control option in the advanced settings dialog. 81 | #: addon\globalPlugins\beepKeyboard\__init__.py:120 82 | msgid "&Ignored characters with shift pressed" 83 | msgstr "" 84 | 85 | #. Translators: label for an edit text control option in the advanced settings dialog. 86 | #: addon\globalPlugins\beepKeyboard\__init__.py:123 87 | msgid "Beep &always for the following characters" 88 | msgstr "" 89 | 90 | #. Translators: label for a combo box control in the advanced settings dialog. 91 | #: addon\globalPlugins\beepKeyboard\__init__.py:127 92 | msgid "&Select tone to configure" 93 | msgstr "" 94 | 95 | #. Translators: label for an option of a combo box control. 96 | #: addon\globalPlugins\beepKeyboard\__init__.py:129 97 | msgid "Typed characters with shift pressed" 98 | msgstr "" 99 | 100 | #. Translators: label for an option of a combo box control. 101 | #: addon\globalPlugins\beepKeyboard\__init__.py:131 102 | msgid "Custom characters" 103 | msgstr "" 104 | 105 | #. Translators: label for an option of a combo box control. 106 | #: addon\globalPlugins\beepKeyboard\__init__.py:133 107 | msgid "Typed characters when caps lock is on" 108 | msgstr "" 109 | 110 | #. Translators: label for an option of a combo box control. 111 | #: addon\globalPlugins\beepKeyboard\__init__.py:135 112 | msgid "Toggle key goes off" 113 | msgstr "" 114 | 115 | #. Translators: label for an option of a combo box control. 116 | #: addon\globalPlugins\beepKeyboard\__init__.py:137 117 | msgid "Toggle key goes on" 118 | msgstr "" 119 | 120 | #. Translators: label for an edit text control option in the advanced settings dialog. 121 | #: addon\globalPlugins\beepKeyboard\__init__.py:142 122 | msgid "Tone &pitch" 123 | msgstr "" 124 | 125 | #. Translators: label for an edit text control option in the advanced settings dialog. 126 | #: addon\globalPlugins\beepKeyboard\__init__.py:145 127 | msgid "Tone &length" 128 | msgstr "" 129 | 130 | #. Translators: label for an edit text control option in the advanced settings dialog. 131 | #: addon\globalPlugins\beepKeyboard\__init__.py:148 132 | msgid "Tone &volume" 133 | msgstr "" 134 | 135 | #. Translators: label for a button to play demo tone in advanced settings dialog. 136 | #: addon\globalPlugins\beepKeyboard\__init__.py:151 137 | msgid "&Test tone" 138 | msgstr "" 139 | 140 | #. Translators: an error message sent to ve spoken by NVDA. 141 | #: addon\globalPlugins\beepKeyboard\__init__.py:166 142 | msgid "You entered a wrong value. Please correct it or discard changes." 143 | msgstr "" 144 | 145 | #: addon\globalPlugins\beepKeyboard\_beepKeyboardUtils.py:135 146 | msgid "&Not now" 147 | msgstr "" 148 | 149 | #: addon\globalPlugins\beepKeyboard\_beepKeyboardUtils.py:146 150 | #, python-format 151 | msgid "Request for contributions to %s" 152 | msgstr "" 153 | 154 | #: addon\globalPlugins\beepKeyboard\_beepKeyboardUtils.py:147 155 | msgid "" 156 | "Creating add-ons demands substantial time and effort. With limited job " 157 | "prospects in my country, your donations could significantly aid in " 158 | "dedicating more time to developing free plugins for the community.\n" 159 | "Your contribution would support the development of this and other free " 160 | "projects.\n" 161 | "Would you like to contribute to this cause? Select from our available " 162 | "payment methods below. You will be redirected to the corresponding website " 163 | "to complete your donation.\n" 164 | "Thank you for your support and generosity." 165 | msgstr "" 166 | 167 | #. Add-on description 168 | #. Translators: Long description to be shown for this add-on on add-on information from add-ons manager 169 | #: buildVars.py:20 170 | msgid "This add-on beeps with some keyboard events." 171 | msgstr "" 172 | -------------------------------------------------------------------------------- /addon/locale/es/LC_MESSAGES/nvda.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the 'beepKeyboard' package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: 'beepKeyboard' '1.8'\n" 10 | "Report-Msgid-Bugs-To: 'nvda-translations@groups.io'\n" 11 | "POT-Creation-Date: 2024-01-04 14:35-0600\n" 12 | "PO-Revision-Date: 2024-01-04 14:45-0600\n" 13 | "Last-Translator: \n" 14 | "Language-Team: \n" 15 | "Language: es\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "X-Generator: Poedit 3.4.2\n" 20 | 21 | #: addon\globalPlugins\beepKeyboard\__init__.py:59 22 | msgid "Using Paypal" 23 | msgstr "Usando Paypal" 24 | 25 | #: addon\globalPlugins\beepKeyboard\__init__.py:63 26 | msgid "using Co-fi" 27 | msgstr "usando co-fi" 28 | 29 | #: addon\globalPlugins\beepKeyboard\__init__.py:67 30 | msgid "See more methods on my github Page" 31 | msgstr "Ver más métodos en mi página de github" 32 | 33 | #. Translators: This is the label for the beepKeyboard settings category in NVDA Settings screen. 34 | #. Add-on summary, usually the user visible name of the addon. 35 | #. Translators: Summary for this add-on to be shown on installation and add-on information. 36 | #: addon\globalPlugins\beepKeyboard\__init__.py:75 buildVars.py:17 37 | msgid "Beep keyboard" 38 | msgstr "" 39 | 40 | #. Translators: label for a checkbox option in the settings panel. 41 | #: addon\globalPlugins\beepKeyboard\__init__.py:80 42 | msgid "Beep for uppercases when &caps lock is on" 43 | msgstr "" 44 | "Pitar para las mayúsculas cuando el bloqueo de mayúsculas está activado" 45 | 46 | #. Translators: label for a checkbox option in the settings panel. 47 | #: addon\globalPlugins\beepKeyboard\__init__.py:83 48 | msgid "Beep for typed characters when &shift is pressed" 49 | msgstr "Pitar con los caracteres escritos cuando &shift está presionado" 50 | 51 | #. Translators: label for a checkbox option in the settings panel. 52 | #: addon\globalPlugins\beepKeyboard\__init__.py:86 53 | msgid "Beep for &toggle keys changes" 54 | msgstr "" 55 | "pitar al &alternar el estado de teclas como mayúsculas o bloqueo numérico" 56 | 57 | #. Translators: label for a checkbox option in the settings panel. 58 | #: addon\globalPlugins\beepKeyboard\__init__.py:89 59 | msgid "" 60 | "&Announce toggle keys changes (if Beep for toggle keys changes is disabled " 61 | "NVDA will have the original behavior)" 62 | msgstr "" 63 | "Verbalizar &cambios al activar o desactivar teclas de estado (si el pitido " 64 | "para cambios de teclas de estado está deshabilitado, NVDA tendrá el " 65 | "comportamiento original)" 66 | 67 | #. Translators: label for a checkbox option in the settings panel. 68 | #: addon\globalPlugins\beepKeyboard\__init__.py:92 69 | msgid "&disable beeping on password fields" 70 | msgstr "&deshabilitar pitidos en campos de contraseña" 71 | 72 | #. Translators: label for a button to open advanced settings dialog in the settings panel. 73 | #: addon\globalPlugins\beepKeyboard\__init__.py:96 74 | msgid "&Open advanced options" 75 | msgstr "&Abrir opciones avanzadas" 76 | 77 | #: addon\globalPlugins\beepKeyboard\__init__.py:98 78 | msgid "&Support beep keyboard add-on" 79 | msgstr "&Apoyar el complemento Beep Keyboard" 80 | 81 | #. Translators: This is the label for the beep keyboard advanced settings dialog 82 | #: addon\globalPlugins\beepKeyboard\__init__.py:115 83 | msgid "Advanced settings - Keyboard beep" 84 | msgstr "Configuración avanzada - Beep Keyboard" 85 | 86 | #. Translators: label for an edit text control option in the advanced settings dialog. 87 | #: addon\globalPlugins\beepKeyboard\__init__.py:120 88 | msgid "&Ignored characters with shift pressed" 89 | msgstr "&Caracteres a ignorar con ship presionado" 90 | 91 | #. Translators: label for an edit text control option in the advanced settings dialog. 92 | #: addon\globalPlugins\beepKeyboard\__init__.py:123 93 | msgid "Beep &always for the following characters" 94 | msgstr "pitar &siempre para los siguientes caracteres" 95 | 96 | #. Translators: label for a combo box control in the advanced settings dialog. 97 | #: addon\globalPlugins\beepKeyboard\__init__.py:127 98 | msgid "&Select tone to configure" 99 | msgstr "&Seleccione el tono para configurar" 100 | 101 | #. Translators: label for an option of a combo box control. 102 | #: addon\globalPlugins\beepKeyboard\__init__.py:129 103 | msgid "Typed characters with shift pressed" 104 | msgstr "Caracteres escritos con ship presionado" 105 | 106 | #. Translators: label for an option of a combo box control. 107 | #: addon\globalPlugins\beepKeyboard\__init__.py:131 108 | msgid "Custom characters" 109 | msgstr "Caracteres personalizados" 110 | 111 | #. Translators: label for an option of a combo box control. 112 | #: addon\globalPlugins\beepKeyboard\__init__.py:133 113 | msgid "Typed characters when caps lock is on" 114 | msgstr "Caracteres escritos cuando el bloqueo de mayúsculas está activado" 115 | 116 | #. Translators: label for an option of a combo box control. 117 | #: addon\globalPlugins\beepKeyboard\__init__.py:135 118 | msgid "Toggle key goes off" 119 | msgstr "La tecla de estado se desactiva" 120 | 121 | #. Translators: label for an option of a combo box control. 122 | #: addon\globalPlugins\beepKeyboard\__init__.py:137 123 | msgid "Toggle key goes on" 124 | msgstr "La tecla de estado se activa" 125 | 126 | #. Translators: label for an edit text control option in the advanced settings dialog. 127 | #: addon\globalPlugins\beepKeyboard\__init__.py:142 128 | msgid "Tone &pitch" 129 | msgstr "Frecuencia de tono" 130 | 131 | #. Translators: label for an edit text control option in the advanced settings dialog. 132 | #: addon\globalPlugins\beepKeyboard\__init__.py:145 133 | msgid "Tone &length" 134 | msgstr "Duración de tono" 135 | 136 | #. Translators: label for an edit text control option in the advanced settings dialog. 137 | #: addon\globalPlugins\beepKeyboard\__init__.py:148 138 | msgid "Tone &volume" 139 | msgstr "Volumen de tono" 140 | 141 | #. Translators: label for a button to play demo tone in advanced settings dialog. 142 | #: addon\globalPlugins\beepKeyboard\__init__.py:151 143 | msgid "&Test tone" 144 | msgstr "Probar tono" 145 | 146 | #. Translators: an error message sent to ve spoken by NVDA. 147 | #: addon\globalPlugins\beepKeyboard\__init__.py:166 148 | msgid "You entered a wrong value. Please correct it or discard changes." 149 | msgstr "Ingresaste un valor incorrecto. Corríjelo o descarta los cambios." 150 | 151 | #: addon\globalPlugins\beepKeyboard\_beepKeyboardUtils.py:135 152 | msgid "&Not now" 153 | msgstr "&Ahora no" 154 | 155 | #: addon\globalPlugins\beepKeyboard\_beepKeyboardUtils.py:146 156 | #, python-format 157 | msgid "Request for contributions to %s" 158 | msgstr "Solicitud de contribuciones para %s" 159 | 160 | #: addon\globalPlugins\beepKeyboard\_beepKeyboardUtils.py:147 161 | msgid "" 162 | "Creating add-ons demands substantial time and effort. With limited job " 163 | "prospects in my country, your donations could significantly aid in " 164 | "dedicating more time to developing free plugins for the community.\n" 165 | "Your contribution would support the development of this and other free " 166 | "projects.\n" 167 | "Would you like to contribute to this cause? Select from our available " 168 | "payment methods below. You will be redirected to the corresponding website " 169 | "to complete your donation.\n" 170 | "Thank you for your support and generosity." 171 | msgstr "" 172 | "La creación de complementos exige mucho tiempo y esfuerzo. Debido a las " 173 | "bajas oportunidades laborales en mi país, tus donaciones podrían ayudar " 174 | "significativamente a dedicar más tiempo al desarrollo de complementos " 175 | "gratuitos para la comunidad.\n" 176 | "Tu contribución apoyaría el desarrollo de este y otros proyectos " 177 | "gratuitos.\n" 178 | "¿Te gustaría contribuir a esta causa? Selecciona entre nuestros métodos de " 179 | "pago disponibles a continuación. Serás redirigido al sitio web " 180 | "correspondiente para completar tu donación.\n" 181 | "Gracias por tu apoyo y generosidad." 182 | 183 | #. Add-on description 184 | #. Translators: Long description to be shown for this add-on on add-on information from add-ons manager 185 | #: buildVars.py:20 186 | msgid "This add-on beeps with some keyboard events." 187 | msgstr "Este complemento emite un pitido con algunos eventos del teclado." 188 | -------------------------------------------------------------------------------- /addon/globalPlugins/beepKeyboard/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # Beep keyboard: This add-on beeps with some keyboard events. 3 | # Copyright (C) 2019 - 2022 David CM 4 | # Author: David CM 5 | # Released under GPL 2 6 | #globalPlugins/beepKeyboard.py 7 | 8 | import api, codecs, config, globalPluginHandler, gui, keyboardHandler, tones, ui, winreg, winUser, wx, addonHandler 9 | from .beepKeyboardUtils import configSpec, registerConfig, showDonationsDialog 10 | addonHandler.initTranslation() 11 | 12 | 13 | @configSpec('beepKeyboard') 14 | class AppConfig: 15 | beepUpperWithCapsLock = 'boolean(default=True)' 16 | beepCharacterWithShift = 'boolean(default=False)' 17 | beepToggleKeyChanges = 'boolean(default=False)' 18 | announceToggleStatus = 'boolean(default=True)' 19 | disableBeepingOnPasswordFields = 'boolean(default=True)' 20 | ignoredCharactersForShift = "string(default='\\x1b\\t\\b\\r ')" 21 | beepForCharacters = "string(default='')" 22 | shiftedCharactersTone = 'int_list(default=list(6000,10,25))' 23 | customCharactersTone = 'int_list(default=list(6000,10,25))' 24 | capsLockUpperTone = 'int_list(default=list(3000,40,50))' 25 | toggleOffTone = 'int_list(default=list(500,40,50))' 26 | toggleOnTone = 'int_list(default=list(2000, 40, 50))' 27 | AF = registerConfig(AppConfig) 28 | 29 | 30 | # Constants. 31 | REG_TOGGLE_KEYS = r"Control Panel\Accessibility\ToggleKeys" 32 | REG_KEY = "Flags" 33 | REG_VALUE_ON = 63 34 | 35 | # global variables 36 | ignoreToggleKeys = False 37 | 38 | def beep(l): 39 | """ it receives a list with three arguments to beep: [pitch, length, volume]""" 40 | if not (AF.disableBeepingOnPasswordFields and api.getFocusObject().isProtected): 41 | tones.beep(*l, right=l[-1]) 42 | 43 | #saves the original _reportToggleKey function 44 | origReportToggleKey = keyboardHandler.KeyboardInputGesture._reportToggleKey 45 | 46 | # alternate function to report state key. 47 | def _reportToggleKey(self): 48 | global ignoreToggleKeys 49 | if not ignoreToggleKeys: 50 | if winUser.getKeyState(self.vkCode) & 1: 51 | beep(AF.toggleOnTone) 52 | else: beep(AF.toggleOffTone) 53 | if ignoreToggleKeys or AF.announceToggleStatus or (AF.disableBeepingOnPasswordFields and api.getFocusObject().isProtected): 54 | origReportToggleKey(self) 55 | 56 | 57 | DONATE_METHODS = ( 58 | { 59 | 'label': _('Using Paypal'), 60 | 'url': 'https://paypal.me/davicm' 61 | }, 62 | { 63 | 'label': _('using Co-fi'), 64 | 'url': 'https://ko-fi.com/davidacm' 65 | }, 66 | { 67 | 'label': _('See more methods on my github Page'), 68 | 'url': 'https://davidacm.github.io/donations/' 69 | } 70 | ) 71 | 72 | 73 | class BeepKeyboardSettingsPanel(gui.settingsDialogs.SettingsPanel): 74 | # Translators: This is the label for the beepKeyboard settings category in NVDA Settings screen. 75 | title = _("Beep keyboard") 76 | 77 | def makeSettings(self, settingsSizer): 78 | sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) 79 | # Translators: label for a checkbox option in the settings panel. 80 | self.beepUpperWithCapsLock = sHelper.addItem(wx.CheckBox(self, label=_("Beep for uppercases when &caps lock is on"))) 81 | self.beepUpperWithCapsLock.SetValue(AF.beepUpperWithCapsLock) 82 | # Translators: label for a checkbox option in the settings panel. 83 | self.beepCharacterWithShift = sHelper.addItem(wx.CheckBox(self, label=_("Beep for typed characters when &shift is pressed"))) 84 | self.beepCharacterWithShift.SetValue(AF.beepCharacterWithShift) 85 | # Translators: label for a checkbox option in the settings panel. 86 | self.beepToggleKeyChanges = sHelper.addItem(wx.CheckBox(self, label=_("Beep for &toggle keys changes"))) 87 | self.beepToggleKeyChanges.SetValue(AF.beepToggleKeyChanges) 88 | # Translators: label for a checkbox option in the settings panel. 89 | self.announceToggleStatus = sHelper.addItem(wx.CheckBox(self, label=_("&Announce toggle keys changes (if Beep for toggle keys changes is disabled NVDA will have the original behavior)"))) 90 | self.announceToggleStatus.SetValue(AF.announceToggleStatus) 91 | # Translators: label for a checkbox option in the settings panel. 92 | self.disableBeepingOnPasswordFields = sHelper.addItem(wx.CheckBox(self, label=_("&disable beeping on password fields"))) 93 | self.disableBeepingOnPasswordFields.SetValue(AF.disableBeepingOnPasswordFields) 94 | 95 | # Translators: label for a button to open advanced settings dialog in the settings panel. 96 | advancedButton = sHelper.addItem (wx.Button (self, label = _("&Open advanced options"))) 97 | advancedButton.Bind(wx.EVT_BUTTON, self.onAdvanced) 98 | donateButton = sHelper.addItem(wx.Button(self, label=_("&Support beep keyboard add-on"))) 99 | donateButton.Bind(wx.EVT_BUTTON, lambda e: showDonationsDialog(self, "Beep Keyboard", DONATE_METHODS)) 100 | 101 | def onAdvanced(self, evt): 102 | advanced = AdvancedBeepKeyboardSettingsDialog(self, multiInstanceAllowed=True) 103 | advanced.ShowModal() 104 | 105 | def onSave(self): 106 | AF.beepUpperWithCapsLock = self.beepUpperWithCapsLock.GetValue() 107 | AF.beepCharacterWithShift = self.beepCharacterWithShift.GetValue() 108 | AF.beepToggleKeyChanges = self.beepToggleKeyChanges.GetValue() 109 | AF.announceToggleStatus = self.announceToggleStatus.GetValue() 110 | AF.disableBeepingOnPasswordFields = self.disableBeepingOnPasswordFields.GetValue() 111 | config.post_configProfileSwitch.notify() 112 | 113 | class AdvancedBeepKeyboardSettingsDialog(gui.SettingsDialog): 114 | # Translators: This is the label for the beep keyboard advanced settings dialog 115 | title = _("Advanced settings - Keyboard beep") 116 | 117 | def makeSettings(self, settingsSizer): 118 | sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) 119 | # Translators: label for an edit text control option in the advanced settings dialog. 120 | self.ignoredCharactersForShift = sHelper.addLabeledControl(_("&Ignored characters with shift pressed"), wx.TextCtrl) 121 | self.ignoredCharactersForShift.SetValue(AF.ignoredCharactersForShift) 122 | # Translators: label for an edit text control option in the advanced settings dialog. 123 | self.beepForCharacters = sHelper.addLabeledControl(_("Beep &always for the following characters"), wx.TextCtrl) 124 | self.beepForCharacters.SetValue(AF.beepForCharacters) 125 | self.tonesParameters = [AF.shiftedCharactersTone, AF.customCharactersTone, AF.capsLockUpperTone, AF.toggleOffTone, AF.toggleOnTone] 126 | # Translators: label for a combo box control in the advanced settings dialog. 127 | self.toneOptionsList = sHelper.addLabeledControl(_("&Select tone to configure"), wx.Choice, choices=[ 128 | # Translators: label for an option of a combo box control. 129 | _("Typed characters with shift pressed"), 130 | # Translators: label for an option of a combo box control. 131 | _("Custom characters"), 132 | # Translators: label for an option of a combo box control. 133 | _("Typed characters when caps lock is on"), 134 | # Translators: label for an option of a combo box control. 135 | _("Toggle key goes off"), 136 | # Translators: label for an option of a combo box control. 137 | _("Toggle key goes on")]) 138 | self.toneOptionsList.SetSelection(0) 139 | self.curSelection=0 140 | self.toneOptionsList.Bind(wx.EVT_CHOICE, self.onToneOptionChange) 141 | # Translators: label for an edit text control option in the advanced settings dialog. 142 | self.tonePitch = sHelper.addLabeledControl(_("Tone &pitch"), wx.TextCtrl) 143 | self.tonePitch.SetValue(str(self.tonesParameters[0][0])) 144 | # Translators: label for an edit text control option in the advanced settings dialog. 145 | self.toneLength = sHelper.addLabeledControl(_("Tone &length"), wx.TextCtrl) 146 | self.toneLength.SetValue(str(self.tonesParameters[0][1])) 147 | # Translators: label for an edit text control option in the advanced settings dialog. 148 | self.toneVolume = sHelper.addLabeledControl(_("Tone &volume"), wx.TextCtrl) 149 | self.toneVolume.SetValue(str(self.tonesParameters[0][2])) 150 | # Translators: label for a button to play demo tone in advanced settings dialog. 151 | testButton = sHelper.addItem (wx.Button (self, label = _("&Test tone"))) 152 | testButton.Bind(wx.EVT_BUTTON, self.onTest) 153 | 154 | def postInit(self): 155 | # ensure that focus is on the ignoredCharactersForShift 156 | self.ignoredCharactersForShift.SetFocus() 157 | 158 | def updateCurrentToneValues(self): 159 | try: 160 | l = [int(self.tonePitch.GetValue()), int(self.toneLength.GetValue()), int(self.toneVolume.GetValue())] 161 | if True in [k<0 for k in l]: raise ValueError 162 | self.tonesParameters[self.curSelection] = l 163 | except ValueError: 164 | tones.beep(100,160) 165 | # Translators: an error message sent to ve spoken by NVDA. 166 | ui.message(_("You entered a wrong value. Please correct it or discard changes.")) 167 | raise ValueError 168 | 169 | def onTest(self, evt): 170 | self.updateCurrentToneValues() 171 | beep(self.tonesParameters[self.curSelection]) 172 | 173 | def onToneOptionChange(self, evt): 174 | try: 175 | self.updateCurrentToneValues() 176 | except ValueError: 177 | self.toneOptionsList.SetSelection(self.curSelection) 178 | return 179 | self.curSelection = self.toneOptionsList.GetCurrentSelection() 180 | co = self.tonesParameters[self.curSelection][0:3] 181 | beep(co) 182 | self.tonePitch.SetValue(str(co[0])) 183 | self.toneLength.SetValue(str(co[1])) 184 | self.toneVolume.SetValue(str(co[2])) 185 | 186 | def onOk(self, evt): 187 | self.updateCurrentToneValues() 188 | AF.ignoredCharactersForShift = self.ignoredCharactersForShift.GetValue() 189 | AF.beepForCharacters = self.beepForCharacters.GetValue() 190 | AF.shiftedCharactersTone, AF.customCharactersTone, AF.capsLockUpperTone, AF.toggleOffTone, AF.toggleOnTone = self.tonesParameters 191 | config.post_configProfileSwitch.notify() 192 | super(AdvancedBeepKeyboardSettingsDialog, self).onOk(evt) 193 | 194 | 195 | class GlobalPlugin(globalPluginHandler.GlobalPlugin): 196 | def __init__(self): 197 | super(globalPluginHandler.GlobalPlugin, self).__init__() 198 | self.handleConfigProfileSwitch() 199 | gui.settingsDialogs.NVDASettingsDialog.categoryClasses.append(BeepKeyboardSettingsPanel) 200 | config.post_configProfileSwitch.register(self.handleConfigProfileSwitch) 201 | 202 | def checkEaseAccessToggleKeys(self): 203 | global ignoreToggleKeys 204 | # disables sounds for toggle keys if native system toggle keys is enabled. 205 | try: 206 | r = winreg.OpenKey(winreg.HKEY_CURRENT_USER, REG_TOGGLE_KEYS, 0, winreg.KEY_READ) 207 | v, _ = winreg.QueryValueEx(r, REG_KEY) 208 | if int(v) == REG_VALUE_ON: ignoreToggleKeys = True 209 | else: ignoreToggleKeys = False 210 | except: 211 | ignoreToggleKeys = False 212 | 213 | def event_typedCharacter(self, obj, nextHandler, ch): 214 | nextHandler() 215 | if AF.beepUpperWithCapsLock and winUser.getKeyState(winUser.VK_CAPITAL)&1 and ch.isupper(): 216 | beep(AF.capsLockUpperTone) 217 | elif AF.beepCharacterWithShift and not winUser.getKeyState(winUser.VK_CONTROL) &32768 and winUser.getKeyState(winUser.VK_SHIFT) &32768 and ch not in self.ignoredCharactersForShift and not (config.conf["keyboard"]["beepForLowercaseWithCapslock"] and ch.islower() and winUser.getKeyState(winUser.VK_CAPITAL)&1): 218 | beep(AF.shiftedCharactersTone) 219 | elif ch in self.beepForCharacters: beep(AF.customCharactersTone) 220 | 221 | def setExternalReportToggleStatus(self, flag): 222 | global ignoreToggleKeys 223 | if flag: 224 | self.checkEaseAccessToggleKeys() 225 | if not ignoreToggleKeys: 226 | keyboardHandler.KeyboardInputGesture._reportToggleKey = _reportToggleKey 227 | return 228 | keyboardHandler.KeyboardInputGesture._reportToggleKey = origReportToggleKey 229 | 230 | def handleConfigProfileSwitch(self): 231 | self.setExternalReportToggleStatus(AF.beepToggleKeyChanges) 232 | self.ignoredCharactersForShift = codecs.decode(AF.ignoredCharactersForShift, 'unicode_escape') 233 | self.beepForCharacters = codecs.decode(AF.beepForCharacters, 'unicode_escape') 234 | 235 | def terminate(self): 236 | super(GlobalPlugin, self).terminate() 237 | self.setExternalReportToggleStatus(False) 238 | gui.settingsDialogs.NVDASettingsDialog.categoryClasses.remove(BeepKeyboardSettingsPanel) 239 | config.post_configProfileSwitch.unregister(self.handleConfigProfileSwitch) 240 | -------------------------------------------------------------------------------- /sconstruct: -------------------------------------------------------------------------------- 1 | # NVDA add-on template SCONSTRUCT file 2 | # Copyright (C) 2012-2023 Rui Batista, Noelia Martinez, Joseph Lee 3 | # This file is covered by the GNU General Public License. 4 | # See the file COPYING.txt for more details. 5 | 6 | import codecs 7 | import gettext 8 | import os 9 | import os.path 10 | import zipfile 11 | import sys 12 | 13 | # While names imported below are available by default in every SConscript 14 | # Linters aren't aware about them. 15 | # To avoid Flake8 F821 warnings about them they are imported explicitly. 16 | # When using other Scons functions please add them to the line below. 17 | from SCons.Script import BoolVariable, Builder, Copy, Environment, Variables 18 | 19 | sys.dont_write_bytecode = True 20 | 21 | # Bytecode should not be written for build vars module to keep the repository root folder clean. 22 | import buildVars # NOQA: E402 23 | 24 | 25 | def md2html(source, dest): 26 | import markdown 27 | # Use extensions if defined. 28 | mdExtensions = buildVars.markdownExtensions 29 | lang = os.path.basename(os.path.dirname(source)).replace('_', '-') 30 | localeLang = os.path.basename(os.path.dirname(source)) 31 | try: 32 | _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[localeLang]).gettext 33 | summary = _(buildVars.addon_info["addon_summary"]) 34 | except Exception: 35 | summary = buildVars.addon_info["addon_summary"] 36 | title = "{addonSummary} {addonVersion}".format( 37 | addonSummary=summary, addonVersion=buildVars.addon_info["addon_version"] 38 | ) 39 | headerDic = { 40 | "[[!meta title=\"": "# ", 41 | "\"]]": " #", 42 | } 43 | with codecs.open(source, "r", "utf-8") as f: 44 | mdText = f.read() 45 | for k, v in headerDic.items(): 46 | mdText = mdText.replace(k, v, 1) 47 | htmlText = markdown.markdown(mdText, extensions=mdExtensions) 48 | # Optimization: build resulting HTML text in one go instead of writing parts separately. 49 | docText = "\n".join([ 50 | "", 51 | "" % lang, 52 | "", 53 | "" 54 | "", 55 | "", 56 | "%s" % title, 57 | "\n", 58 | htmlText, 59 | "\n" 60 | ]) 61 | with codecs.open(dest, "w", "utf-8") as f: 62 | f.write(docText) 63 | 64 | 65 | def mdTool(env): 66 | mdAction = env.Action( 67 | lambda target, source, env: md2html(source[0].path, target[0].path), 68 | lambda target, source, env: 'Generating % s' % target[0], 69 | ) 70 | mdBuilder = env.Builder( 71 | action=mdAction, 72 | suffix='.html', 73 | src_suffix='.md', 74 | ) 75 | env['BUILDERS']['markdown'] = mdBuilder 76 | 77 | 78 | def validateVersionNumber(key, val, env): 79 | # Used to make sure version major.minor.patch are integers to comply with NV Access add-on store. 80 | # Ignore all this if version number is not specified, in which case json generator will validate this info. 81 | if val == "0.0.0": 82 | return 83 | versionNumber = val.split(".") 84 | if len(versionNumber) < 3: 85 | raise ValueError("versionNumber must have three parts (major.minor.patch)") 86 | if not all([part.isnumeric() for part in versionNumber]): 87 | raise ValueError("versionNumber (major.minor.patch) must be integers") 88 | 89 | 90 | vars = Variables() 91 | vars.Add("version", "The version of this build", buildVars.addon_info["addon_version"]) 92 | vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0", validateVersionNumber) 93 | vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) 94 | vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) 95 | 96 | env = Environment(variables=vars, ENV=os.environ, tools=['gettexttool', mdTool]) 97 | env.Append(**buildVars.addon_info) 98 | 99 | if env["dev"]: 100 | import datetime 101 | buildDate = datetime.datetime.now() 102 | year, month, day = str(buildDate.year), str(buildDate.month), str(buildDate.day) 103 | versionTimestamp = "".join([year, month.zfill(2), day.zfill(2)]) 104 | env["addon_version"] = f"{versionTimestamp}.0.0" 105 | env["versionNumber"] = f"{versionTimestamp}.0.0" 106 | env["channel"] = "dev" 107 | elif env["version"] is not None: 108 | env["addon_version"] = env["version"] 109 | if "channel" in env and env["channel"] is not None: 110 | env["addon_updateChannel"] = env["channel"] 111 | 112 | buildVars.addon_info["addon_version"] = env["addon_version"] 113 | buildVars.addon_info["addon_updateChannel"] = env["addon_updateChannel"] 114 | 115 | addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") 116 | 117 | 118 | def addonGenerator(target, source, env, for_signature): 119 | action = env.Action( 120 | lambda target, source, env: createAddonBundleFromPath(source[0].abspath, target[0].abspath) and None, 121 | lambda target, source, env: "Generating Addon %s" % target[0] 122 | ) 123 | return action 124 | 125 | 126 | def manifestGenerator(target, source, env, for_signature): 127 | action = env.Action( 128 | lambda target, source, env: generateManifest(source[0].abspath, target[0].abspath) and None, 129 | lambda target, source, env: "Generating manifest %s" % target[0] 130 | ) 131 | return action 132 | 133 | 134 | def translatedManifestGenerator(target, source, env, for_signature): 135 | dir = os.path.abspath(os.path.join(os.path.dirname(str(source[0])), "..")) 136 | lang = os.path.basename(dir) 137 | action = env.Action( 138 | lambda target, source, env: generateTranslatedManifest(source[1].abspath, lang, target[0].abspath) and None, 139 | lambda target, source, env: "Generating translated manifest %s" % target[0] 140 | ) 141 | return action 142 | 143 | 144 | env['BUILDERS']['NVDAAddon'] = Builder(generator=addonGenerator) 145 | env['BUILDERS']['NVDAManifest'] = Builder(generator=manifestGenerator) 146 | env['BUILDERS']['NVDATranslatedManifest'] = Builder(generator=translatedManifestGenerator) 147 | 148 | 149 | def createAddonHelp(dir): 150 | docsDir = os.path.join(dir, "doc") 151 | if os.path.isfile("style.css"): 152 | cssPath = os.path.join(docsDir, "style.css") 153 | cssTarget = env.Command(cssPath, "style.css", Copy("$TARGET", "$SOURCE")) 154 | env.Depends(addon, cssTarget) 155 | if os.path.isfile("readme.md"): 156 | readmePath = os.path.join(docsDir, buildVars.baseLanguage, "readme.md") 157 | readmeTarget = env.Command(readmePath, "readme.md", Copy("$TARGET", "$SOURCE")) 158 | env.Depends(addon, readmeTarget) 159 | 160 | 161 | def createAddonBundleFromPath(path, dest): 162 | """ Creates a bundle from a directory that contains an addon manifest file.""" 163 | basedir = os.path.abspath(path) 164 | with zipfile.ZipFile(dest, 'w', zipfile.ZIP_DEFLATED) as z: 165 | # FIXME: the include/exclude feature may or may not be useful. Also python files can be pre-compiled. 166 | for dir, dirnames, filenames in os.walk(basedir): 167 | relativePath = os.path.relpath(dir, basedir) 168 | for filename in filenames: 169 | pathInBundle = os.path.join(relativePath, filename) 170 | absPath = os.path.join(dir, filename) 171 | if pathInBundle not in buildVars.excludedFiles: 172 | z.write(absPath, pathInBundle) 173 | # Add-on store does not require submitting json files. 174 | # createAddonStoreJson(dest) 175 | return dest 176 | 177 | 178 | def createAddonStoreJson(bundle): 179 | """Creates add-on store JSON file from an add-on package and manifest data.""" 180 | import json 181 | import hashlib 182 | # Set different json file names and version number properties based on version number parsing results. 183 | if env["versionNumber"] == "0.0.0": 184 | env["versionNumber"] = buildVars.addon_info["addon_version"] 185 | versionNumberParsed = env["versionNumber"].split(".") 186 | if all([part.isnumeric() for part in versionNumberParsed]): 187 | if len(versionNumberParsed) == 1: 188 | versionNumberParsed += ["0", "0"] 189 | elif len(versionNumberParsed) == 2: 190 | versionNumberParsed.append("0") 191 | else: 192 | versionNumberParsed = [] 193 | if len(versionNumberParsed): 194 | major, minor, patch = [int(part) for part in versionNumberParsed] 195 | jsonFilename = f'{major}.{minor}.{patch}.json' 196 | else: 197 | jsonFilename = f'{buildVars.addon_info["addon_version"]}.json' 198 | major, minor, patch = 0, 0, 0 199 | print('Generating % s' % jsonFilename) 200 | sha256 = hashlib.sha256() 201 | with open(bundle, "rb") as f: 202 | for byte_block in iter(lambda: f.read(65536), b""): 203 | sha256.update(byte_block) 204 | hashValue = sha256.hexdigest() 205 | try: 206 | minimumNVDAVersion = buildVars.addon_info["addon_minimumNVDAVersion"].split(".") 207 | except AttributeError: 208 | minimumNVDAVersion = [0, 0, 0] 209 | minMajor, minMinor = minimumNVDAVersion[:2] 210 | minPatch = minimumNVDAVersion[-1] if len(minimumNVDAVersion) == 3 else "0" 211 | try: 212 | lastTestedNVDAVersion = buildVars.addon_info["addon_lastTestedNVDAVersion"].split(".") 213 | except AttributeError: 214 | lastTestedNVDAVersion = [0, 0, 0] 215 | lastTestedMajor, lastTestedMinor = lastTestedNVDAVersion[:2] 216 | lastTestedPatch = lastTestedNVDAVersion[-1] if len(lastTestedNVDAVersion) == 3 else "0" 217 | channel = buildVars.addon_info["addon_updateChannel"] 218 | if channel is None: 219 | channel = "stable" 220 | addonStoreEntry = { 221 | "addonId": buildVars.addon_info["addon_name"], 222 | "displayName": buildVars.addon_info["addon_summary"], 223 | "URL": "", 224 | "description": buildVars.addon_info["addon_description"], 225 | "sha256": hashValue, 226 | "homepage": buildVars.addon_info["addon_url"], 227 | "addonVersionName": buildVars.addon_info["addon_version"], 228 | "addonVersionNumber": { 229 | "major": major, 230 | "minor": minor, 231 | "patch": patch 232 | }, 233 | "minNVDAVersion": { 234 | "major": int(minMajor), 235 | "minor": int(minMinor), 236 | "patch": int(minPatch) 237 | }, 238 | "lastTestedVersion": { 239 | "major": int(lastTestedMajor), 240 | "minor": int(lastTestedMinor), 241 | "patch": int(lastTestedPatch) 242 | }, 243 | "channel": channel, 244 | "publisher": "", 245 | "sourceURL": buildVars.addon_info["addon_sourceURL"], 246 | "license": buildVars.addon_info["addon_license"], 247 | "licenseURL": buildVars.addon_info["addon_licenseURL"], 248 | } 249 | with open(jsonFilename, "w") as addonStoreJson: 250 | json.dump(addonStoreEntry, addonStoreJson, indent="\t") 251 | 252 | 253 | def generateManifest(source, dest): 254 | addon_info = buildVars.addon_info 255 | with codecs.open(source, "r", "utf-8") as f: 256 | manifest_template = f.read() 257 | manifest = manifest_template.format(**addon_info) 258 | with codecs.open(dest, "w", "utf-8") as f: 259 | f.write(manifest) 260 | 261 | 262 | def generateTranslatedManifest(source, language, out): 263 | _ = gettext.translation("nvda", localedir=os.path.join("addon", "locale"), languages=[language]).gettext 264 | vars = {} 265 | for var in ("addon_summary", "addon_description"): 266 | vars[var] = _(buildVars.addon_info[var]) 267 | with codecs.open(source, "r", "utf-8") as f: 268 | manifest_template = f.read() 269 | result = manifest_template.format(**vars) 270 | with codecs.open(out, "w", "utf-8") as f: 271 | f.write(result) 272 | 273 | 274 | def expandGlobs(files): 275 | return [f for pattern in files for f in env.Glob(pattern)] 276 | 277 | 278 | addon = env.NVDAAddon(addonFile, env.Dir('addon')) 279 | 280 | langDirs = [f for f in env.Glob(os.path.join("addon", "locale", "*"))] 281 | 282 | # Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated 283 | for dir in langDirs: 284 | poFile = dir.File(os.path.join("LC_MESSAGES", "nvda.po")) 285 | moFile = env.gettextMoFile(poFile) 286 | env.Depends(moFile, poFile) 287 | translatedManifest = env.NVDATranslatedManifest( 288 | dir.File("manifest.ini"), 289 | [moFile, os.path.join("manifest-translated.ini.tpl")] 290 | ) 291 | env.Depends(translatedManifest, ["buildVars.py"]) 292 | env.Depends(addon, [translatedManifest, moFile]) 293 | 294 | pythonFiles = expandGlobs(buildVars.pythonSources) 295 | for file in pythonFiles: 296 | env.Depends(addon, file) 297 | 298 | # Convert markdown files to html 299 | # We need at least doc in English and should enable the Help button for the add-on in Add-ons Manager 300 | createAddonHelp("addon") 301 | for mdFile in env.Glob(os.path.join('addon', 'doc', '*', '*.md')): 302 | htmlFile = env.markdown(mdFile) 303 | try: # It is possible that no moFile was set, because an add-on has no translations. 304 | moFile 305 | except NameError: # Runs if there is no moFile 306 | env.Depends(htmlFile, mdFile) 307 | else: # Runs if there is a moFile 308 | env.Depends(htmlFile, [mdFile, moFile]) 309 | env.Depends(addon, htmlFile) 310 | 311 | # Pot target 312 | i18nFiles = expandGlobs(buildVars.i18nSources) 313 | gettextvars = { 314 | 'gettext_package_bugs_address': 'nvda-translations@groups.io', 315 | 'gettext_package_name': buildVars.addon_info['addon_name'], 316 | 'gettext_package_version': buildVars.addon_info['addon_version'] 317 | } 318 | 319 | pot = env.gettextPotFile("${addon_name}.pot", i18nFiles, **gettextvars) 320 | env.Alias('pot', pot) 321 | env.Depends(pot, i18nFiles) 322 | mergePot = env.gettextMergePotFile("${addon_name}-merge.pot", i18nFiles, **gettextvars) 323 | env.Alias('mergePot', mergePot) 324 | env.Depends(mergePot, i18nFiles) 325 | 326 | # Generate Manifest path 327 | manifest = env.NVDAManifest(os.path.join("addon", "manifest.ini"), os.path.join("manifest.ini.tpl")) 328 | # Ensure manifest is rebuilt if buildVars is updated. 329 | env.Depends(manifest, "buildVars.py") 330 | 331 | env.Depends(addon, manifest) 332 | env.Default(addon) 333 | env.Clean(addon, ['.sconsign.dblite', 'addon/doc/' + buildVars.baseLanguage + '/']) 334 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | --------------------------------------------------------------------------------