plover 5.0.0.dev3__tar.gz → 5.0.0rc1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/NEWS.md +19 -0
- {plover-5.0.0.dev3/plover.egg-info → plover-5.0.0rc1}/PKG-INFO +1 -1
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/ci.md +1 -6
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/conf.py +1 -1
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/__init__.py +1 -1
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/linux/keyboardcontrol_uinput.py +137 -37
- {plover-5.0.0.dev3 → plover-5.0.0rc1/plover.egg-info}/PKG-INFO +1 -1
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/CONTRIBUTING.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/LICENSE.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/MANIFEST.in +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/README.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/SCOWL_README.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/_static/board-layout.png +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/_static/custom.css +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/_static/de-speech.png +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/_static/dolores.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/_static/engine-flow.png +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/_static/favicon.ico +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/_static/jp-speech.png +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/_static/keys-layout.png +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/_static/uncomfortable.png +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/_templates/breadcrumbs.html +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/_templates/layout.html +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/add_translation.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/config.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/dictionary.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/dictionary_lib.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/engine.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/exception.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/formatting.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/i18n.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/key_combo.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/log.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/machine.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/machine_keyboard_capture.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/machine_keymap.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/misc.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/orthography.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/oslayer.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/oslayer_config.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/oslayer_controller.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/oslayer_i18n.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/oslayer_keyboardcontrol.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/oslayer_log.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/oslayer_wmctrl.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/output.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/plover.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/plover_stroke.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/qt.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/registry.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/resource.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/steno.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/steno_dictionary.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/suggestions.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/system.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api/translation.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/api_reference.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/basic_usage.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/cli_reference.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/configuration.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/contributing.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/design.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/developer_guide.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/dict_editor.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/dict_formats.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/dictionaries.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/hardware_communication.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/hardware_setup.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/i18n.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/index.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/installation.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/internals.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/platform_layer.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/plugin-dev/commands.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/plugin-dev/dictionaries.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/plugin-dev/extensions.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/plugin-dev/gui_tools.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/plugin-dev/machines.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/plugin-dev/macros.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/plugin-dev/metas.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/plugin-dev/publishing.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/plugin-dev/setup.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/plugin-dev/systems.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/plugin_dev.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/plugins.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/releases.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/requirements.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/system-dev/board-layout.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/system-dev/key-arrangement.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/system-dev/layout-test.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/system-dev/steno-system.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/system-dev/system.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/system_dev.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/doc/translation_language.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/linux/README.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/linux/appimage/Dockerfile +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/linux/appimage/apprun.sh +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/linux/appimage/blacklist.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/linux/appimage/build.sh +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/linux/appimage/deps.sh +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/linux/appimage/pyinfo.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/linux/plover.desktop +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/news.d/api/.gitignore +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/news.d/bugfix/.gitignore +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/news.d/feature/.gitignore +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/news.d/template.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/osx/README.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/osx/app_resources/Info.plist +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/osx/app_resources/dist_blacklist.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/osx/app_resources/plover.icns +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/osx/app_resources/plover_launcher.c +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/osx/deps.sh +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/osx/dmg_resources/background.png +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/osx/dmg_resources/background.psd +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/osx/dmg_resources/background@2x.png +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/osx/dmg_resources/settings.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/osx/make_app.sh +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/__main__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/assets/american_english_words.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/assets/commands.json +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/assets/main.json +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/assets/plover-icon.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/assets/plover.ico +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/assets/plover.png +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/assets/user.json +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/command/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/command/set_config.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/config.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/dictionary/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/dictionary/base.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/dictionary/helpers.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/dictionary/json_dict.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/dictionary/loading_manager.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/dictionary/rtfcre_dict.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/dictionary/rtfcre_parse.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/engine.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/exception.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/formatting.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_none/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_none/add_translation.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_none/engine.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_none/main.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/about_dialog.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/about_dialog.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/add_translation_dialog.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/add_translation_dialog.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/add_translation_widget.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/add_translation_widget.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/config_file_widget.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/config_keyboard_widget.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/config_serial_widget.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/config_window.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/config_window.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/console_widget.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/console_widget.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/dictionaries_widget.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/dictionaries_widget.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/dictionary_editor.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/dictionary_editor.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/engine.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/info_browser.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/log_qt.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/lookup_dialog.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/lookup_dialog.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/machine_options.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/main.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/main_window.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/main_window.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/paper_tape.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/paper_tape.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/plugins_manager.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/plugins_manager.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/add.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/dictionary_error.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/dictionary_favorite.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/dictionary_loading.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/dictionary_normal.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/dictionary_readonly.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/down.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/folder.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/font_selector.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/git.png +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/lightbulb.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/lookup.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/pencil.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/pin.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/plover.png +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/plugins_manager.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/reconnect.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/remove.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/save.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/settings.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/state-disabled.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/state-disconnected.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/state-enabled.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/tape.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/translation_add.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/trash.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/undo.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources/up.svg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/resources.qrc +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/run_dialog.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/run_dialog.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/steno_validator.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/suggestions_dialog.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/suggestions_dialog.ui +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/suggestions_widget.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/tool.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/trayicon.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/gui_qt/utils.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/i18n.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/key_combo.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/log.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/machine/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/machine/base.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/machine/geminipr.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/machine/keyboard.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/machine/keyboard_capture/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/machine/keymap.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/machine/passport.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/machine/procat.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/machine/stentura.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/machine/txbolt.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/macro/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/macro/repeat.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/macro/retro.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/macro/undo.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/messages/es/LC_MESSAGES/plover.po +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/messages/fr/LC_MESSAGES/plover.po +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/messages/it/LC_MESSAGES/plover.po +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/messages/nl/LC_MESSAGES/plover.po +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/messages/plover.pot +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/messages/zh_tw/LC_MESSAGES/plover.po +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/meta/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/meta/attach.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/meta/case.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/meta/command.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/meta/conditional.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/meta/currency.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/meta/glue.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/meta/key_combo.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/meta/mode.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/meta/punctuation.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/meta/word_end.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/misc.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/orthography.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/config.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/controller.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/linux/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/linux/display_server.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/linux/i18n.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/linux/keyboardcontrol.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/linux/keyboardcontrol_x11.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/linux/log.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/linux/log_dbus.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/linux/serial.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/linux/wmctrl.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/linux/wmctrl_x11.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/osx/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/osx/i18n.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/osx/keyboardcontrol.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/osx/keyboardlayout.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/osx/log.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/osx/serial.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/osx/wmctrl.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/windows/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/windows/i18n.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/windows/keyboardcontrol.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/windows/keyboardlayout.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/windows/log.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/windows/serial.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/oslayer/windows/wmctrl.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/output/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/output/keyboard.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/plugins_manager/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/plugins_manager/__main__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/plugins_manager/global_registry.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/plugins_manager/local_registry.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/plugins_manager/package_index.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/plugins_manager/pip_wrapper.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/plugins_manager/plugin_metadata.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/plugins_manager/registry.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/plugins_manager/requests.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/plugins_manager/utils.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/registry.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/resource.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/scripts/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/scripts/dist_main.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/scripts/main.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/scripts/send_command.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/steno.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/steno_dictionary.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/suggestions.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/system/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/system/english_stenotype.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover/translation.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover.egg-info/SOURCES.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover.egg-info/dependency_links.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover.egg-info/entry_points.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover.egg-info/requires.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover.egg-info/top_level.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover.egg-info/zip-safe +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/check_requirements.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/download.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/functions.sh +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/get_pip.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/install_wheels.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/pyqt.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/setup.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/source_less.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/testing/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/testing/blackbox.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/testing/dict.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/testing/output.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/testing/parametrize.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/testing/steno.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/testing/steno_dictionary.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/tree.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/trim.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/plover_build_utils/zipdir.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/pyproject.toml +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/pytest.ini +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/bootstrap.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/build.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/ci.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/code_quality.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/constraints.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/dev.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/dist.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/dist_extra_gui_qt.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/dist_extra_log.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/packaging.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/release.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/setup.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/reqs/test.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/setup.cfg +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/setup.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/conftest.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/gui_qt/__init__.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/gui_qt/test_dictionaries_widget.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/gui_qt/test_steno_validator.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/py37compat.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_blackbox.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_command.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_config.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_default_dict.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_engine.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_formatting.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_json_dict.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_key_combo.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_keyboard.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_keymap.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_loading_manager.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_log.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_machine.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_misc.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_orthography.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_passport.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_resource.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_rtfcre_dict.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_steno.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_steno_dictionary.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_stentura.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/test/test_translation.py +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/tox.ini +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/windows/README.md +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/windows/dist_blacklist.txt +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/windows/dist_build.sh +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/windows/dist_deps.sh +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/windows/installer.bmp +0 -0
- {plover-5.0.0.dev3 → plover-5.0.0rc1}/windows/installer.nsi +0 -0
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
# v5.0.0rc1 (2025-09-02)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Features
|
|
5
|
+
|
|
6
|
+
### Linux
|
|
7
|
+
|
|
8
|
+
- Refactor Uinput to use pipe instead of select with timeout. (#1760)
|
|
9
|
+
- Passthrough keyboard shortcuts. (#1761)
|
|
10
|
+
- Uinput: refactor initialization and cleanup. (#1765)
|
|
11
|
+
|
|
12
|
+
## Bugfixes
|
|
13
|
+
|
|
14
|
+
No significant changes.
|
|
15
|
+
|
|
16
|
+
## API
|
|
17
|
+
|
|
18
|
+
No significant changes.
|
|
19
|
+
|
|
1
20
|
# v5.0.0.dev3 (2025-07-14)
|
|
2
21
|
|
|
3
22
|
|
|
@@ -123,13 +123,8 @@ jobs completed successfully.
|
|
|
123
123
|
### PyPI release
|
|
124
124
|
|
|
125
125
|
On *tagged* release, the source distribution and wheel are published
|
|
126
|
-
to PyPI.
|
|
126
|
+
to PyPI via [Trusted Publishing](https://docs.pypi.org/trusted-publishers/).
|
|
127
127
|
|
|
128
|
-
For this to work, a valid [PyPI token](https://pypi.org/help/#apitoken)
|
|
129
|
-
must be configured: the `PYPI_TOKEN` secret of the `release`
|
|
130
|
-
[environment](https://docs.github.com/en/actions/reference/environments)
|
|
131
|
-
will be used. Additionally, the optional `PYPI_URL` secret can be set to
|
|
132
|
-
use another PyPI compatible index (e.g. Test PyPI).
|
|
133
128
|
|
|
134
129
|
### GitHub release
|
|
135
130
|
|
|
@@ -13,7 +13,7 @@ else:
|
|
|
13
13
|
# want to translate anyway.
|
|
14
14
|
_ = lambda s: s
|
|
15
15
|
|
|
16
|
-
__version__ = "5.0.
|
|
16
|
+
__version__ = "5.0.0rc1"
|
|
17
17
|
__copyright__ = "(C) Open Steno Project"
|
|
18
18
|
__url__ = "http://www.openstenoproject.org/"
|
|
19
19
|
__download_url__ = "http://www.openstenoproject.org/plover"
|
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
from evdev import
|
|
1
|
+
from evdev import (
|
|
2
|
+
UInput,
|
|
3
|
+
ecodes as e,
|
|
4
|
+
util,
|
|
5
|
+
InputDevice,
|
|
6
|
+
list_devices,
|
|
7
|
+
InputEvent,
|
|
8
|
+
KeyEvent,
|
|
9
|
+
)
|
|
2
10
|
import threading
|
|
3
|
-
|
|
11
|
+
import os
|
|
12
|
+
import selectors
|
|
13
|
+
|
|
4
14
|
from psutil import process_iter
|
|
5
15
|
|
|
6
16
|
from plover.output.keyboard import GenericKeyboardEmulation
|
|
@@ -320,6 +330,17 @@ KEYCODE_TO_KEY = dict(
|
|
|
320
330
|
zip(LAYOUTS[DEFAULT_LAYOUT].values(), LAYOUTS[DEFAULT_LAYOUT].keys())
|
|
321
331
|
)
|
|
322
332
|
|
|
333
|
+
MODIFIER_KEY_CODES: set[int] = {
|
|
334
|
+
e.KEY_LEFTSHIFT,
|
|
335
|
+
e.KEY_RIGHTSHIFT,
|
|
336
|
+
e.KEY_LEFTCTRL,
|
|
337
|
+
e.KEY_RIGHTCTRL,
|
|
338
|
+
e.KEY_LEFTALT,
|
|
339
|
+
e.KEY_RIGHTALT,
|
|
340
|
+
e.KEY_LEFTMETA,
|
|
341
|
+
e.KEY_RIGHTMETA,
|
|
342
|
+
}
|
|
343
|
+
|
|
323
344
|
|
|
324
345
|
class KeyboardEmulation(GenericKeyboardEmulation):
|
|
325
346
|
def __init__(self):
|
|
@@ -412,21 +433,30 @@ class KeyboardEmulation(GenericKeyboardEmulation):
|
|
|
412
433
|
|
|
413
434
|
|
|
414
435
|
class KeyboardCapture(Capture):
|
|
436
|
+
_selector: selectors.DefaultSelector
|
|
437
|
+
_device_thread: threading.Thread | None
|
|
438
|
+
# Pipes to signal `_run` thread to stop
|
|
439
|
+
_device_thread_read_pipe: int | None
|
|
440
|
+
_device_thread_write_pipe: int | None
|
|
441
|
+
|
|
415
442
|
def __init__(self):
|
|
416
443
|
super().__init__()
|
|
417
|
-
# This is based on the example from the python-evdev documentation, using the first of the three alternative methods: https://python-evdev.readthedocs.io/en/latest/tutorial.html#reading-events-from-multiple-devices-using-select
|
|
418
444
|
self._devices = self._get_devices()
|
|
419
|
-
|
|
420
|
-
self.
|
|
445
|
+
|
|
446
|
+
self._selector = selectors.DefaultSelector()
|
|
447
|
+
self._device_thread = None
|
|
448
|
+
self._device_thread_read_pipe = None
|
|
449
|
+
self._device_thread_write_pipe = None
|
|
450
|
+
|
|
421
451
|
self._res = util.find_ecodes_by_regex(r"KEY_.*")
|
|
422
452
|
self._ui = UInput(self._res)
|
|
423
|
-
self._suppressed_keys =
|
|
453
|
+
self._suppressed_keys = set()
|
|
424
454
|
# The keycodes from evdev, e.g. e.KEY_A refers to the *physical* a, which corresponds with the qwerty layout.
|
|
425
455
|
|
|
426
456
|
def _get_devices(self):
|
|
427
457
|
input_devices = [InputDevice(path) for path in list_devices()]
|
|
428
458
|
keyboard_devices = [dev for dev in input_devices if self._filter_devices(dev)]
|
|
429
|
-
return
|
|
459
|
+
return keyboard_devices
|
|
430
460
|
|
|
431
461
|
def _filter_devices(self, device):
|
|
432
462
|
"""
|
|
@@ -451,7 +481,7 @@ class KeyboardCapture(Capture):
|
|
|
451
481
|
There is likely a race condition here between checking active keys and
|
|
452
482
|
actually grabbing the device, but it appears to work fine.
|
|
453
483
|
"""
|
|
454
|
-
for device in self._devices
|
|
484
|
+
for device in self._devices:
|
|
455
485
|
if len(device.active_keys()) > 0:
|
|
456
486
|
for _ in device.read_loop():
|
|
457
487
|
if len(device.active_keys()) == 0:
|
|
@@ -461,26 +491,50 @@ class KeyboardCapture(Capture):
|
|
|
461
491
|
|
|
462
492
|
def _ungrab_devices(self):
|
|
463
493
|
"""Ungrab all devices. Handles all exceptions when ungrabbing."""
|
|
464
|
-
for device in self._devices
|
|
494
|
+
for device in self._devices:
|
|
465
495
|
try:
|
|
466
496
|
device.ungrab()
|
|
467
497
|
except:
|
|
468
498
|
log.debug("failed to ungrab device", exc_info=True)
|
|
469
499
|
|
|
470
500
|
def start(self):
|
|
501
|
+
# Exception handling note: cancel() will eventually be called when the
|
|
502
|
+
# machine reconnect button is pressed or when the machine is changed.
|
|
503
|
+
# Therefore, cancel() does not need to be called in the except block.
|
|
471
504
|
try:
|
|
472
505
|
self._grab_devices()
|
|
473
|
-
|
|
506
|
+
self._device_thread_read_pipe, self._device_thread_write_pipe = os.pipe()
|
|
507
|
+
self._selector.register(self._device_thread_read_pipe, selectors.EVENT_READ)
|
|
508
|
+
for device in self._devices:
|
|
509
|
+
self._selector.register(device, selectors.EVENT_READ)
|
|
510
|
+
|
|
511
|
+
self._device_thread = threading.Thread(target=self._run)
|
|
512
|
+
self._device_thread.start()
|
|
513
|
+
except Exception:
|
|
474
514
|
self._ungrab_devices()
|
|
515
|
+
self._ui.close()
|
|
475
516
|
raise
|
|
476
|
-
self._running = True
|
|
477
|
-
self._thread = threading.Thread(target=self._run)
|
|
478
|
-
self._thread.start()
|
|
479
517
|
|
|
480
518
|
def cancel(self):
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
self.
|
|
519
|
+
if (
|
|
520
|
+
self._device_thread_read_pipe is None
|
|
521
|
+
or self._device_thread_write_pipe is None
|
|
522
|
+
):
|
|
523
|
+
# The only way for these pipes to be None is if pipe creation in start() failed
|
|
524
|
+
# In that case, no other code after pipe creation would have run
|
|
525
|
+
# and no cleanup is required
|
|
526
|
+
return
|
|
527
|
+
try:
|
|
528
|
+
# Write some arbitrary data to the pipe to signal the _run thread to stop
|
|
529
|
+
os.write(self._device_thread_write_pipe, b"a")
|
|
530
|
+
if self._device_thread is not None:
|
|
531
|
+
self._device_thread.join()
|
|
532
|
+
self._selector.close()
|
|
533
|
+
except Exception:
|
|
534
|
+
log.debug("error stopping KeyboardCapture", exc_info=True)
|
|
535
|
+
finally:
|
|
536
|
+
os.close(self._device_thread_read_pipe)
|
|
537
|
+
os.close(self._device_thread_write_pipe)
|
|
484
538
|
|
|
485
539
|
def suppress(self, suppressed_keys=()):
|
|
486
540
|
"""
|
|
@@ -488,31 +542,77 @@ class KeyboardCapture(Capture):
|
|
|
488
542
|
are passed through to a UInput device and emulated, while keys in this list get sent to plover.
|
|
489
543
|
It does add a little bit of delay, but that is not noticeable.
|
|
490
544
|
"""
|
|
491
|
-
self._suppressed_keys = suppressed_keys
|
|
545
|
+
self._suppressed_keys = set(suppressed_keys)
|
|
492
546
|
|
|
493
547
|
def _run(self):
|
|
548
|
+
keys_pressed_with_modifier: set[int] = set()
|
|
549
|
+
down_modifier_keys: set[int] = set()
|
|
550
|
+
|
|
551
|
+
def _process_key_event(event: InputEvent) -> tuple[str | None, bool]:
|
|
552
|
+
"""
|
|
553
|
+
Processes an InputEvent to determine which key Plover should receive
|
|
554
|
+
and whether the event should be suppressed.
|
|
555
|
+
Considers pressed modifiers and Plover's suppressed keys.
|
|
556
|
+
Returns a tuple of (key_to_send_to_plover, suppress)
|
|
557
|
+
"""
|
|
558
|
+
if not self._suppressed_keys:
|
|
559
|
+
# No keys are suppressed
|
|
560
|
+
# Always send to Plover so that it can handle global shortcuts like PLOVER_TOGGLE (PHROLG)
|
|
561
|
+
return KEYCODE_TO_KEY.get(event.code, None), False
|
|
562
|
+
if event.code in MODIFIER_KEY_CODES:
|
|
563
|
+
# Can't use if-else because there is a third case: key_hold
|
|
564
|
+
if event.value == KeyEvent.key_down:
|
|
565
|
+
down_modifier_keys.add(event.code)
|
|
566
|
+
elif event.value == KeyEvent.key_up:
|
|
567
|
+
down_modifier_keys.discard(event.code)
|
|
568
|
+
return None, False
|
|
569
|
+
key = KEYCODE_TO_KEY.get(event.code, None)
|
|
570
|
+
if key is None:
|
|
571
|
+
# Key is unhandled. Passthrough
|
|
572
|
+
return None, False
|
|
573
|
+
if event.value == KeyEvent.key_down and down_modifier_keys:
|
|
574
|
+
keys_pressed_with_modifier.add(event.code)
|
|
575
|
+
return None, False
|
|
576
|
+
if (
|
|
577
|
+
event.value == KeyEvent.key_up
|
|
578
|
+
and event.code in keys_pressed_with_modifier
|
|
579
|
+
):
|
|
580
|
+
# Must pass through key up event if key was pressed with modifier
|
|
581
|
+
# or else it will stay pressed down and start repeating.
|
|
582
|
+
# Must release even if modifier key was released first
|
|
583
|
+
keys_pressed_with_modifier.discard(event.code)
|
|
584
|
+
return None, False
|
|
585
|
+
suppress = key in self._suppressed_keys
|
|
586
|
+
return key, suppress
|
|
587
|
+
|
|
494
588
|
try:
|
|
495
|
-
while
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
for fd in r:
|
|
504
|
-
for event in self._devices[fd].read():
|
|
589
|
+
while True:
|
|
590
|
+
for key, events in self._selector.select():
|
|
591
|
+
if key.fd == self._device_thread_read_pipe:
|
|
592
|
+
# Stop this thread
|
|
593
|
+
return
|
|
594
|
+
assert isinstance(key.fileobj, InputDevice)
|
|
595
|
+
device: InputDevice = key.fileobj
|
|
596
|
+
for event in device.read():
|
|
505
597
|
if event.type == e.EV_KEY:
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
598
|
+
key_to_send_to_plover, suppress = _process_key_event(event)
|
|
599
|
+
if key_to_send_to_plover is not None:
|
|
600
|
+
# Always send keys to Plover when no keys suppressed.
|
|
601
|
+
# This is required for global shortcuts like
|
|
602
|
+
# Plover toggle (PHROLG) when Plover is disabled.
|
|
603
|
+
# Note: Must explicitly check key_up or key_down
|
|
604
|
+
# because there is a third case: key_hold
|
|
605
|
+
if event.value == KeyEvent.key_down:
|
|
606
|
+
self.key_down(key_to_send_to_plover)
|
|
607
|
+
elif event.value == KeyEvent.key_up:
|
|
608
|
+
self.key_up(key_to_send_to_plover)
|
|
609
|
+
if suppress:
|
|
610
|
+
# Skip rest of loop to prevent event from
|
|
611
|
+
# being passed through
|
|
612
|
+
continue
|
|
613
|
+
|
|
614
|
+
# Passthrough event
|
|
615
|
+
self._ui.write_event(event)
|
|
516
616
|
except:
|
|
517
617
|
log.error("keyboard capture error", exc_info=True)
|
|
518
618
|
finally:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|