[
  {
    "path": ".coveragerc",
    "content": "[run]\nbranch = True\n\nsource =\n    hid_parser\n    hidapi\n    keysyms\n    logitech_receiver\n    solaar\n\nomit =\n    */tests/*\n    */setup.py\n    */__main__.py\n\n[report]\nexclude_lines =\n    pragma: no cover\n    if __name__ == '__main__':\n    if typing.TYPE_CHECKING\n\nfail_under = 40\n"
  },
  {
    "path": ".git-blame-ignore-revs",
    "content": "# yapf bulk change\n72a8d311bce64b1536c08e754d22bb91efb66460\n# isort bulk change\ne6369e0c3c240715a0a2daede6c3b225ed63cf60\n# pre-commit bulk change\n33521558ed7007c24b24127f1448c2c23ecbfb35\n# flake8 bulk change\n627185079f65c9cc471194b7927c833682e4a7a3\n# yapf style update\n27c90fa736d8a7a1ef6acda4345d3599862e185c\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Information**\n<!-- Make sure that your issue is not one of the known issues in the\n     Solaar documentation at https://pwr-solaar.github.io/Solaar/ -->\n<!-- Make sure that Solaar's udev rule is running by executing\n     `ls -l /dev/hidraw*` and looking for + as the last character of the permissions. -->\n<!-- Do not bother opening an issue for a version older than 1.1.14.\n     Upgrade to the current version and see if your issue persists. -->\n<!-- If you are not running the current version of Solaar,\n     strongly consider upgrading to the current version. -->\n<!-- Note that some distributions have very old versions of Solaar\n     as their default version.  -->\n\n- Solaar version (`solaar --version` or `git describe --tags` if cloned from this repository):\n- Distribution:\n- Kernel version (ex. `uname -srmo`):\n- Output of `solaar show`:\n<!-- To run `solaar show` in 1.1.18 you have to clone Solaar from this repository\n  and `run bin/solaar show` from the download directory. -->\n\n<details>\n\n```\nSOLAAR SHOW OUTPUT HERE\n```\n</details>\n\n- Contents of `~/.config/solaar/config.yaml` (or `~/.config/solaar/config.json` if `~/.config/solaar/config.yaml` not present):\n\n<details>\n\n```\nCONTENTS HERE\n```\n</details>\n\n\n- Errors or warrnings from Solaar:\n<!-- Under normal operation Solaar keeps a log of warning and error messages\nin ~/.tmp while it is running, as a file starting with 'Solaar'.\nIf this file is not available or does not have useful information you can\nrun Solaar as `solaar -ddd`, after killing any running Solaar processes to\nhave Solaar log debug, informational, warning, and error messages to stdout. -->\n\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Information**\n<!-- The version of Solaar in this repository has more features than released vesions.  Update to this version before asking for a new feature. -->\n- Solaar version (`solaar --version` and `git describe --tags`):\n- Distribution:\n- Kernel version (ex. `uname -srmo`):\n- Output of `solaar show` for the target device (if applicable):\n\n<details>\n\n```\nOUTPUT HERE\n```\n</details>\n\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/workflows/checks.yml",
    "content": "name: checks\n\non: [push, pull_request]\n\njobs:\n  pre-commit:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Checkout\n      uses: actions/checkout@v4\n\n    - name: Set up Python\n      uses: actions/setup-python@v5\n\n    - name: Run pre-commit\n      uses: pre-commit/action@v3.0.0\n"
  },
  {
    "path": ".github/workflows/gh-pages.yml",
    "content": "name: Deploy to GitHub Pages\non:\n  push:\n    branches:\n      - master\n\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\nconcurrency:\n  group: 'pages'\n  cancel-in-progress: false\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Set up Python\n        uses: actions/setup-python@v5\n        with:\n          python-version: '3.x'\n\n      - name: Install dependencies\n        run: |\n          pip install mkdocs mkdocs-rtd-dropdown mkdocs-mermaid2-plugin mkdocstrings[python]\n\n      - name: Build and deploy\n        run: |\n          mkdocs build\n\n      - name: Upload artifact\n        uses: actions/upload-pages-artifact@v3\n        with:\n          path: 'site'\n\n  deploy:\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    runs-on: ubuntu-latest\n    needs: build\n\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: tests\n\non: [push, pull_request]\n\njobs:\n  ubuntu-tests:\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        python-version: [3.13]\n      fail-fast: false\n\n    steps:\n    - name: Checkout\n      uses: actions/checkout@v4\n\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v5\n      with:\n        python-version: ${{ matrix.python-version }}\n\n    - name: Install Ubuntu dependencies for python 3.8\n      if: matrix.python-version == '3.8'\n      run: |\n        make install_apt\n\n    - name: Install Ubuntu dependencies for python 3.13\n      if: matrix.python-version == '3.13'\n      run: |\n        make install_apt_python3.13\n\n    - name: Install Python dependencies\n      run: |\n        make install_pip PIP_ARGS='.[\"test\"]'\n\n    - name: Run tests on Ubuntu\n      run: |\n        make test\n\n    - name: Upload coverage to Codecov\n      if: github.ref == 'refs/heads/master'\n      uses: codecov/codecov-action@v4.5.0\n      with:\n        directory: ./coverage/reports/\n        env_vars: OS, PYTHON\n        files: ./coverage.xml\n        flags: unittests\n        name: codecov-umbrella\n        token: ${{ secrets.CODECOV_TOKEN }}\n\n  macos-tests:\n    runs-on: macos-latest\n\n    strategy:\n      matrix:\n        python-version: [3.13]\n      fail-fast: false\n\n    steps:\n    - name: Checkout\n      uses: actions/checkout@v4\n\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v5\n      with:\n        python-version: ${{ matrix.python-version }}\n\n    - name: Set up macOS dependencies\n      run: |\n        make install_brew\n    - name: Add Homebrew's library directory to dyld search path\n      run: |\n        echo \"DYLD_FALLBACK_LIBRARY_PATH=$(brew --prefix)/lib:$DYLD_FALLBACK_LIBRARY_PATH\" >> $GITHUB_ENV\n    - name: Install Python dependencies\n      run: |\n        make install_pip PIP_ARGS='.[\"test\"]'\n    - name: Run tests on macOS\n      run: |\n        pytest --cov --cov-report=xml\n    - name: Upload coverage to Codecov\n      if: github.ref == 'refs/heads/master'\n      uses: codecov/codecov-action@v4.5.0\n      with:\n        directory: ./coverage/reports/\n        env_vars: OS, PYTHON\n        files: ./coverage.xml\n        flags: unittests\n        name: codecov-umbrella\n        token: ${{ secrets.CODECOV_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "*.pyc\n*.pyo\n__pycache__/\n*.log\n*.mo\n\n/lib/Solaar.egg-info/\n/lib/solaar.egg-info/\n/lib/solaar/commit\n/build/\n/sdist/\n/dist/\n/deb_dist/\n/MANIFEST\n\n.coverage\n/htmlcov/\n\n/docs/captures/\n/share/logitech_icons/\n/share/locale/\n\n/po/*.po~\n\n/.idea/\n\n.DS_Store\n._*\n\nPipfile\nPipfile.lock\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n- repo: https://github.com/pre-commit/pre-commit-hooks\n  rev: v4.3.0\n  hooks:\n  - id: check-ast\n  - id: check-builtin-literals\n  - id: check-merge-conflict\n  - id: check-yaml\n  - id: check-toml\n  - id: debug-statements\n  - id: end-of-file-fixer\n  - id: trailing-whitespace\n- repo: https://github.com/astral-sh/ruff-pre-commit\n  rev: v0.2.2\n  hooks:\n  - id: ruff\n    name: ruff lint\n    args: [--fix, --exit-non-zero-on-fix]\n  - id: ruff-format\n    name: ruff format\n"
  },
  {
    "path": ".python-version",
    "content": "3.11\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# 1.1.19\n\n* New Georgian translation\n* Remove test that doesn't work in older Pythons\n* Update help messages for CLI commands\n* Allow solaar config  to change LED settings\n* Add python3-devel to install-dnf in Makefile\n* hidconsole can send an HID command non-interactively\n* Add info about new lightspeed receiver\n* Update Swedish and zh_TW translation\n* Fix bug when showing details about direct-connected device\n* Drop testing of Python before 3.13\n* Fix crash in solaar show when showing notification flags. (#3070)\n\n# 1.1.18\n\n* Fix crash when showing notification flags\n\n# 1.1.17\n\n* Add dark icons\n* Permit onboard profiles version 5\n* Update Russian and Polish translations\n* Add onboard profiles warning to sensitivity tooltip\n* Better error messages for solaar profile\n* Remove Solaar name for mice with WPID 4008\n* Prevent lock failure when showing debug messages\n* Replace color picker (#3028)\n* Add setting for HAPTIC feature\n* Add setting to adjust force needed for force-sensing buttons\n* Expand new settings type\n* Add new settings type for structure-backed setting\n* Use PATH instead of hardcoded absolute paths (#3014)\n* Add scroll ratchet force setting\n* Fix debug messages for MouseClick rule\n* Improve debug message for rule evaluation\n* App wrapper and launch agent scripts for MacOS\n* Ignore hidden features\n* Don't pop up window in response to ADC changes\n* Update bug report template\n* Fixed malformed doc file by adding closing tag\n* Fix error in low-level request for device with no recevier\n* Update documentation files\n\n# 1.1.16\n\n* Add new flags for reprogrammable keys feature\n* Correctly handle missing battery feature\n\n# 1.1.15\n\n* Correctly re-raise permissions exception\n* Add several new special keys and tasks\n* Update several translations\n* Center labels and remove buggy entry resizing logic\n* Add shape keys from Key POP Icon\n* Device and Action rule conditions match on codename and name\n* Fix listing hidpp10 devices - bytes vs string concatenation (#2856)\n* Add present flag, unset when internal error occurs, set when notification appears\n* Pause setting up features when error occurs; use ADC message to signal connection and disconnection\n* Fix listing of hidpp10 peripherals\n* Complete DEVICE_FEATURES to DeviceFeature transition for hidpp10 devices\n* Fix NOTIFICATION_FLAG to NotificationFlag transition leftovers\n* Fix github workflow stopping all matrix jobs when one of them fails\n* Fix ubuntu github CI\n* Update index.md\n* Python documentation appears to be broken so don't set it up\n* Improve documentation on onboard profiles\n* Use correct LOD values for extended adjustable dpi\n* Better support RGB Effects - not readable\n* Fix crash when asking for help about config\n* Fix error when updating ChoiceControlBig box\n* Add uninstallation docs\n* Handle unknown power switch locations again\n* Correctly handle selection of [empty] in rule editor\n* Handle `HIDError` in `hidapi.hidapi_impl._match()` (#2804)\n* Give ghost devices a path\n* Guard against typeerror when setting the value of a control box\n* Recover from errors in ping\n* Replace spaces by underscores when looking up features\n* Rewrote string concatenation/format with f strings\n* Fix logo not showing in about dialog box\n* Make typing-extensions dependency mandatory\n* Properly ignore unsupported locale\n* hidapi: skip unsupported devices and handle exception on open\n* Ignore macOS junk files and pipenv config\n* Fix ui desktop notifications test\n* hidpp20: Remove dependency to NamedInts\n* Estimate accurate battery level for some rechargable devices (#2745)\n* Upgrade desktop notifications tests to take notifications availability into account\n* Update tests to run on Python 3.13\n* Remove outdated logger enabled checks\n* Introduce GTK signal types\n* Introduce error types\n* Remove alias for SupportedFeature\n* Refactor process_device_notification\n* Refactor process_receiver_notification\n* Refactor receiver event handling\n* Introduce custom logger\n* Refactor notifications\n* Rename variable to full name notification\n* Test notifications\n* Test extraction of serial and max. devices\n* Refactor extraction of serial and max. devices\n* macOS: Fix int.from_bytes, int.to_bytes for show.py\n* macOS: Remove udev rule warning\n* macOS: Add support for Bluetooth devices\n* Add back and forward mouseclick actions\n* Speedup lookup of known receivers\n* Refactor device filtering\n* Reorder private functions and variable definitions\n* Turn filter_products_of_interest into a public function\n* Improve tests of known receivers\n* Refactor: Remove NamedInts and move enums where used\n* Add docstrings and type hints\n* Enforce rules on RuleComponentUI subclasses\n* Simplify settings UI class\n* Remove diversion alias\n* Refactor: Convert Kind to IntEnum\n* Split up huge settings module\n* Remove Python 2 specific path handling\n* Delete logging temp file on exit\n* Update Swedish translation\n\n# 1.1.14\n\n* Handle fake feature enums in show\n* Fix battery entries in config.yaml\n* Add ratchet setting for smart shift enhanced devices\n* Refactor Gesture into enum\n* Replace ERROR NamedInts by IntEnum (#2645)\n* Refactor hidpp20 to use enum\n* Update Polish, Swedish, Norwegian Nynorsk (nn), and Norwegian Bokmål (nb) translations\n* Use IntEnum for firmware and cidgroup constances\n* Change pairing error values to intenums\n* Fix initialization bug for PackedRangeControl\n* Add tests for feature class, process_notification, and key_is_down\n* Check all bits for extended report rate\n* Add type hints\n* Improve about dialog\n* Reduce dependencies\n* Refactor code\n* Improve testing\n* Allow unknown keys in Key rule conditions\n* Improve documentation for cli actions\n* Cycle sw_id to better guard against duplication of messages\n* Handle error return on root feature\n* Clean up documentation\n* Improve github interactions\n* Add information about Onboard Profiles overriding some settings\n* Add wording to README.md that Solaar is not a device driver\n* Clean up imports\n* Handle unknown device kinds\n* Fix broken links to Solaar logo\n* Use mkdocs for public documentation\n* Clean up setup.py\n* Remove Dead links in the AppStream file\n* Update about.py\n* Remove check on driver\n* Improve base module\n* Remove unnecessary receiver info 'hid_driver'\n* Convert HIDPPNotification to dataclass\n* Be defensive when converting battery status to string\n* Automatically detect packages in /lib\n* Clean up locale code\n* Improve rules documentation\n* Refactor creation of devices\n* Add headings to structure rules.md\n* Unify imports in logitech package\n* Don't ping device when getting name or codename\n* Use dataclasses and enums where useful\n* Introduce Device protocol and type hints\n* Add typing_extensions dependency\n* Move hidpp10 independent functions to module level\n* Fix macOS compatibility and reenable CI tests\n* Unify imports in hidapi package\n* Move screenshots into dedicated folder and add high-level graph of components\n* Update French and Chinese translations\n* Drop support for end-of-life Python 3.7\n\n# 1.1.13\n\n* Update Polish and Russian translations.\n* Fix bug in suspend and resume callback\n* Add choices universe for backlight setting\n* Add simplify diversion.py and add unit tests\n* Get and use current host number for K375sFnSwap because of bug in firmware of MX Keys S\n* Fix bug with logo in about window\n* Don't ping device just to get logging information\n* Optimize write for per-key lighting\n* Add and initialize per-key lighting to a special no-change value\n* Remove some Python 2 compatibility code\n* Update French translation\n* Refactor rule loading for testability\n\n# 1.1.12\n\n* Check for existence of keys file before opening\n* Perform translation for all translatable strings.\n* Add included hid_parser to packages installed\n* Improve label and description for LED zone settings\n* Add message about Onboard Profiles to LED Zone settings\n* Initialize device registers to empty list\n* Use bluez dbus signals to disconnect and connect bluetooth devices\n* Handle a different signal for onboard profiles directory in ROM\n* Introduce small delay in getting pairing information to let receiver settle after pairing\n* Improve testing for settings_templates, settings, hidpp20, and device and fix small bugs found\n* Add extended adjustable DPI setting\n* Improve and extend infrastructure for testing setting_templates\n* Update Greek, Polish, Russian, and Traditional Chinese translations\n* Implement and test per-key lighting\n* Refactor and test pair_window in GUI\n* Handle situation when read of a setting fails in GUI\n* Permit continuing when a read during pushing fails\n* Fix bug in LEDZoneSetting when effect is not implemented\n* Add tests for LEDEffect structures in hidpp20\n* Handle BRIGHTNESS_CONTROL notifications\n* Add settings for BRIGHTNESS_CONTROL and RGB_EFFECTS features\n* Fix small bugs found from testing in settings\n* Use f-strings for more exceptions and log message\n* Tests for setting_templates\n* Simple change in settings to improve testability\n* Use feature_request from the device everywhere in hidpp20\n* Fix bug in backlight 2 durations\n* Replace deprecated code constructs\n* Set up test data and classes to help test HID++ interactions\n* Use pytest to test code for logitech_receiver modules\n* Align init methods for all receiver classes\n* Start refactoring of code base\n* Allow sub-second delays in Later\n* Fix bug in setting configuration cookie due to bad documentation\n* Use ruff for code styling and linting\n* Upgrade string formating to f-string\n* Document battery-icons=solaar option\n* Tell devices to delay device sending first messages until configuration is done\n* Optimize some functions in FeaturesArray\n* Fix bug in creating features array\n* Fix bug in building battery line in show\n* Refactor diversion_rules\n* Fix bug in determining tray icon\n* Fix bug in getting friendly name\n* Move status information to Device and Receiver objects\n* Add tests for get_kind_from_index and base product information\n* Update EX100 documentation\n* Use object attributes instead of dictionary in status objects\n* Create subclasses of receiver for different variants\n* Add requirement for CONFIG_HIDRAW to documentation\n* Add some low-level tests for some hidpp20 functions, profiles, and lighting and some hidpp10 tests\n* Fix app name casing in UI\n* Add missing receiver type for Lightspeed receivers\n* Add new device types\n* Refactor device and receiver instantiation\n* Simplify naming of distribution files\n* Clean up some logging code\n* Remove duplicated code to read register\n* Introduce Hidpp20 and Hidpp10 class\n* Remove unnecessary calls of del\n* Fix bug when reading BACKLIGHT setting from device\n* Replace invalid hidpp10 and hidpp20 usages\n* Use only timer thread to save config.yaml\n* Improve README\n* Copy newer version of hid_parser\n* Reorder code in settings\n* Update installation documentation\n* Add missing license blocks\n* Clean up listener and notifications code\n* Add locks to prevent multiple persisters for device\n* Clean up configuration, device, and receiver code\n* Move battery constants common to HID++ 1.0 and 2.0 to common\n* Move mapping of device kind into hidpp20\n* Move pairing information gathering to receiver\n* update contributors\n* Expand allowable profile numbers\n* Clean up __init__ in logitech_receiver\n* Modify pre-commit args to make ruff change files\n* Fix bug in hidpp20 get host names\n* Use ruff for formatting and linting\n* Fix bug in rule Set action\n* Add notify module to logitech_receiver\n* Implement setting_changed callback and pass in to new devices and receivers\n* Add callback to call when changing a setting\n* Move exceptions, hidpp20 and hidpp10 constants into new modules\n* Streamline status code\n* Upgrade debugging in udev\n* Fix deprecated GitHub actions\n* Extend makefile and tests\n* Improve features array\n* Move ui_async to common.py\n* Improve module imports\n* Add tests of common module\n\n# 1.1.11\n\n* Rename light icons and install them in correct place\n* Setup macOS tests using GitHub action (#2284)\n* Better checking for setting in record_setting\n* Fix invalid func name set logo name\n* Simplify installation of udev rules\n* Add document on implementation\n* Tidy up scrolling appearance in configuration panel\n* Correctly handle profile button with no action\n* Don't unlock setting when changed by external means\n* Refactor code to record change to setting\n* Add GitHub action for tests\n* Introduce tests with pytest\n* Simplify logger instantiation\n* Update label and tooltip for divert-gkeys setting\n* Don't lock setting when an error occurs\n* Catch assertion errors when reading setting values from devices\n* Support LED Zone control feature\n* Dump and load device profiles\n* Select among profiles.\n* Support backlight levels and duration\n* Use \"Report Rate\" instead of \"Polling\" for movement report rate\n* Support extended report rate setting\n* Add stable branch to release.sh (#2236)\n* Fix changelog parsing in release.sh\n* Update installation.md with new udev rules location\n* Downgrade assertion on missing notification flag to warning\n* Write empty file if there are no rules to save\n* Be defensive in device error messages\n* Add descriptions of M650, PRO X 2, G915, MX Anywhere 2S, G305, and MX Keys S\n* Report hidraw node in debugging messages\n* Add names for new Logitech features\n* Update Spanish, French, and Polish translations\n* Defend against lightspeed receivers that contact devices for basic information\n* Remove incorrect feature for M325 mice\n* Add K845 keyboard\n* Add partial support for macOS and minimal support for Windows\n* Correctly enumerate devices on receiver\n* Add wording in documentation about Logitech reusing model numbers\n* Better handling and installation of icons\n* Catch errors when pinging to try to put device online\n* Be more cautious when creating log messages to avoid exceptions\n* Correctly handle NoSuchDevice exception when pinging device\n* Fix test in rules for device equality\n* Add installation instructions for pipx and add not about other GTK system packages\n* Fix bug in NamedInt\n* Add support for MK550\n* Install udev rule files to correct placces\n* Expand expected ping responses\n* Update codename when device status changes\n\n# 1.1.10\n\n* Add information about NixOS flake package\n* Permit bluetooth devices in hidconsole\n* Add descriptor for Logitech MX Revolution Mouse M-RCL 124\n* Improve determination for short and long messages\n* Add descriptor for G500s\n* Fix bug in scan-registers\n* Add single depress and release options for rule mouse click action\n* Add rule condition for hostname\n* Update keysym generation to current list of keysyms\n* Allow device 0 in hidconsole\n* Upgrade messages when no supported device found\n* Documentation update for the gnome extension for better Solaar rule support\n* Remove udev-acl tag from udev rules\n* Add support for process condition in Wayland\n* Update French, Chinese, and German translations\n* Add G733 Headset\n* Restore tools/clean.sh\n* Add Bluetooth Keyboard C714\n* Update several device descriptions\n* Update scan-registers.sh\n* Remove assertion on last byte of ping responses\n* Add symbolic version of solaar icon\n* Fix bug when finding name or codename\n* Update documentation\n* Put version in initial INFO logging message\n\n# 1.1.9\n\n* Add descriptors for G535 wireless gaming headset and wireless keyboard EX110\n* Update Greek translation\n* Fix minor issues in documentation\n* Remove some deprecated GTK code\n* Use zero exit code for kill interrupts\n* Add rule Test condition for battery charging\n* Get wpid for 28Mz devices from udev when enumerating\n* Add Device condition to rules\n* Don't show wireless link or battery information when unknown or not present\n* Add desccriptor for G9x and LX7 mice\n* Fix bug in determining kind of devices for 27Mz receivers\n* Set initial lock status of smooth scrolling features to ignore\n* Fix glitch in configuration file update when changing versions\n* Add more debugging output for rules\n* Clean up pinging code\n* Put initial ping of direct-connected devices inside listener thread\n* Read and check before write of range settings\n* Improve pairing determination\n* Cut off determination of receiver devices when all have been found\n* Remove derived configuration fields when Solaar version changes\n* Allow device descriptors without name and codename\n* Filter and escape technical detail fields\n* Add setting for ADC power managemen\n* Correctly determine whether to ping with a long HID++ message\n* Add description for K470 keyboard from the MK470 combo (#1945)\n* Add setting value for mouse gestures\n* Update German and French translations\n* Remove old clean.sh and monitor.py tools\n* Retry opening device if permissions error encountered\n* Better handlling of IO errors at device creation\n* Add KeyIsDown rule condition to check whether a diverted key is down\n* Clean up device and receiver creation\n\n# 1.1.8\n\n* Add parameter to thumb wheel rule conditions\n* Rename Serbian translation file\n* Update Polish translation\n* Improve handling of wheel notifications\n* Only record changes of scroll wheel ratchet\n* Don't mark setting as absent if there are device errors\n* More robust access to keyword exception fields\n* Add support for config change feature\n* Clean up GTK code\n* Update documentation on mouse gestures and known issues\n* Get commit information from git describe and dpkg-parsechangelog\n* Update pre-commit tools to current versions\n* Update installation instructions\n* Add 8-character commit hash to version information\n* Update solaar.desktop (#1857)\n* Get release in setup.py by reading lib/solaar/__init__.py\n* Remove version number from docs/_config.yml\n* Update solaar.desktop\n* Update es.po\n* Clarify status of C542 receiver\n* Update devices directory\n* Add description of several devices\n* Show name of disconnecting receiver or device in disconnect warning\n* Reduce standard size of rule editor window\n* Remove unnecessary dependency on typing_extensions\n\n# 1.1.7\n\n* Add dependency on typing_extension to setup.py\n* Don't defer saves in CLI and don't require Gtk in CLI\n* Be more permissive in recognizing HID++ report descriptors\n* Update Polish and Croatian translations\n* Switch scroll ratcheting in response to scroll ratchet button notification\n* Add setting to turn scroll ratchet on and off\n* Eliminate visual glitch when updating range setting\n* Make hid-parser an optional dependency\n\n# 1.1.6\n\n* Only update remaining pairings after successful pairing\n* Check for presence of status attribute when resuming\n* Update Polish and Croation translations\n* Don't add non-existant key in raw xy processing\n* Add special keys from MX Mechanical Mini\n* Fix processing of HID++ 1.0 battery reports\n* Use report descriptors to determine suitable devices\n* Handle exceptions when processing configuration file\n* Add Logitech PRO Gaming Keyboard\n* Fix bad entries in divert-keys when found\n* Correctly convert old-style diversions to new style and remove old ones\n* Add optional save argument to write_key_value methods\n* Use device name in configuration entries if device modelId is zeroes\n* Don't show normal DJ messages in debug log\n* Add Later rule action\n* Correctly record battery feature when ADC produces error\n* Print feature call errors in solaar show instead of terminating\n* Use ADC notifications to set device inactive and active\n* Add one to feature count to count ROOT feature\n* Don't check modifiers for KeyPress actions that are not clicks\n* Augment comments on what Solaar cannot do\n* Fix bug in printing closed handle\n* Use only product records to determine which receivers unpair\n* Add conditional delay to get around race with Linux HID++ driver\n\n# 1.1.5\n\n* Add G213 Prodigy Gaming Keyboard\n* Update Turkish, Croation, and zh_CN translations\n* Move old device descriptions to new locations and clean up\n* Increase minimum stopped time between mouse movements\n* Fix bug with non-recognized empty mouse movement\n* Allow config panel to scroll\n* Add descriptions for K360 4004, MX Master 4017, Lightspeed C541, and G915 407D\n* Change security tooltip for unencrypted wireless connections\n* Add Norwegian Bokmal translation\n* Update documentation on continuously running GUI, diverted keys, and changing hosts\n* Solaar config no longer applies settings\n* Add description of rule components to rule editor\n* Ignore first movement for mouse gestures when reprog controls version is 5 or more\n* Add Active rule condition to test whether a device is active\n* Terminate iteration over receiver devices when all have been found\n* Downgrade Set prolem messages from error to warning\n* Log informational messages and above to a temporary file\n* Don't produce warnings when editing rules in rule editor\n* Fix bug that didn't save rules file if there were no rules\n* Allow devices with connection number larger than max_devices\n* Show more registers in solaar probe\n* Show feature versions in solaar show\n* Fix problems with deleting devices on exit\n* Update German translation\n* Update device documentation directory\n* Add descriptors for G502 Proteus Spectrum Optical Mouse and G935 headset\n* Record feature versions\n* Add Serbian translation\n* Fix circular import in rules\n* Keep track of devices and use in rules\n* Update zh_CN and zh_TW translations\n* Convert old-style mouse gestures and sliding dpi settings to new style\n* Allow multiple keys for mouse gestures and sliding dpi\n* Defer saving configuration file for a while to cut down on the number if times it is saved\n* Use correct functions for unified battery and battery voltage features.\n* Add defensive check for missing keys array in mouse gestures setting\n* Better presentation of battery information\n* Add support for ADC MEASUREMENT battery feature\n* Add information on how to find divertable key names in solaar show output\n* Better warnings for feature call errors with reprogrammable key and gesture settings\n* Increase entry size for ChoiceControlBig\n\n# 1.1.4\n\n* Update Croatian translation\n* Handle unanticipated values for persistent remappable action as default\n* Improve system tray interface documentation\n* Remove blank lines from system tray popup\n* Update Polish translation\n* Add depress and release options to KeyPress rule action\n* Only close existing devices for receiver\n* Differentiate debug messages for different setting types\n* Implement packed range setting in config panel\n* Only produce warning for unimplemented display of setting\n* Add sidetone and equalizer settings for headsets\n* Add packed ranges setting\n* Use built-ins for conversions between int and byte string\n* Don't add HI_RES wheel ecodes to evdev device codes\n* Handle null key in persistent remappable actions when device does not respond\n* Consult polling rate feature for polling rate\n* Eliminate extra file handles\n* Close file handles for receiver-connected devices\n* Access to more keys in KeyPress rule action when in other keyboard groups\n* Update Turkish translation\n* Put battery levels in tray menu labels\n* Reduce warnings for inaccessible keys in KeyPress rule action\n* Better determination of keycodes and insert needed shifts in KeyPress actions.\n* Be careful when processing notifications for partly set up devices.\n* Clear out fields for empty persistent remappable action.\n* Fix message generation when device is offline.\n* Fix bug in feature lookup.\n* Add support for G533 Headset and G502 Gaming Mouse\n* Improve device features handling.\n* Keep trying settings that have worked in the past.\n* Store None in persisters for non-persisting settings.\n* Only create configuration entries for off-line devices if they have a serial number.\n\n# 1.1.3\n\n* Update documentation files\n* Lower remove python 3.7 constructs and lower python dependency to 3.6\n* Fix bug in xtest mouse scrolling\n* Allow mouse gesture setting for non-mice, e.g., trackballs\n* Print message when there is another Solaar process running\n* Fix determination of whether to force read before writing boolean setting\n* Add recent diversion features to default list in rules UI\n* Add setting to divert hires scroll wheel\n* Don't use device kind to determine how to handle notifications\n* Update Polish, Russian, and zh_CN translations\n* Remove pggettext so as to not require Python 3.8\n* Remove Python 2 unicode support\n* Store keys in configuration file as int instead of str\n* Use yaml for configuration file instead of json.\n* Remove process-dependent rules from built-in rules.\n* Handle situation where GTK application cannot be set up in CLI.\n* Remove obsolete upower signals.\n* Appinfo/metadata fixes including using correct APP_ID.\n* Fix bugs in solaar config.\n* Add full set of mouse buttons in persistent remappable actions setting.\n* Improve rule behaviour under Wayland and when Xtest or X11 not available.\n* Fix up and document dependencies (evdev, Python, ...).\n\n# 1.1.2\n\n* Update documentation on supported devices and translations\n* Include evdev as a dependency\n* Try to use uinput for fake input if XTest extension not available\n* Add Nano receiver C542 for M190 mice\n* Broaden range of HID++ Bluetooth devices\n* Add setting to divert gestures\n* Rule editor can edit all rule components\n* Configuration via solaar config takes effect in Solaar UI if it is running\n* Add setting to disable Onboard Profiles and decouple from Polling Rate setting\n* Add setting for PERSISTENT_REMAPPABLE_ACTION, common keyboard and mouse cases only\n* Split Test rule condition into Test and TestBytes and support in rule editor\n* Fix bug in speed-change setting\n* Support Backlight3 feature\n* Ensure that settings are pushed in resume\n* Update German, Polish,  and zh_CN translations\n* Determine device number for direct-connected devices from protocol\n* fix bug in add and delete button actions in rule editor\n* dispose of no-op notifications quickly\n* add rule condition for checking device settings\n* use local file for conversion from key names to keysyms\n* get keyboard group and use to get correct keycodes (X11 only)\n* improve how rules work under Wayland\n* add settings for M-Key LEDs and MR-Key LED\n* fix bug in unpacking M and MR key notification\n* add G815 keyboard and MX518 mouse\n* add new special keys for recent keyboards\n* track M and MR keys for use in rules\n* make sure that device is online when searching for devices in solaar show\n* don't check for device kind in dpi sliding setting\n* fix problem with devices that report 0 DPI\n* handle missing divert-setting in action RW for settings\n* add id property (unitId or serial) and don't use ? for unknown serial\n* fix contains for NamedInts and eliminate use of has_element\n* check for xtest and disable modifier checking if not available\n* improve determination of gesture information\n* add Set rules to rule GUI\n* add gesture params to Set rules\n* hide system tray when there are no devices to control\n* add G733 headset, G9 mouse, G502 Hero mouse\n* Use greyscale solaar icon in tray when using symbolic icons\n* Fix bugs in solaar config\n* Use classes for settings to hep with modularity\n* Accept '~' and Toggle for toggling boolean settings in cli and rules\n* handle errors when writing to devices\n* refactor config_panel.py to use classes for widgets\n* add rules action to set Solaar settings\n* decrease amount of logging at each debug level\n* don't stretch toggles in settings\n* use key structure for key remapping setting\n* optimize ReprogrammableKey implementation\n* keep track of settings that are absent from device\n* add G512 keyboard and G402 mouse\n* reformat descriptors.py\n* use feature numbers for reprogrammable key versions\n* don't use new_from_icon_set in menu as it is deprecated\n\n# 1.1.1\n\n* Keep left pane in Solaar main window the same size\n* Fix crash when checking a process condition when X11 not running\n* Add version number to output of solaar show\n* Fix crash when pinging a device with unknown protocol\n* Display battery percentage estimates from battery voltage\n* Add minimal support for Logitech PRO X Wireless Gaming Headset\n* Push settings when device requests software reconfiguration\n* Fix read for key/button diversion setting\n* Add modalias information to Solaar metainfo\n* Don't do on-screen notifications when devices are powered on\n* Add setting to switch crown between smooth and ratchet scrolling\n* Add write_prefix_bytes argument to Boolean validator\n* Update Russian and Spanish translations\n* New shell script tools to help determine capabilities of receivers\n* Add special keys for MX Keys for Business and MX Keys Mini\n* Improve tray menu ordering\n* Add --tray-icon-size option to get around bugs in some tray implementations\n\n# 1.1.0\n\n* Fix bug when adding receiver to tray menu\n* Add Catalan translation.\n* Add toggle command to solaar config to toggle boolean settings\n* Don't select windows with no PID when looking for focus window\n* Catch errors when applying settings so that other settings are not affected\n* Add support for Bolt receivers and devices, including pairing\n* Revise method for creating system tray menu\n* Remove obsolete code (mostly Python 2 compatibility code)\n* Add support for PRO X Wireless Mouse, G914 TKL keyboard\n* Ignore more notifications that come to a device listener\n* Handle more device connection protocols\n* Update usage and rules documentation\n* Change emojis to text in documentation\n* Pare down device documentation so as not to require frequent updates\n* Add information about M500S mouse\n* Reimplement MOUSE GESTURE and DPI SLIDING settings\n* Add setting for DPI CHANGE button to switch sensitivity\n* Use file name instead of icon name for tray to avoid XFCE bug\n* Update documentation on implemented features and mouse gestures\n* Update Polish, Japanese, and Spanish translations\n* Make Quit and About strings more translatable\n\n# 1.0.7\n\n* Don't use time_ns so as not to require Python 3.7\n* Correctly determine setting box in change_click method\n* Handle fake Nano connection notifications\n* Lock on actual handle, not just on handle number\n* Mark Nano receiver C52F as not unpairing\n* Upgrade pairing/unpairing documentation\n* Don't signal status change when battery changes from None to None.\n* Add Japanese translation\n* Use first word of name for code name if no other code name available.\n* Better determination of when to add SW ID.\n* Check for more HID++ feature request failing.\n* Fix bug with new_fn_inversion setting.\n* Use correct device number for directly connected devices\n* Add debug message when candidate device found\n* Update Polish, Taiwanese, and Brazilian Portuguese translations\n* Add MouseProcess a rule condition like Process but for the window under the mouse\n* Add parameters for binary settings to support prefixes\n* Add locks to serialize requests to devices\n* Fix bug when reprog key requests returns None\n* Fix bug for empty process name and class\n* Rules can now trigger on both pressing and releasing a diverted key\n* Upgrade mouse gestures to allow sequences of movements\n* Fix gkeys diversion faked read\n* Add support for Logitech g pro x superlight receiver\n* Convert HID++ 2.0 device kinds to enhanced HID++ 1.0 device kinds\n* Update about window, bug report templates, and supported kernels.\n\n# 1.0.6\n\n* Update sliding DPI to look for suitable keys\n* Add mouse gestures that can trigger rules\n* Complain if receivers do not support connection notification\n* In polling rate setting, only modify onboard profiles when actually writing polling rate\n* Add ability to ignore settings.\n* Use symbols for receiver sub-registers\n* Add support for wired G700\n* Do not set attention icon\n* Replace deprecated GTK stock menu icons\n* Better handling of icons in tray and tray menus\n* Receiver c52e does not unpair\n* Match active WM_CLASS as well as active process name in rules\n* Correctly set icon theme value when regular battery icons are not available\n* Handle exception when device is not available when device is being added\n* Perform initial activation of devices in listener threads\n* Keep track of serial numbers in the configuration file\n* Don't update settings for non-active devices\n* Set the current host name if not stored on the device\n* Add setting for SMART SHIFT ENHANCED feature\n* Don't unnecessarily use long messages for HID++ 1.0 commands\n* Correctly select choices in solaar config and use 1-origin addressing\n* Add quirk for G915 TKL keyboard because its host mode interferes with its Fn keys\n* Show command outputs both saved and on-device settings\n* Update documentation\n* Fix bug in hidconsole\n* Update French translation\n\n# 1.0.5\n\n* Update documentation on devices forgetting settings.\n* Improve help messages\n* Fix bug in finding receiver to pair\n* Solaar config command can set keyed settings.\n* Add setting for polling rate\n* Use long HID++ messages for all 2.0 requests\n* Update German, Italian, and Polish translations\n* Solaar config command no longer selects paired but unconnected devices\n* Show HID++ 1.0 remaining pairings value in solaar show for devices that support it\n* Add option to not use battery icons in system tray.\n* Update Polish and Dutch translation.\n* Add Czech translation.\n* Remove information on SUSE package as it is very old.\n* Turn GKEY notifications into Gn key keypresses that can trigger rules.\n* Push device settings to devices after suspend when device is immediately active.\n* Reduce unnecessary saving of configuration file.\n* Better handling of disconnected devices.\n* Implement GUI to edit rules.\n* Implement rule-base processing of HID++ feature notifications (depends on X11).\n* Add settings for diversion of crown and remappable keys.\n* Access widgets by name instead of by index.\n* Implement UNIFIED_BATTERY feature and use in battery reports.\n* Add a clickable lock icon that determines where each setting can be changed.\n\n# 1.0.4\n\n* Update pt_BR translation\n* Support USB and BT connected devices that are not in descriptors.py\n* Use FRIENDLY NAME for codename if needed and available.\n* Extract manufacturer and product ID from Udev HID information.\n* Add Bluetooth and USB product IDs to device descriptors records.\n* Support Bluetooth-connected devices.\n* Add model ID and unit ID to device identification.\n* Support changing DPI by pressing DPI Switch button and sliding horizontally\n* Add device-specific notification handlers.\n* Add MX Vertical USB information.\n* Udev rule adds seat permissions for all Logitech devices.\n* Support USB-connected devices in GUI.\n* Make probe and config work for USB-connected devices.\n* Improve strings and display for settings.\n* Correctly handle non-unifying connection notifications.\n* Update GUI strings for several settings.\n* Better support for EX100 and devices that connect to it.\n* Partial support for feature GESTURE_2.\n* Simplify interface for settings.\n* Use DJ connection notifications to set device active status\n* Udev rule sets seat write permissions for hidraw nodes for device as well as receivers.\n* Handle USB devices that use HID++ protocol in CLI.\n* Use device hidraw nodes where possible.\n* Handle receivers with serial numbers that don't provide number of pairings.\n* Ignore exceptions when setting locale.\n* Correctly discover settings that share a name.\n* Don't show pop-up notifications at startup.\n* Keep battery voltage updated in GUI.\n* Add Portuguese translation.\n* Update several translations.\n* Add Lightspeed receivers c545 and c541.\n* Reimplement REPROG_CONTROLS data structure.\n\n# 1.0.3\n\n* Clean up documentation files.\n* Update documentation on installation.\n* Update Swedish and French translations.\n* Add Norwegian Nynorsk and Danish translations.\n* Fix bug handling DJ pairing notifications.\n* Add Norwegian Bokmål translation.\n* Remove deprecated solaar-cli application.\n* Don't install udev or autostart files from python (or pip).\n* Solaar needs Python 3.6+ and probably needs kernel 5.2+\n* Handle exceptions on dynamic settings when device is not connected.\n* Fix infinite loop on some low-level write errors\n* Add support for EX100 keyboard/mouse and receiver (046d:c517)\n* Add two settings for THUMB_WHEEL feature - inversion and reporting via HID++\n* Update German translation\n* Use REPORT RATE feature when available to determine polling rate.\n* Improve config command speed when not printing all settings\n* Improve config command handling and checking of arguments\n* Add setting for CHANGE_HOST feature\n* Add argument to settings for values that are not to persist\n* Add argument to settings to not wait for reply when writing a value to device\n* Add argument to not wait for reply from request to device\n* Add settings for MULTIPLATFORM and DUALPLATFORM features\n* Remove Logitech documents from documentation directory\n* Change config command to not read all settings when only printing or showing one\n* Display hosts info in 'solaar show' if device supports it\n* Remove non-working smooth-scroll from M510 v1\n* Add yapf and flake8 code style checks\n* Fix feature k375s Fn inversion\n* Update controls (keys and buttons) and tasks (actions)\n* Improved way to specify feature settings.\n* Don't abort on device notifications with unexpected device numbers, just warn.\n* Keep track of non-features so as not to ask device multiple times.\n* Implement KEYBOARD DISABLE KEYS feature.\n* Don't create notifications for DJ device activity reports.\n* Update a few special keys and actions.\n* Add keyed choice settings in configuration panel.\n* Support remappable keys from reprogrammable keys v4 feature.\n* Add setting class for keyed choice.\n* Only check for features once per device.\n* Use settings interface to show feature values in `solaar show` if no special code for feature.\n* Remove maximum window size.\n* Process battery voltage notifications.\n* Display battery voltage information in main window if regular battery information not available.\n* Show next battery level where available.\n* Update list of implemented features and provide information on how to implement features.\n* Add c53d as a Lightspeed receiver.\n\n# 1.0.2\n\n* Add usage document\n* Don't produce error dialog for inaccessible receivers with access control lists.\n* Add option --battery-icons=symbolic to use symbolic icons if available.\n* Update French translation\n* Update installation documentation\n* Remove packaging directory tree as it is not maintained\n* Pip installs udev rule and solaar autostart when doing install without --user flag\n* Use Solaar icon instead of a missing battery icon\n* Use only standard icons for battery levels.  Symbolic icons do not change to white in dark themes because of problems external to Solaar.\n* Better reporting of battery levels when charging for some devices.\n* Add information on K600 TV, M350 WIPD 4080, and MX Keys\n* Remove assertion requiring receivers to still be in window when they are updated.\n* Augment long description of Solaar showing up in repositories.\n* Update installation directions.\n* Install udev rule as well as autostart file when doing system install.\n* Add support for Ayatana AppIndicator.\n* Use setuptools icon directory on system installs when not using pip.\n* Add receiver C517 and several older devices.\n* Improved translations for polish.\n* Bypass bug in appindicator when solaar is file in current directory.\n* Don't check that device kind matches feature kind.\n* Better determination of icons for battery levels.\n* Use Ayatana AppIndicator if available.\n* Improve error reporting when required system packages are not install.\n* Better tooltip description\n* Add release script to help when creating releases\n* Look up tray icon filenames to get around a bug in libappindicator.\n* Make the default behavior be to show the main window at startup.\n* Support c537 nano receiver\n* Add logind signals for suspend/resume.\n* Remove solaar-gnome3 package\n* Ignore features for devices that don't follow feature specification\n* Add probe command to command-line interface to dump receiver registers\n* Don't terminate on malformed or unknown messages\n* Create fewer internal notifications for messages from devices\n* Add a button to the main window to terminate (quit) Solaar\n* Set up nano receivers as receivers with no unpairing and with re-pairing\n* Set up c534 as receiver with max 2 pairings, no unpairing, re-pairing\n* Better support receivers that do not unpair or when pairing replace existing pairings\n* Add information about receiver pairing to receiver data structure\n* Better support devices that only allow a limited number of total re-pairings\n* Add --window option to control main window visibility and tray usage\n* Ignore receiver if USB id is not retrieved\n* Fix bug with double deleting when devices are disconnected\n* Determine some receiver information from data structure for USB ids\n* Treat battery level of 0 as unknown\n* Fix bug on devices with no serial number\n* Drop support for python2, and use python3 throughout\n* Fix bug in remembering features discovered from device reports\n* Show icons in main window device list\n* Count offline devices when determining whether pairing is possible\n* Update French, Dutch, German, and Croatian translations\n* Better icons for battery levels\n* Support DPI, Backlight 2, Battery Voltage features\n* Support M585, M590, M330, MX Master 2s and 3, new M310, new K800, craft keyboard\n* Documentation improvements\n* Clean up directory structure and remove unused files\n\n# 1.0.1\n\n* Updated the repo url.\n* Fixed typo which was crashing the application.\n* Improved the HID write routine which was causing issues on some devices.\n* Fix non-unifying receivers in Linux 5.2.\n* Add new Lightspeed receiver (used in the G305)\n\n# 1.0.0\n\n* Too many to track...\n\n# 0.9.3\n\n* Merged solaar-cli functionality into main solaar.\n* Scrolling over the systray icon switches between multiple peripherals.\n* Swedish translation courtesy of Daniel Zippert and Emelie Snecker\n* French translation courtesy of Papoteur, David Geiger and Damien Lallement.\n* Fixed some untranslated strings.\n\n# 0.9.2\n\n* Added support for hand detection on the K800.\n* Added support for V550 and V450 Nano.\n* Fixed side-scrolling with the M705 Marathon.\n* Fixed identification of the T650 Touchpad.\n* Added internationalization support and romanian translation.\n* Polish translation courtesy of Adrian Piotrowicz.\n\n# 0.9.1\n\n* When devices report a battery alert, only show the alert once.\n* Make sure devices in the window tree are sorted by registration index.\n* Added an autostart .desktop file.\n* Replaced single-instance code with GtkApplication.\n* Fixed identification of the M505 mouse.\n* Fixed an occasional windowing layout bug with the C52F Nano Receiver.\n\n# 0.9.0\n\n* New single-window UI.\n* Performance MX leds show the current battery charge.\n* Support the VX Nano mouse.\n* Faster and more accurate detection of devices.\n* If upower is accessible through DBus, handle suspend/resume.\n* Replaced Solaar icons with SVGs.\n* Running solaar-cli in parallel with solaar is now less likely to cause issues.\n* Bugfixes to saving and applying device settings.\n* Properly handle ^C when running in console.\n\n# 0.8.9\n\n* Improved support for gnome-shell/Unity.\n* Persist devices settings between runs.\n* Fixed reading of MK700 keyboard battery status.\n* Use battery icons from the current theme instead of custom ones.\n* Debian/Ubuntu packages now depend on an icon theme, to make sure\n  no missing icons appear in the application window.\n* Fixed missing icons under Kubuntu.\n* Many more bug-fixes and reliability improvements.\n\n# 0.8.8\n\n* Partial support for some Nano receivers.\n* Improved support for some devices: M510, K800, Performance MX.\n* Improved battery support for some HID++ 1.0 devices.\n* Properly handle device loss on computer sleep/wake.\n* Better handling of receiver adding and removal at runtime.\n* Removed a few more unhelpful notifications.\n* Incipient support for multiple connected receivers.\n* More Python 3 fixes.\n\n# 0.8.7\n\n* Don't show the \"device disconnected\" notification, it can be annoying and\n  not very useful.\n* More robust detection of systray icon visibility.\n\n# 0.8.6\n\n* Ensure the Gtk application is single-instance.\n* Fix identifying available dpi values.\n* Fixed locating application icons when installed in a custom prefix.\n* Fixed some icon names for the oxygen theme.\n* Python 3 fixes.\n"
  },
  {
    "path": "COPYRIGHT",
    "content": "Copyright 2012, 2013\nDaniel Pavel <daniel.pavel@gmail.com>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, version 2.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n                            NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include COPYRIGHT LICENSE.txt README.md CHANGELOG.md lib/solaar/version lib/solaar/commit\nrecursive-include rules.d *\nrecursive-include share/locale *\n"
  },
  {
    "path": "Makefile",
    "content": "UDEV_RULE_FILE = 42-logitech-unify-permissions.rules\nUDEV_RULES_SOURCE := rules.d/$(UDEV_RULE_FILE)\nUDEV_RULES_SOURCE_UINPUT := rules.d-uinput/$(UDEV_RULE_FILE)\nUDEV_RULES_DEST := /etc/udev/rules.d/\n\nPIP_ARGS ?= .\n\n.PHONY: install_ubuntu install_macos\n.PHONY: install_apt install_brew install_pip\n.PHONY: install_udev install_udev_uinput reload_udev uninstall_udev\n.PHONY: format lint test\n\ninstall_ubuntu: install_apt install_udev_uinput install_pip\n\ninstall_macos: install_brew install_pip\n\ninstall_apt:\n\t@echo \"Installing Solaar dependencies via apt\"\n\tsudo apt update\n\tsudo apt install libdbus-1-dev libglib2.0-dev libgtk-3-dev libgirepository1.0-dev\n\ninstall_apt_python3.13:\n\t@echo \"Installing Solaar dependencies via apt\"\n\tsudo apt update\n\tsudo apt install libdbus-1-dev libglib2.0-dev libgtk-3-dev libgirepository-2.0-dev gobject-introspection\n\ninstall_dnf:\n\t@echo \"Installing Solaar dependencies via dnf\"\n\tsudo dnf install gtk3 python3-devel python3-gobject python3-dbus python3-pyudev python3-psutil python3-xlib python3-yaml\n\ninstall_brew:\n\t@echo \"Installing Solaar dependencies via brew\"\n\tbrew update\n\tbrew install hidapi gtk+3 pygobject3 gobject-introspection\n\ninstall_pip:\n\t@echo \"Installing Solaar via pip\"\n\tpython -m pip install --upgrade pip\n\tpip install $(PIP_ARGS)\n\ninstall_pipx:\n\t@echo \"Installing Solaar via pipx\"\n\tpipx install --system-site-packages $(PIP_ARGS)\n\ninstall_udev:\n\t@echo \"Copying Solaar udev rule to $(UDEV_RULES_DEST)\"\n\tsudo cp $(UDEV_RULES_SOURCE) $(UDEV_RULES_DEST)\n\tmake reload_udev\n\ninstall_udev_uinput:\n\t@echo \"Copying Solaar udev rule (uinput) to $(UDEV_RULES_DEST)\"\n\tsudo cp $(UDEV_RULES_SOURCE_UINPUT) $(UDEV_RULES_DEST)\n\tmake reload_udev\n\nreload_udev:\n\t@echo \"Reloading udev rules\"\n\tsudo udevadm control --reload-rules\n\nuninstall_udev:\n\t@echo \"Removing Solaar udev rules from $(UDEV_RULES_DEST)\"\n\tsudo rm -f $(UDEV_RULES_DEST)/$(UDEV_RULE_FILE)\n\tmake reload_udev\n\nformat:\n\t@echo \"Formatting Solaar code\"\n\truff format .\n\nlint:\n\t@echo \"Linting Solaar code\"\n\truff check . --fix\n\ntest:\n\t@echo \"Running Solaar tests\"\n\tpytest --cov --cov-report=xml\n"
  },
  {
    "path": "README.md",
    "content": "# <img src=\"https://pwr-solaar.github.io/Solaar/img/solaar.svg\" width=\"60px\"/> Solaar\n\nSolaar is a Linux manager for many Logitech keyboards, mice, and other devices\nthat connect wirelessly to a Unifying, Bolt, Lightspeed or Nano receiver\nas well as many Logitech devices that connect via a USB cable or Bluetooth.\nSolaar is not a device driver and responds only to special messages from devices\nthat are otherwise ignored by the Linux input system.\n\n<a href=\"https://pwr-solaar.github.io/Solaar/index\">More Information</a> -\n<a href=\"https://pwr-solaar.github.io/Solaar/usage\">Usage</a> -\n<a href=\"https://pwr-solaar.github.io/Solaar/capabilities\">Capabilities</a> -\n<a href=\"https://pwr-solaar.github.io/Solaar/rules\">Rules</a> -\n<a href=\"https://pwr-solaar.github.io/Solaar/installation\">Manual Installation</a> -\n<a href=\"https://pwr-solaar.github.io/Solaar/issues\">Known Issues</a>\n\n\n[![codecov](https://codecov.io/gh/pwr-Solaar/Solaar/graph/badge.svg?token=D7YWFEWID6)](https://codecov.io/gh/pwr-Solaar/Solaar)\n[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2+-blue.svg)](../LICENSE.txt)\n\n<p align=\"center\">\n<img src=\"https://pwr-solaar.github.io/Solaar/screenshots/Solaar-main-window-multiple.png\" width=\"54%\"/>\n  &#160;\n<img src=\"https://pwr-solaar.github.io/Solaar/screenshots/Solaar-main-window-receiver.png\" width=\"43%\"/>\n</p>\n\n<p align=\"center\">\n<img src=\"https://pwr-solaar.github.io/Solaar/screenshots/Solaar-main-window-back-divert.png\" width=\"49%\"/>\n  &#160;\n<img src=\"https://pwr-solaar.github.io/Solaar/screenshots/Solaar-rule-editor.png\" width=\"48%\"/>\n</p>\n\nSolaar supports:\n- pairing/unpairing of devices with receivers\n- configuring device settings\n- custom button configuration\n- running rules in response to special messages from devices\n\nFor more information see\n    <a href=\"https://pwr-solaar.github.io/Solaar/index\">the main Solaar documentation page.</a> -\n\n\n## Installation Packages\n\nUp-to-date prebuilt packages are available for some Linux distros\n(e.g., Fedora) in their standard repositories.\nIf a recent version of Solaar is not\navailable from the standard repositories for your distribution, you can try\none of these packages:\n\n- Arch solaar package in the [extra repository][arch]\n- Ubuntu/Kubuntu package in [Solaar stable ppa][ppa stable]\n- NixOS Flake package in [Svenum/Solaar-Flake][nix flake]\n\nSolaar is available from some other repositories\nbut may be several versions behind the current version:\n\n- a [Debian package][debian], courtesy of Stephen Kitt\n- a Ubuntu package is available from [universe repository][ubuntu universe repository]\n- a [Gentoo package][gentoo], courtesy of Carlos Silva and Tim Harder\n- a [Mageia package][mageia], courtesy of David Geiger\n\n[ppa stable]: https://launchpad.net/~solaar-unifying/+archive/ubuntu/stable\n[arch]: https://www.archlinux.org/packages/extra/any/solaar/\n[gentoo]: https://packages.gentoo.org/packages/app-misc/solaar\n[mageia]: http://mageia.madb.org/package/show/release/cauldron/application/0/name/solaar\n[ubuntu universe repository]: http://packages.ubuntu.com/search?keywords=solaar&searchon=names&suite=all&section=all\n[nix flake]: https://github.com/Svenum/Solaar-Flake\n[debian]: https://packages.debian.org/search?keywords=solaar&searchon=names&suite=all&section=all\n"
  },
  {
    "path": "RELEASE.md",
    "content": "# Solaar releases\n\n## Please read before making a release\n\nWe support two type of releases: normal releases (ex. `1.0.0`) and release\ncandidates (ex. `1.0.0rc1`). Release candidates must have a `rcX` suffix.\n\nRelease routine:\n\n- Update version in `lib/solaar/version`\n- Add release changes to `CHANGELOG.md`\n- Add release information to `share/solaar/io.github.pwr_solaar.solaar.metainfo.xml`\n- Create a commit that starts with `release VERSION`\n- Push commit to Solaar repository\n- Invoke `./release.sh`\n  - Git tags are signed so you must have GPG set up\n  - You are required to have a github token with `public_repo` access\n    in `~/.github-token`\n"
  },
  {
    "path": "RHEL.md",
    "content": "# Solaar installation guide for RHEL, Rocky, AlmaLinux, and CentOS Stream\n\nThis guide covers manual installation and an automated install example for\nRHEL-family systems using `dnf`.\n\n## Supported distributions\n\n- Red Hat Enterprise Linux (RHEL)\n- Rocky Linux\n- AlmaLinux\n- Oracle Linux\n- CentOS Stream\n\nThe commands assume a minimal CLI system with `sudo` access.\n\n## 1) Install dependencies\n\n```bash\nsudo dnf makecache --refresh\nsudo dnf install -y \\\n  git \\\n  gtk3 \\\n  python3 \\\n  python3-devel \\\n  python3-dbus \\\n  python3-gobject \\\n  python3-pip \\\n  python3-psutil \\\n  python3-pyudev \\\n  python3-setuptools \\\n  python3-xlib \\\n  python3-yaml\n```\n\nOptional troubleshooting helpers:\n\n```bash\nsudo dnf install -y \\\n  evemu \\\n  libinput \\\n  usbutils\n```\n\n## 2) Clone Solaar\n\n```bash\ngit clone https://github.com/pwr-Solaar/Solaar.git\ncd Solaar\n```\n\n## 3) Install Solaar\n\nInstall for the current user:\n\n```bash\npython3 -m pip install --user .\n```\n\nOr install system-wide:\n\n```bash\nsudo python3 -m pip install .\n```\n\n## 4) Install udev rules\n\nInstall the recommended `uinput` rule:\n\n```bash\nsudo make install_udev_uinput\n```\n\nVerify rule installation:\n\n```bash\nls -l /etc/udev/rules.d/42-logitech-unify-permissions.rules\n```\n\nRollback udev rule installation:\n\n```bash\nsudo make uninstall_udev\n```\n\n## 5) Run Solaar\n\n```bash\nsolaar\n```\n\nor:\n\n```bash\npython3 -m solaar\n```\n\n## 6) Automated install options\n\nUse the guided installer in this repository:\n\n```bash\n./tools/install-rhel.sh\n```\n\nMinimal non-interactive example script:\n\n```bash\ncat > install-rhel-solaar.sh <<'SCRIPT'\n#!/usr/bin/env bash\nset -euo pipefail\n\nif [[ \"${EUID}\" -eq 0 ]]; then\n  echo \"Run as a regular user with sudo access, not as root.\"\n  exit 1\nfi\n\nsudo dnf makecache --refresh\nsudo dnf install -y \\\n  git \\\n  gtk3 \\\n  python3 \\\n  python3-devel \\\n  python3-dbus \\\n  python3-gobject \\\n  python3-pip \\\n  python3-psutil \\\n  python3-pyudev \\\n  python3-setuptools \\\n  python3-xlib \\\n  python3-yaml\n\nif [[ ! -d Solaar/.git ]]; then\n  git clone https://github.com/pwr-Solaar/Solaar.git\nfi\n\ncd Solaar\npython3 -m pip install --user .\nsudo make install_udev_uinput\n~/.local/bin/solaar --version\nSCRIPT\n\nchmod +x install-rhel-solaar.sh\n./install-rhel-solaar.sh\n```\n\n## 7) Verification\n\n```bash\ncommand -v solaar\nsolaar --version\npython3 -m pip show solaar\n```\n\nIf installed with `--user`, ensure `~/.local/bin` is on your `PATH`:\n\n```bash\necho \"$PATH\" | tr ':' '\\n' | grep -Fx \"$HOME/.local/bin\" >/dev/null || \\\n  echo 'Add ~/.local/bin to PATH'\n```\n\n## 8) Troubleshooting\n\nReceiver not detected:\n\n```bash\nlsusb | grep -Ei 'logitech|046d'\nsudo udevadm trigger\n```\n\nCheck access to hidraw devices:\n\n```bash\nls -l /dev/hidraw*\ngetfacl /dev/hidraw* 2>/dev/null | sed -n '1,80p'\n```\n"
  },
  {
    "path": "Release_Notes.md",
    "content": "# Notes on Major Changes in Releases\n\n## Version 1.1.18\n\n* Solaar is only guaranteed to work in Python 3.13 or later.\n\n## Version 1.1.17\n\n* Several new features have been added related to the MX Master 4\n  * The scroll ratchet force can be adjusted\n  * The force required to click the button under your thumb can be adjusted\n  * The haptic force can be adjusted\n  * Haptic feeback can be triggered by commands like `solaar config 'mx master 4' haptic-play 'HAPPY ALER'`\n\n## Version 1.1.16\n\n* Two bugs that were affecting users in 1.1.15 are fixed.\n\n## Version 1.1.15\n\n* Some key names have been changed to match Logitech names.  Rules that use removed names will no longer work and will end up with a key of 0.\n* Device and Action rule conditions match on device codename and name\n* Solaar supports configuration of Bluetooth devices on macOS.\n\n## Version 1.1.13\n\n* Solaar will drop support for Python 3.7 immediately after version 1.1.13.\n\n* Version 1.1.12 does not push settings to many devices after a resume resulting in the device reverting to its default behaviour.  This is fixed in 1.1.13.\n\n## Version 1.1.12\n\n* Solaar now processes DBus disconnection and connection messages from Bluez and re-initializes devices when they reconnect, to handle to a change introduced in Bluez 5.73. The HID++ driver does not re-initialize devices, which causes problems with smooth scrolling. Until the issue is resolved having Scroll Wheel Resolution set to true (and not ignored) may be helpful.\n\n* The credits for translations have not been kept up to date.  Translators who are not listed can update docs/i18n.ml and lib/solaar/ui/about.py.\n\n* Solaar now has settings for features BRIGHTNESS_CONTROL, RGB_EFFECTS, and PER_KEY_LIGHTING features.  The names of keys in the Per-key Lighting setting are for the standard US keyboard.  Users who wish to modify these names should look at the section Keyboard Key Names and Locations in `https://pwr-solaar.github.io/Solaar/capabilities`\n\n* A unit test test suite is being constructed using pytest.\n\n* The Solaar code for communicating with receivers and devices has been significantly modified to improve testability and organization.  Errors may have been introduced for uncommon hardware.\n\n* The Later rule action uses precision timing for delays of less than one second.\n\n* Solaar now indentifies supported devices by whether they support the HID protocols that Solaar needs.  If a device does not show up at all when running Solaar, it almost certainly cannot be supported by Solaar.\n\n## Version 1.1.11\n\n* Solaar can dump device profiles in YAMLfor devices that support profiles and load profiles back from an edited file.  See [the capabilities page](https://pwr-solaar.github.io/Solaar/capabilities) for more information.\n\n* Solaar has settings for each LED Zone that a device supports under feature Color LED Effects.\n\n* Solaar has settings for extended report rate, backlight levels, durations, and profile selection.\n\n* Solaar now partly works in MacOS.  Please open new issues for problems.  Solaar may work in Windows.   Please open new issues for problems.  See https://github.com/pwr-Solaar/Solaar/pull/1971 for more information.  Fixing problems in MacOS or Windows may take considerable time.\n\n* Solaar works better when the Python package hid-parser is available.   Distriubtions should try have this package installed.\n\n## Version 1.1.10\n\n* The mouse click rule action can now just simulate depressing or releasing the button.\n\n* There is a new rule condition to check the hostname.\n\n## Version 1.1.9\n\n* Solaar now exits with at 0 exit code when killed.\n\n* Two Solaar settings can interfere with the implementation of smooth scrolling in modern Linux HID++ drivers.  These settings are initially set to ignore so that this interference does not happen.\n\n* The Device rule condition checks for the device that produced a notification.\n\n* The KeyIsDown rule condition checks whether a *diverted* rule key is down.\n\n## Version 1.1.8\n\n* The thumb wheel rule conditions take an optional parameter that checks for total signed thumb wheel movement.\n\n## Version 1.1.7\n\n* Solaar responds to scroll wheel ratchet notifications by changing its scroll wheel ratcheting.\n\n* Solaar processing of report descriptors is optional, depending on whether the package hid-parser is available.\n\n## Version 1.1.6\n\n* Solaar requires Python version 3.7.\n\n* Solaar uses report descriptors to recognize unknown devices that use HID++.\n\n* The Later rule action takes an integer delay in seconds and one or more rule components.  The action immediately completes while also scheduling the rule components for later exection.\n\n## Version 1.1.5\n\n* The Active rule condition takes the serial number or unitID of a device and checks whether the device is active.  A device is active if it is connected (via a receiver, USB or Bluetooth), not turned off, and not in a power-saving state.  This condition can be used to check whether changing a setting on the device will have any effect, as devices respond to messages only when active.\n\n* Solaar logs warnings and errors to a file in the user's temporary file directory.  This file is deleted when Solaar exists normally.  If Solaar is run with `-dd` or `-ddd` informational messages are also logged in the file.\n\n* If the first element of a Mouse Gesture rule condition is a key or button name then that name must be the same as the name of the key or button that initiated the mouse gesture.\n\n* The Sliding DPI and Mouse Gestures are now set up using the Key/Button Diversion setting.   Changing a key or button to Sliding DPI makes it initiate the sliding DPI changing.  Changing a key or button to Mouse Gestures makes it initiate a mouse gesture.  There can be multiple keys or buttons for sliding DPI and multiple keys or buttons for mouse gestures.\n\n* Solaar waits a few seconds to save settings changes to its configuration file.  If you interrupt Solaar soon after changing a setting the change might not be saved.\n\n\n## Version 1.1.4\n\n* There are settings for sidetone and equalizer gains for headsets.\n\n* The KeyPress action can now either deppress, release, or click (default) keys.\n\n* The KeyPress action now inserts shift and level 3 keypresses if simulating a key symbol requires one or both of them.  So producing a \"B\" no longer requires adding a shift keysymbol.\n\n## Version 1.1.3\n\n* Solaar uses yaml for configuration files, converting the json configuration file to yaml if necessary.\n\n* Solaar rules work better under Wayland but still cannot access the current process nor the current keyboard modifiers.\n\n* Solaar uses uinput for simulating input in Wayland.  See https://pwr-solaar.github.io/Solaar/rules for instructions on setting up uinput correctly.\n\n## Version 1.1.2\n\n* Solaar now depends on Python evdev.  It can be installed if needed via `pip install --user evdev` or, in most distributions, by installing the python3-evdev package.\n\n* Solaar rules partly work under Wayland.  There is no access to the current process in Wayland.  Simulated input uses uinput if XTest extension not available, requiring read and write permissions on /dev/uinput.\n\n* There is a setting to divert gestures so that they can trigger rules.\n\n* There is a setting to disable Onboard Profiles, which can interfere with the Polling Rate and M-Key LEDs settings.  The Polling Rate setting no longer disables onboard profiles.\n\n* There is a setting for the Persistent Remappable Keys feature.\n\n* There is a new rule condition that tests device settings.\n\n* There are new settings to set M-Key LEDs and MR-Key LED.\n\n* There is a new kind of Solaar rule action to change settings for devices.\n\n## Version 1.1.1\n\n* There is a new setting to switch keyboard crowns between smooth and ratchet scrolling.\n\n## Version 1.1.0\n\n* Solaar now supports Bolt receivers and devices that connect to them, including authentication of devices when pairing.\n\n* A setting has been added for the DPI CHANGE button to switch movement sensitivity.\n\n## Version 1.0.7\n\n* Solaar rules can now trigger on both pressing and releasing a diverted key.\n\n* The new rule condition MouseProcess is like the Process condition except for the process of the window under the mouse.\n\n* Mouse gestures have been upgraded.  A mouse gesture is now a sequence of movements separated by no movement periods while the mouse gesture button is held down.  The MouseGesture rule condition matches mouse gesture sequences.  The old mouse-up, etc., tests are converted to MouseGesture conditions.\n\n## Version 1.0.6\n\n* The sliding DPI setting now looks for suitable keys to use to trigger its effects.\n\n* If a mouse has a suitable button it can generate mouse gestures, which trigger rule processing.  Mouse gestures need to be turned on and the button diverted to produce mouse gestures.\n\n* Settings can now be ignored by clicking on the icon at the right-hand edge of a setting until the dialog error icon (usually a red icon) appears.   Solaar will not try to restore the value for an ignored setting.\n\n* Icon handling in the tray and the tray menu has been updated to work better with some system tray implementations.\n\n* The process rule condition also matches against the current X11 WM_CLASS.\n\n* The SMART SHIFT ENHANCED feature is supported.\n\n## Version 1.0.5\n\n* Solaar has rules that can perform actions such as pressing keys or scrolling when certain HID++ feature notifications happen.  Users can change these rules either by editing ~/.config/solaar/rules.yaml or via a GUI.  Rules depend on X11 and so are only available under X11.  This is an experimental feature for Solaar and may undergo changes in the future.\n\n* Each setting has a clickable lock icon that determines whether the setting can be changed.\n\n## Version 1.0.4\n\n* Devices that connect directly via Bluetooth or USB are now supported.  These devices show up in the GUI as separate lines, not under a receiver.  A device that is directly connected and also paired to a receiver will show up twice, but the entry under the receiver will not be active.  With this change identifying devices becomes more difficult so occasionally check your Solaar configuration file (at ~/.config/solaar/config.json) to see that there is only one entry for each of your devices.\n\n* There are new settings for gestures, thumb wheels,  adjusting the wheel ratchet behavior, and changing DPI using a DPI Switch button.\n\n* Solaar's Udev rule now adds seat permissions for all Logitech devices.  Users who install Solaar themselves will have to install the new Udev rule and activate the rule.  One way to do this is to restart the user's computer.\n\n## Version 1.0.3\n\n* The separate deprecated solaar-cli command has been removed.\n\n* Devices can be switched between hosts using the Change Host setting.  The device will try to connect to the other host.  Some devices will detect that there is no active host on the other connections and reconnect back.\n\n## Version 1.0.2\n\n* The separate unneeded solaar-gnome3 command has been removed.  The packaging directories have been removed.\n\n* Non-unifying receivers are modelled better.  Many of them cannot unpair but instead new pairings replace existing pairings.\n\n* Battery icon selection has been simplified.\n"
  },
  {
    "path": "bin/solaar",
    "content": "#!/usr/bin/env python3\n# -*- python-mode -*-\n# -*- coding: UTF-8 -*-\n\n## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n\ndef init_paths():\n    \"\"\"Make the app work in the source tree.\"\"\"\n    import os.path\n    import sys\n\n    root = os.path.join(os.path.realpath(sys.path[0]), \"..\")\n    prefix = os.path.normpath(root)\n    src_lib = os.path.join(prefix, \"lib\")\n    share_lib = os.path.join(prefix, \"share\", \"solaar\", \"lib\")\n    for location in src_lib, share_lib:\n        init_py = os.path.join(location, \"solaar\", \"__init__.py\")\n        if os.path.exists(init_py):\n            sys.path[0] = location\n            break\n\n\nif __name__ == \"__main__\":\n    init_paths()\n    import solaar.gtk\n\n    solaar.gtk.main()\n"
  },
  {
    "path": "docs/.gitignore",
    "content": "# ignore documentation-specific files\n\n.jekyll-metadata\nGemfile\nGemfile.lock\n_site/\n"
  },
  {
    "path": "docs/LICENSE.txt",
    "content": "GNU GENERAL PUBLIC LICENSE\n\nVersion 2, June 1991\n\nCopyright (C) 1989, 1991 Free Software Foundation, Inc.\n<https://fsf.org/>\nEveryone is permitted to copy and distribute verbatim copies\nof this license document, but changing it is not allowed.\n\nPreamble\n\nThe licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.\n\nWhen we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.\n\nTo protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.\n\nFor example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.\n\nWe protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.\n\nAlso, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.\n\nFinally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.\n\nThe precise terms and conditions for copying, distribution and modification follow.\nTERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The \"Program\", below, refers to any such program or work, and a \"work based on the Program\" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term \"modification\".) Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.\n\n1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.\n\n2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.\n    b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.\n    c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.\n\n3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\n    b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\n    c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.\n\nIf distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.\n\n4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.\n\n5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.\n\n6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.\n\n7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.\n\nThis section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.\n\n8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.\n\n9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and \"any later version\", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.\n\n10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.\n\nNO WARRANTY\n\n11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\nEND OF TERMS AND CONDITIONS\nHow to Apply These Terms to Your New Programs\n\nIf you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.\n\nTo do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the \"copyright\" line and a pointer to where the full notice is found.\n\none line to give the program's name and an idea of what it does.\nCopyright (C) yyyy  name of author\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, see\n<https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this when it starts in an interactive mode:\n\nGnomovision version 69, Copyright (C) year name of author\nGnomovision comes with ABSOLUTELY NO WARRANTY; for details\ntype `show w'.  This is free software, and you are welcome\nto redistribute it under certain conditions; type `show c'\nfor details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your school, if any, to sign a \"copyright disclaimer\" for the program, if necessary. Here is a sample; alter the names:\n\nYoyodyne, Inc., hereby disclaims all copyright\ninterest in the program `Gnomovision'\n(which makes passes at compilers) written\nby James Hacker.\n\nsignature of Moe Ghoul, 1 April 1989\nMoe Ghoul, President of Vice\n\nThis General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License.\n"
  },
  {
    "path": "docs/README.text",
    "content": "# Documentation Readme\n\nThis project's documentation is hosted using GitHub pages, which serves static pages using Jekyll.\n[Please refer to the official documentation for instructions for how to build the site locally.](https://help.github.com/articles/setting-up-your-github-pages-site-locally-with-jekyll/)\n"
  },
  {
    "path": "docs/capabilities.md",
    "content": "---\ntitle: Solaar Capabilities\nlayout: page\n---\n\n# Solaar Capabilities\n\n[**Solaar**][solaar] reports on and controls [Logitech][logitech] devices\n(keyboards, mice, and trackballs) that connect to your computer via a\nLogitech USB receiver (a very small piece of hardware that plugs into one of\nyour USB ports).\nSolaar is designed to detect all connected devices,\nand at the very least display some basic information about them.\nAt this moment, all [Unifying][unifying] receivers are supported (e.g., devices\nwith USB ID `046d:c52b` or `046d:c532`) as are several Lightspeed Receivers\nand many Nano receivers.\n\nSolaar also reports on and controls some Logitech devices that directly connect\nto your computer using a USB cable or via Bluetooth.\nNot all such devices supported in Solaar as information needs to be added to Solaar\nfor each device type that directly connects.\n\n\n## HID++\n\nThe devices that Solaar handles use Logitech's HID++ protocol.\n\nHID++ is a Logitech-proprietary protocol that extends the standard HID\nprotocol for interfacing with receivers, keyboards, mice, and so on. It allows\nLogitech receivers to communicate with multiple devices and modify some\nfeatures of the device. As the HID++ protocol is\nproprietary, many aspects of it are unknown. Some information about HID++\nhas been obtained from Logitech but even that is subject to change and\nextension.\n\nThere are several versions of HID++ and many Logitech\nreceivers and devices that utilize it. Different receivers and devices\nimplement different portions of HID++ so even if two devices appear to be\nthe same in both physical appearance and behavior they may work\ndifferently underneath. (For example, there are versions of the\nM510 mouse that use different versions of the HID++ protocol.)\nContrariwise, two different devices may appear different physically but\nactually look the same to software. (For example, some M185 mice look the\nsame to software as some M310 mice.)\n\nThe software identity of a receiver can be determined by its USB product ID\n(reported by Solaar and also viewable in Linux using `lsusb`). The software\nidentity of a device that connects to a receiver can be determined by\nits wireless PID as reported by Solaar.  The software identity of devices that\nconnect via a USB cable or via bluetooth can be determined by their USB or\nBluetooth product ID.\n\n\n## Pairing and Unpairing\n\nSolaar is able to pair and unpair devices with\nreceivers as supported by the device and receiver.\n\nFor Unifying and Bolt receivers, pairing adds a new paired device, but\nonly if there is an open slot on the receiver. So these receivers need to\nbe able to unpair devices that they have been paired with or else they will\nnot have any open slots for pairing. Some Nano and Lightspeed receivers, like the\nNano receiver with USB ID `046d:c534`, can only pair with one keyboard and one mouse\nand pairing a new device replaces whatever device of that kind was\npreviously paired to the receiver. These receivers cannot unpair. Further,\nsome receivers can pair an unlimited number of times but others can only\npair a limited number of times.\n\nBolt receivers add an authentication phase to pairing,\nwhere the user has type a passcode or click some buttons to authenticate the device.\n\nOnly some connections between receivers and devices are possible. It should\nbe possible to connect any device with a Unifying logo on it to any receiver\nwith a Unifying logo on it and any device with a Bolt logo on it to any receiver\nwith a Bolt logo on it.\n\nMany receivers without the Unifying or Bolt logo\ncan connect only to the model of devices they were bought with and many devices\nwithout the Unifying or Bolt logo can only connect to a receiver\nthat matches the one they were bought with.\n\n## Device Settings\n\nSolaar can display quite a few changeable settings of receivers and devices.\nFor a list of HID++ features and their support see [the features page](features.md).\n\nSolaar does not do much beyond using the HID++ protocol to change the\nbehavior of receivers and devices via changing their settings.\nIn particular, Solaar cannot change how\nthe operating system turns the keycodes that a keyboard produces into\ncharacters that are sent to programs. That is the province of HID device\ndrivers and other software (such as X11).\n\nSettings can only be changed in the Solaar GUI when they are unlocked.\nTo unlock a setting click on the icon at the right-hand edge of the setting\nuntil an unlocked lock appears (with tooltop \"Changes allowed\").\n\nSolaar keeps track of most of the changeable settings of a device.\nDevices forget most changed settings when the device is turned off\nor goes into a power-saving mode.\nExceptions include the setting to change the host the device is connected to,\nthe setting to persistently change what a key or button does,\nand, for some devices, the fn-swap setting.\nWhen Solaar starts, it restores on-line devices to their previously-known state\nexcept for host connection and persistent key and button changes and while running Solaar restores\ndevices to their previously-known state when the device itself comes on line.\nSetting information is stored in the file `~/.config/solaar/config.yaml`.\n\nUpdating of a setting can be turned off in the Solaar GUI by clicking on the icon\nat the right-hand edge of the setting until a red icon appears (with tooltip\n\"Ignore this setting\").\n\nSolaar keeps track of settings independently on each computer.\nAs a result if a device is switched between different computers\nSolaar may apply different settings for it on the different computers.\n\nQuerying a device for its current state can require quite a few HID++\ninteractions. These interactions can temporarily slow down the device, so\nSolaar tries to internally cache information about devices while it is\nrunning.  If the device\nstate is changed by some other means, even sometimes by another invocation\nof Solaar, this cached information may become incorrect. Currently there is\nno way to force an update of the cached information besides restarting Solaar.\n\nLogitech receivers and devices have firmware in them. Some firmware\ncan be updated using Logitech software in Windows. For example, there are\nsecurity issues with some Logitech receivers and devices and Logitech has\nfirmware updates to alleviate these problems. Some Logitech firmware can\nalso be updated in Linux using `fwupdmgr`.\nWARNING: Updating firmware can cause a piece of hardware to become\npermanently non-functional if something goes wrong with the update or the\nupdate installs the wrong firmware.\n\n## Other Solaar Capabilities\n\nSolaar has a few capabilities that go beyond simply changing device settings.\n\n### Rule-based Processing of HID++ Notifications\n\nSolaar can process HID++ Notifications from devices to, for example,\nchange the speed of some thumb wheels.  These notifications are only sent\nfor actions that are set in Solaar to their HID++ setting (also known as diverted).\nFor more information on this capability of Solaar see\n[the rules page](https://pwr-solaar.github.io/Solaar/rules).\n\nUsers can edit rules using a GUI by clicking on the `Rule Editor` button in the Solaar main window.\n\n### Sliding DPI\n\nA few mice (such as the MX Vertical) have a button that is supposed to be used to change\nthe sensitivity (DPI) of the mouse by pressing the button and moving the mouse left and right.\nOther mice (such as the MX Master 3) don't have a button specific for this purpose\nbut have buttons that can be used for it.\n\nThe `Key/Button Diversion` setting can assign buttons to adjust sensitivity by setting the value for the button to `Sliding DPI`.\nThis capability is only present if the device supports changing the DPI in this way.\n\nPressing a button when it is set to `Sliding DPI` causes the mouse pointer to stop moving.\nWhen the button is released a new Sensitivity (DPI) value is applied to the mouse,\ndepending on how far right or left the mouse is moved.   If the mouse is moved only a little bit\nthe previous value that was set is applied to the mouse.\nNotifications from Solaar are displayed showing the setting that will be applied.\n\n### Mouse Gestures\n\nSome mice (such as the MX Master 3) have a button that is supposed to be used to\ncreate up/down/left/right mouse gestures.  Other mice (such as the MX Vertical) don't\nhave a button specific for this purpose but have buttons that can be used for it.\n\nThe `Key/Button Diversion` setting can assign buttons to initiate mouse gestures by setting the value for the button to `Mouse Gestures`.\nThis capability is only present if the device can support it.\n\nPressing a button when it is set to `Mouse Gestures` causes the mouse pointer to stop moving.\nWhen the button is released a `MOUSE_GESTURE` notification with the mouse movements and diverted key presses\nis sent to the Solaar rule system so that rules can detect these notifications.\nFor more information on Mouse Gestures rule conditions see\n[the rules page](https://pwr-solaar.github.io/Solaar/rules).\n\n### Keyboard Key Names and Locations\n\nSolaar uses the standard Logitech names for keyboard keys.  Some Logitech keyboards have different icons on some of their keys and have different functionality than suggested by these names.\n\nSolaar uses the standard US keyboard layout.  This currently only matters for the `Per-key Lighting` setting.  Users who want to have the key names for this setting reflect the keyboard layout that they use can create and edit `~/.config/solaar/keys.yaml` which contains a YAML dictionary of key names and locations.  For example, switching the `Y` and `Z` keys can be done  as:\n\n\tZ: 25\n\tY: 26\n\nThis is an experimental feature and may be modified or even eliminated.\n\n\n### Onboard Profiles\n\nSome mice store one or more profiles onboard.  An onboard profile controls certain aspects of the behavior of the mouse, including the rate at which the mouse reports movement, the resolution of the the movement reports, what the mouse buttons do, LED effects, and maybe more.  Solaar has a setting that switches between profiles or disables all profiles.\n\nWhen an onboard profile is active it may not be possible to change the aspects that the profile controls.  This is often seen for the Report Rate setting.   For some devices it is possible to make changes to the Sensitivity setting and to LED settings.  These changes are likely to only be temporary and may be overridden when the device reconnects or when Solaar is restarted.  This is in keeping with the intent of Onboard Profiles as controlling the device behavior.  To make the changes to these settings permanent it is necessary to disable onboard profiles.  Alternatively, multiple profiles can be set up as described below and these settings controlled by switching between the profiles.\n\nSolaar can dump the entire set of profiles into a YAML file and can load the entire set of profiles from a file.  Users can edit the file to effect changes to the profiles.\n\nA profile file has some bookkeeping information, including profile version and the name of the device, and a sequence of profiles.\n\nEach profile has the following fields:\n- enabled: Whether the profile is enabled.\n- sector: Where the profile is stored in device memory.  Sectors greater than 0xFF are in ROM and cannot be written (use the low byte as the sector to write to Flash).\n- name: A memonic name for the profile.\n- report_rate: A report rate in milliseconds from 1 to 8.\n- resolutions: A sequence of five sensor resolutions in DPI.\n- resolution_default_index: The index of the default sensor resolution (0 to 4).\n- resolution_shift_index: The index of the sensor resolution used when the DPI Shift button is pressed (0 to 4).\n- buttons: The action for each button on the mouse in normal mode.\n- gbuttons: The action for each button on the mouse in G-Shift mode.\n- angle_snap: Enable angle snapping for devices.\n- red, blue, green: Color indicator for the profile.\n- lighting: Lighting information for logo and side LEDs in normal mode, then for power saving mode.\n- ps_timeout: Delay in ms to go into power saving mode.\n- po_timeout: Delay in ms to go from power saving mode to fully off.\n- power_mode: Unknown purpose.\n- write count: Unknown purpose.\nMissing or unused parts of a profile are often a sequence of 0xFF bytes.\n\nButton actions can either perform a function (behavior: 9) or send a button click or key press (behaviour: 8).\nFunctions are:\n- 0: No Action - do nothing\n- 1: Tilt Left\n- 2: Tilt Right\n- 3: Next DPI - change device resolution to the next DPI\n- 4: Previous DPI - change device resolution to the previous DPI\n- 5: Cycle DPI - change device resolution to the next DPI considered as a cycle\n- 6: Default_DPI - change device resolution to the default resolution\n- 7: Shift_DPI - change device resolution to the shift resolution\n- 8: Next Profile - change to the next enabled profile\n- 9: Previous Profile - change to the previous enabled profile\n- 10: Cycle Profile - change to the next enabled profile considered as a cycle\n- 11: G-Shift - change all buttons to their G-Shift state\n- 12: Battery Status - show battery status on the device LEDs\n- 13: Profile Select - select the n'th enabled profile\n- 14: Mode Switch\n- 15: Host Button - switch between hosts (unverified)\n- 16: Scroll Down\n- 17: Scroll Up\nSome devices might not be able to perform all functions.\n\nButtons can send (type):\n- 0: Don't send anything.\n- 1: A button click (value) as a 16-bit bitmap, i.e., 1 is left click, 2 is right, 4 is middle, etc.\n- 2: An 8-bit USB HID keycode (value) plus an 8-bit modifier bitmap (modifiers), i.e., 0 for no modifiers, 1 for control, 2 for shift, etc.\n- 3: A 16-bit HID Consumer keycode (value).\n\nSee USB_HID_KEYCODES and HID_CONSUMERCODES in lib/logitech_receiver/special_keys.py for values to use for keycodes.\n\nButtons can also execute macros but Solaar does not provide any support for macros.\n\nLighting information is a sequence of lighting effects, with the first usually for the logo LEDs and the second usually for the side LEDs.\n\nThe fields possible in an effect are:\n- ID: The kind of effect:\n- color: A color parameter for the effect as a 24-bit RGB value.\n- intensity: How intense to make the color (1%-100%), 0 for the default (usually 100%).\n- speed: How fast to pulse in ms (one byte).\n- ramp: How to change to the color (0=default, 1=ramp up/down, 2=no ramping).\n- period: How fast to perform the effect in ms (two bytes).\n- form: The form of the breathe effect.\n- bytes: The raw bytes of other effects.\n\nThe possible effects and the fields the use are:\n- 0x0: Disable - No fields.\n- 0x1: Fixed color - color, whether to ramp.\n- 0x2: Pulse a color - color, speed.\n- 0x3 Cycle through the spectrum - period, intensity, form.\n- 0x8; A boot effect - No fields.\n- 0x9: A demo effect - NO fields.\n- 0xa: breathe a color (like pulse) - color, period.\n- 0xb: Ripple - color, period.\n- null: An unknown effect.\nOnly effects supported by the device can be used.\n\nTo set up profiles, first run `solaar profiles <device name>`, which will output a YAML dump of the profiles on the device. Then store the YAML dump into a file and edit the file to make changes. Finally run `solaar profiles <device name> <file name>` to load the profiles back onto the device. Profiles are stored in flash memory and persist when the device is inactive or turned off. When loading profiles Solaar is careful to only write the flash memory sectors that need to be changed. Solaar also checks for correct profile version and device name before loading a profile into a device.\n\nKeep a copy of the initial dump of profiles so that it can be loaded back to the device if problems are encountered with the edited profiles. The safest changes are to take an unused or unenabled profile sector and create a new profile in it, likely mostly copying parts of another profile.\n\n\n## System Tray\n\nSolaar's GUI normally uses an icon in the system tray.\nThis allows users to close Solaar and reopen from the tray.\nThis aspect of Solaar depends on having an active system tray which may\nrequire some special setup when using Gnome, particularly under Wayland.\n\nIf you are running Gnome, you most likely need the\n`gnome-shell-extension-appindicator` package installed.\nIn Fedora, this can be done by running\n```\nsudo dnf install gnome-shell-extension-appindicator\n```\nThe likely command in Ubuntu and related distributions is\n```\nsudo apt install gnome-shell-extension-appindicator\n```\nYou may have to log out and log in again before the system tray shows up.\n\n\n## Battery Icons\n\nFor many devices, Solaar shows the approximate battery level via icons that\nshow up in both the main window and the system tray. In previous versions\nseveral heuristics determined which icon names to use for this purpose,\nbut as more and more battery icon schemes have been developed this has\nbecome impossible to do well. Solaar now uses the eleven standard\nbattery icon names `battery-{full,good,low,critical,empty}[-charging]` and\n`battery-missing`.\n\nSolaar will use the symbolic versions of these icons if started with the\noption `--battery-icons=symbolic`. Because of external bugs,\nthese symbolic icons may be nearly invisible in dark themes.\n\n[solaar]: https://github.com/pwr-Solaar/Solaar\n[logitech]: https://www.logitech.com\n[unifying]: https://en.wikipedia.org/wiki/Logitech_Unifying_receiver\n"
  },
  {
    "path": "docs/debian.md",
    "content": "---\ntitle: Debian Repository\nlayout: page\n---\n\n# Debian repository\n\nSolaar is now part of the [official Debian repository](https://packages.debian.org/solaar). To install it on your Debian machine, use the following command: `sudo apt install solaar`\n"
  },
  {
    "path": "docs/devices/00README.txt",
    "content": "Files in this directory are edited output from `solaar show` providing\ninformation about devices and receivers that Solaar supports.  This\ndirectory does not contain information about all devices and receivers that\nSolaar supports.  Information is generally only added when provided in a\nSolaar issue.\n\nDirections for constructing the files are given below.  The files\n  Unifying Receiver C52B.txt\n  Craft Advanced Keyboard 4066.txt\n  Craft Advanced Keyboard B350.txt\n  MX Master 3 Wireless Mouse 4082.txt\n  MX Master 3 Wireless Mouse B023.txt\nare good examples of following the directions below.\n\n\nFile Naming\n\nLogitech device names are often reused so the names of files can't just be\nthe device name.  File names start with the name of the device or receiver\nas given in the first line of of output for the device.  The file name\ncontinues with a space and the WPID, if the device is connected to a\nreceiver, or the second half of the USB ID, if the device is connected via\nUSB or Bluetooth.  The WPID or USB ID are in upper case.  As devices can\nbehave differently when connected via a receiver or USB or Bluetooth there\nshould be a file for each possible connection method.\n\nFiles that do not follow this naming convention are retained for historical purposes.\n\n\nFile Contents\n\nEach file should contain the output of `solaar show NAME` where NAME\nis enough of the full name of a device or receiver to identify it.\nThe output of `solaar show` will provide information on all connnected\ndevices and receivers including their names.\nThe output of `solaar show NAME` can be edited\nto remove serial numbers and variable information such as the current values\nof settings.\nPassing the style requirements for Solaar documentation may require removing\ntrailing white space on lines.\n\nFor older devices probes of the device registers should be\nincluded but for newer devices this is not necessary.\n\nUnifying receivers can pair with any device that has the Unifying logo.\nBolt receivers can pair with any device that has the Bolt logo.\nNano and Lightspeed receivers can only pair with certain devices,\nso the end of their files should state the devices that they have\nbeen seen to be paired with or are part of.\n\n\nUpdating Files\n\nNewer versions of Solaar add support for more settings so it is useful to\nprovide updated versions of these files if there is information from the\ncurrent version of `solaar show NAME` that is not in the existing file.\n"
  },
  {
    "path": "docs/devices/Bluetooth Multi-Device Keyboard K380 B342.txt",
    "content": "Solaar version 1.1.4\n\n  1: Bluetooth Multi-Device Keyboard K380\n     Device path  : /dev/hidraw5\n     USB id       : 046d:B342\n     Codename     : Keyboard K380\n     Kind         : ?\n     Protocol     : HID++ 4.5\n     Serial number:\n     Model ID:      B34200000000\n     Unit ID:       16000000\n          Firmware: RBK 42.01.B0017\n          Hardware: 72\n     Supports 14 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Firmware RBK 42.01.B0017 B342C18DBFDD\n            Firmware: Hardware  72\n            Unit ID: 16000000  Model ID: B34200000000  Transport IDs: {'btid': 'B342'}\n         3: DEVICE NAME            {0005}\n            Name: Bluetooth Multi-Device Keyboard K380\n            Kind: keyboard\n         4: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: Keyboard K380\n         5: RESET                  {0020}\n         6: BATTERY STATUS         {1000}\n            Battery: 20%, discharging, next level 5%.\n         7: CHANGE HOST            {1814}\n            Change Host        : 1:Luay-A\n         8: HOSTS INFO             {1815}\n            Host 0 (paired): Luay-A\n            Host 1 (paired): BCM20703A2 Generic UART UHE App\n            Host 2 (unpaired):\n         9: REPROG CONTROLS V4     {1B04}\n            Key/Button Diversion (saved): {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Search:Regular, Multiplatform App Switch:Regular, Multiplatform Home:Regular, Multiplatform Menu:Diverted, Multiplatform Back:Regular, Multiplatform Insert:Regular, Screen Capture/Print Screen:Regular, Fn Down:Regular, Fn Up:Regular, Multiplatform Lock:Regular}\n            Key/Button Diversion        : {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Search:Regular, Multiplatform App Switch:Regular, Multiplatform Home:Regular, Multiplatform Menu:Diverted, Multiplatform Back:Regular, Multiplatform Insert:Regular, Screen Capture/Print Screen:Regular, Fn Down:Regular, Fn Up:Regular, Multiplatform Lock:Regular}\n        10: unknown:1E00           {1E00}   hidden\n        11: NEW FN INVERSION       {40A2}\n            Fn-swap: disabled\n            Fn-swap default: enabled\n            Swap Fx function (saved): False\n            Swap Fx function        : False\n        12: LOCK KEY STATE         {4220}\n        13: KEYBOARD DISABLE KEYS  {4521}\n            Disable keys (saved): {Caps Lock:False, Scroll Lock:False, Insert:True, Win:False}\n            Disable keys        : {Caps Lock:False, Scroll Lock:False, Insert:True, Win:False}\n     Has 16 reprogrammable keys:\n         0: Multiplatform Home        , default: MultiPlatform Home          => MultiPlatform Home\n             is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, group mask:empty\n             reporting: default\n         1: Multiplatform App Switch  , default: MultiPlatform App Switch    => MultiPlatform App Switch\n             is FN, FN sensitive, reprogrammable, divertable, pos:5, group:0, group mask:empty\n             reporting: default\n         2: Multiplatform Menu        , default: MultiPlatform Menu          => MultiPlatform Menu\n             is FN, FN sensitive, reprogrammable, divertable, pos:6, group:0, group mask:empty\n             reporting: diverted\n         3: Multiplatform Back        , default: MultiPlatform Back          => MultiPlatform Back\n             is FN, FN sensitive, reprogrammable, divertable, pos:7, group:0, group mask:empty\n             reporting: default\n         4: Previous                  , default: Previous                    => Previous\n             is FN, FN sensitive, divertable, pos:8, group:0, group mask:empty\n             reporting: default\n         5: Play/Pause                , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, divertable, pos:9, group:0, group mask:empty\n             reporting: default\n         6: Next                      , default: Next                        => Next\n             is FN, FN sensitive, divertable, pos:10, group:0, group mask:empty\n             reporting: default\n         7: Mute                      , default: Mute                        => Mute\n             is FN, FN sensitive, divertable, pos:11, group:0, group mask:empty\n             reporting: default\n         8: Volume Down               , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, divertable, pos:12, group:0, group mask:empty\n             reporting: default\n         9: Volume Up                 , default: Volume Up                   => Volume Up\n             is FN, FN sensitive, divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        10: Multiplatform Insert      , default: Switch Language             => Switch Language\n             FN sensitive, reprogrammable, divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        11: Fn Up                     , default: unknown:0070                => unknown:0070\n             is FN, divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        12: Fn Down                   , default: unknown:006F                => unknown:006F\n             is FN, divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        13: Screen Capture/Print Screen, default: Screen Capture              => Screen Capture\n             is FN, reprogrammable, divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        14: Search                    , default: Search Files                => Search Files\n             is FN, reprogrammable, divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        15: Multiplatform Lock        , default: WindowsLock                 => WindowsLock\n             is FN, reprogrammable, divertable, pos:0, group:0, group mask:empty\n             reporting: default\n     Battery: 20%, discharging, next level 5%.\n"
  },
  {
    "path": "docs/devices/Bolt Receiver C548.txt",
    "content": "Solaar version 1.1.4\n\nBolt Receiver\n  Device path  : /dev/hidraw8\n  USB id       : 046d:C548\n  Serial       : 38423638313332394241363434313837\n  Has 2 paired device(s) out of a maximum of 6.\n  Notifications: wireless, software present (0x000900)\n  Device activity counters: 1=252, 2=135\n"
  },
  {
    "path": "docs/devices/Candy companion chip 405F.txt",
    "content": " 7: Candy companion chip\n     Device path  : /dev/hidraw11\n     Codename     : Candy\n     Kind         : touchpad\n     Protocol     : HID++ 4.2\n     Serial number: 5B2B9A98\n     Model ID:      405F00000000\n     Unit ID:       32314707\n          Firmware: CC  07.00.B0010\n        Bootloader: BOT 32.00.B0010\n     Supports 11 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Firmware CC  07.00.B0010 405F\n            Firmware: Bootloader BOT 32.00.B0010 405F\n            Unit ID: 32314707  Model ID: 405F00000000  Transport IDs: {'wpid': '405F'}\n         3: DEVICE NAME            {0005}\n            Name: Candy companion chip\n            Kind: touchpad\n         4: unknown:18A1           {18A1}   internal, hidden\n         5: unknown:1E00           {1E00}   hidden\n         6: unknown:1EB0           {1EB0}   internal, hidden\n         7: DFUCONTROL SIGNED      {00C2}\n         8: unknown:1801           {1801}   internal, hidden\n         9: DEVICE RESET           {1802}   internal, hidden\n        10: unknown:1803           {1803}   internal, hidden\n     Battery status unavailable.\n\nPart of the G PowerPlay Wireless Mouse Pad.\n"
  },
  {
    "path": "docs/devices/Couch Mouse M515 4007.txt",
    "content": "1: Couch Mouse M515\n   Codename     : M515\n   Kind         : mouse\n   Wireless PID : 4007\n   Protocol     : HID++ 2.0\n   Polling rate : 8 ms\n   Serial number: BED587E9\n        Firmware: RQM 24.00.B0023\n      Bootloader: DFU 00.02.B0010\n   The power switch is located on the base.\n   Supports 16 HID++ 2.0 features:\n       0: ROOT                   {0000}\n       1: FEATURE SET            {0001}\n       2: DEVICE FW VERSION      {0003}\n       3: DEVICE NAME            {0005}\n       4: DFUCONTROL             {00C0}\n       5: BATTERY STATUS         {1000}\n       6: unknown:1A30           {1A30}   hidden\n       7: REPROG CONTROLS        {1B00}\n       8: WIRELESS DEVICE STATUS {1D4B}\n       9: unknown:1DF3           {1DF3}   hidden\n      10: VERTICAL SCROLLING     {2100}\n      11: HI RES SCROLLING       {2120}\n      12: MOUSE POINTER          {2200}\n      13: unknown:1F02           {1F02}   hidden\n      14: unknown:1F03           {1F03}   hidden\n      15: unknown:1E80           {1E80}   hidden\n   Has 5 reprogrammable keys:\n       0: LEFT CLICK                 => LeftClick                     mse, reprogrammable\n       1: RIGHT CLICK                => RightClick                    mse, reprogrammable\n       2: MIDDLE BUTTON              => MiddleMouseButton             mse, reprogrammable\n       3: BACK AS BUTTON 4           => BackEx                        mse, reprogrammable\n       4: FORWARD AS BUTTON 5        => BrowserForwardEx              mse, reprogrammable\n   Battery: 65%, discharging,\n"
  },
  {
    "path": "docs/devices/Craft Advanced Keyboard 4066.txt",
    "content": "Solaar version 1.1.4\n\n  2: Craft Advanced Keyboard\n     Device path  : /dev/hidraw4\n     WPID         : 4066\n     Codename     : Craft\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 112C46EA\n     Model ID:      B35040660000\n     Unit ID:       43DAF041\n        Bootloader: BOT 41.01.B0015\n          Firmware: MPK 07.01.B0015\n             Other:\n             Other:\n     The power switch is located on the edge of top right corner.\n     Supports 38 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 41.01.B0015 0000B6A2C54601\n            Firmware: Firmware MPK 07.01.B0015 4066B6A2C54601\n            Firmware: Other\n            Firmware: Other\n            Unit ID: 43DAF041  Model ID: B35040660000  Transport IDs: {'btleid': 'B350', 'wpid': '4066'}\n         3: DEVICE NAME            {0005}\n            Name: Craft Advanced Keyboard\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: Keyboard Craft\n         7: BATTERY STATUS         {1000}\n            Battery: 50%, discharging, next level 20%.\n         8: CHANGE HOST            {1814}\n            Change Host        : 1:idefix\n         9: HOSTS INFO             {1815}\n            Host 0 (paired): idefix\n            Host 1 (paired): idefix\n            Host 2 (paired): Galaxy Tab S6\n        10: BACKLIGHT2             {1982}\n            Backlight (saved): True\n            Backlight        : True\n        11: REPROG CONTROLS V4     {1B04}\n            Key/Button Diversion (saved): {Calculator:Regular, Show Desktop:Diverted, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Diverted, Host Switch Channel 3:Diverted, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular}\n            Key/Button Diversion        : {Calculator:Regular, Show Desktop:Diverted, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Diverted, Host Switch Channel 3:Diverted, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular}\n        12: PERSISTENT REMAPPABLE ACTION {1C00}\n            Persistent Key/Button Mapping        : {Calculator:AL Calculator, Show Desktop:Meta+D, Lock PC:Meta+L, Screen Capture/Print Screen:SYSRQ, Brightness Down:Brightness Down, Brightness Up:Brightness Up, Mission Control/Task View:Meta+TAB, Dashboard Launchpad/Action Center:Meta+A, Backlight Down:No Output (only as default), Backlight Up:No Output (only as default), Previous Fn:Scan Previous Track, Play/Pause Fn:Play/Pause, Next Fn:Scan Next Track, Mute Fn:Mute, Volume Down Fn:No Output, Volume Up Fn:Volume Up, App Contextual Menu/Right Click:COMPOSE}\n        13: K375S FN INVERSION     {40A3}\n            Swap Fx function (saved): True\n            Swap Fx function        : True\n        14: ENCRYPTION             {4100}\n        15: LOCK KEY STATE         {4220}\n        16: KEYBOARD DISABLE KEYS  {4521}\n            Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        17: MULTIPLATFORM          {4531}\n            Set OS (saved): Windows\n            Set OS        : Windows\n        18: CROWN                  {4600}\n            Crown smooth scroll (saved): False\n            Crown smooth scroll        : False\n            Divert crown events (saved): True\n            Divert crown events        : True\n        19: DFUCONTROL SIGNED      {00C2}\n        20: unknown:1803           {1803}   internal, hidden\n        21: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        22: unknown:1813           {1813}   internal, hidden\n        23: OOBSTATE               {1805}   internal, hidden\n        24: unknown:1830           {1830}   internal, hidden\n        25: unknown:1890           {1890}   internal, hidden\n        26: unknown:1891           {1891}   internal, hidden\n        27: unknown:1801           {1801}   internal, hidden\n        28: unknown:18A1           {18A1}   internal, hidden\n        29: unknown:9280           {9280}   internal, hidden\n        30: unknown:1A20           {1A20}   internal, hidden\n        31: unknown:1DF3           {1DF3}   internal, hidden\n        32: unknown:1E00           {1E00}   hidden\n        33: unknown:1EB0           {1EB0}   internal, hidden\n        34: unknown:1861           {1861}   internal, hidden\n        35: unknown:18B0           {18B0}   internal, hidden\n        36: unknown:92C0           {92C0}   internal, hidden\n        37: unknown:9203           {9203}   internal, hidden\n     Has 24 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: diverted\n         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: diverted\n         3: Brightness Down           , default: Brightness Down             => Brightness Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         4: Brightness Up             , default: Brightness Up               => Brightness Up\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:2, group:0, group mask:empty\n             reporting: default\n         5: Mission Control/Task View , default: Mission Control/Task View   => Mission Control/Task View\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:3, group:0, group mask:empty\n             reporting: default\n         6: Dashboard Launchpad/Action Center, default: Dashboard Launchpad/Action Center => Dashboard Launchpad/Action Center\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty\n             reporting: default\n         7: Show Desktop              , default: Show Desktop                => Show Desktop\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:5, group:0, group mask:empty\n             reporting: diverted\n         8: Backlight Down            , default: Backlight Down              => Backlight Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:6, group:0, group mask:empty\n             reporting: default\n         9: Backlight Up              , default: Backlight Up                => Backlight Up\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:7, group:0, group mask:empty\n             reporting: default\n        10: Previous Fn               , default: Previous                    => Previous\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:8, group:0, group mask:empty\n             reporting: default\n        11: Play/Pause Fn             , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:9, group:0, group mask:empty\n             reporting: default\n        12: Next Fn                   , default: Next                        => Next\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:10, group:0, group mask:empty\n             reporting: default\n        13: Mute Fn                   , default: Mute                        => Mute\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, group mask:empty\n             reporting: default\n        14: Volume Down Fn            , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, group mask:empty\n             reporting: default\n        15: Volume Up Fn              , default: Volume Up                   => Volume Up\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Calculator                , default: Calculator                  => Calculator\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Screen Capture/Print Screen, default: Screen Capture              => Screen Capture\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        18: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        19: Lock PC                   , default: WindowsLock                 => WindowsLock\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        20: Left Arrow                , default: Keyboard Left Arrow         => Keyboard Left Arrow\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        21: Right Arrow               , default: Keyboard Right Arrow        => Keyboard Right Arrow\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        22: F Lock                    , default: Do Nothing One              => Do Nothing One\n             is FN, pos:0, group:0, group mask:empty\n             reporting: default\n        23: FN Key                    , default: Do Nothing One              => Do Nothing One\n             nonstandard, pos:0, group:0, group mask:empty\n             reporting: default\n     Has 17 persistent remappable keys:\n         0: Brightness Down            => Consumer: Brightness Down (remapped)\n         1: Brightness Up              => Consumer: Brightness Up (remapped)\n         2: Mission Control/Task View  => Key: Meta+TAB\n         3: Dashboard Launchpad/Action Center => Key: Meta+A\n         4: Show Desktop               => Key: Meta+D\n         5: Backlight Down             => None\n         6: Backlight Up               => None\n         7: Previous Fn                => Consumer: Scan Previous Track\n         8: Play/Pause Fn              => Consumer: Play/Pause\n         9: Next Fn                    => Consumer: Scan Next Track\n        10: Mute Fn                    => Consumer: Mute\n        11: Volume Down Fn             => Key: No Output (remapped)\n        12: Volume Up Fn               => Consumer: Volume Up\n        13: Calculator                 => Consumer: AL Calculator\n        14: Screen Capture/Print Screen => Key: SYSRQ\n        15: App Contextual Menu/Right Click => Key: COMPOSE\n        16: Lock PC                    => Key: Meta+L\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/Craft Advanced Keyboard B350.txt",
    "content": "Solaar version 1.1.4\n\n  1: Craft Advanced Keyboard\n     Device path  : /dev/hidraw5\n     USB id       : 046d:B350\n     Codename     : Craft\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Serial number:\n     Model ID:      B35040660000\n     Unit ID:       43DAF041\n        Bootloader: BOT 41.01.B0015\n          Firmware: MPK 07.01.B0015\n             Other:\n             Other:\n     Supports 33 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 41.01.B0015 0000B6A2C54601\n            Firmware: Firmware MPK 07.01.B0015 B350B6A2C54601\n            Firmware: Other\n            Firmware: Other\n            Unit ID: 43DAF041  Model ID: B35040660000  Transport IDs: {'btleid': 'B350', 'wpid': '4066'}\n         3: DEVICE NAME            {0005}\n            Name: Craft Advanced Keyboard\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: Keyboard Craft\n         7: BATTERY STATUS         {1000}\n            Battery: 50%, discharging, next level 20%.\n         8: CHANGE HOST            {1814}\n            Change Host        : 2:idefix\n         9: HOSTS INFO             {1815}\n            Host 0 (paired): idefix\n            Host 1 (paired): idefix\n            Host 2 (paired): Galaxy Tab S6\n        10: BACKLIGHT2             {1982}\n            Backlight (saved): True\n            Backlight        : True\n        11: REPROG CONTROLS V4     {1B04}\n            Key/Button Diversion (saved): {Calculator:Regular, Show Desktop:Diverted, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Diverted, Host Switch Channel 3:Diverted, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular}\n            Key/Button Diversion        : {Calculator:Regular, Show Desktop:Diverted, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Diverted, Host Switch Channel 3:Diverted, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular}\n        12: PERSISTENT REMAPPABLE ACTION {1C00}\n            Persistent Key/Button Mapping        : {Calculator:AL Calculator, Show Desktop:Meta+D, Lock PC:Meta+L, Screen Capture/Print Screen:SYSRQ, Brightness Down:No Output (only as default), Brightness Up:No Output (only as default), Mission Control/Task View:Meta+TAB, Dashboard Launchpad/Action Center:Meta+A, Backlight Down:No Output (only as default), Backlight Up:No Output (only as default), Previous Fn:Scan Previous Track, Play/Pause Fn:Play/Pause, Next Fn:Scan Next Track, Mute Fn:Mute, Volume Down Fn:Volume Down, Volume Up Fn:Volume Up, App Contextual Menu/Right Click:COMPOSE}\n        13: K375S FN INVERSION     {40A3}\n            Swap Fx function (saved): True\n            Swap Fx function        : True\n        14: ENCRYPTION             {4100}\n        15: LOCK KEY STATE         {4220}\n        16: KEYBOARD DISABLE KEYS  {4521}\n            Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        17: MULTIPLATFORM          {4531}\n            Set OS (saved): Windows\n            Set OS        : Windows\n        18: CROWN                  {4600}\n            Crown smooth scroll (saved): False\n            Crown smooth scroll        : False\n            Divert crown events (saved): True\n            Divert crown events        : True\n        19: DFUCONTROL SIGNED      {00C2}\n        20: unknown:1803           {1803}   internal, hidden\n        21: unknown:1813           {1813}   internal, hidden\n        22: unknown:1830           {1830}   internal, hidden\n        23: unknown:1801           {1801}   internal, hidden\n        24: unknown:18A1           {18A1}   internal, hidden\n        25: unknown:1A20           {1A20}   internal, hidden\n        26: unknown:1DF3           {1DF3}   internal, hidden\n        27: unknown:1E00           {1E00}   hidden\n        28: unknown:1EB0           {1EB0}   internal, hidden\n        29: unknown:1861           {1861}   internal, hidden\n        30: unknown:18B0           {18B0}   internal, hidden\n        31: unknown:92C0           {92C0}   internal, hidden\n        32: unknown:9203           {9203}   internal, hidden\n     Has 24 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: diverted\n         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: diverted\n         3: Brightness Down           , default: Brightness Down             => Brightness Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         4: Brightness Up             , default: Brightness Up               => Brightness Up\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:2, group:0, group mask:empty\n             reporting: default\n         5: Mission Control/Task View , default: Mission Control/Task View   => Mission Control/Task View\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:3, group:0, group mask:empty\n             reporting: default\n         6: Dashboard Launchpad/Action Center, default: Dashboard Launchpad/Action Center => Dashboard Launchpad/Action Center\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty\n             reporting: default\n         7: Show Desktop              , default: Show Desktop                => Show Desktop\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:5, group:0, group mask:empty\n             reporting: diverted\n         8: Backlight Down            , default: Backlight Down              => Backlight Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:6, group:0, group mask:empty\n             reporting: default\n         9: Backlight Up              , default: Backlight Up                => Backlight Up\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:7, group:0, group mask:empty\n             reporting: default\n        10: Previous Fn               , default: Previous                    => Previous\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:8, group:0, group mask:empty\n             reporting: default\n        11: Play/Pause Fn             , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:9, group:0, group mask:empty\n             reporting: default\n        12: Next Fn                   , default: Next                        => Next\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:10, group:0, group mask:empty\n             reporting: default\n        13: Mute Fn                   , default: Mute                        => Mute\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, group mask:empty\n             reporting: default\n        14: Volume Down Fn            , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, group mask:empty\n             reporting: default\n        15: Volume Up Fn              , default: Volume Up                   => Volume Up\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Calculator                , default: Calculator                  => Calculator\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Screen Capture/Print Screen, default: Screen Capture              => Screen Capture\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        18: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        19: Lock PC                   , default: WindowsLock                 => WindowsLock\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        20: Left Arrow                , default: Keyboard Left Arrow         => Keyboard Left Arrow\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        21: Right Arrow               , default: Keyboard Right Arrow        => Keyboard Right Arrow\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        22: F Lock                    , default: Do Nothing One              => Do Nothing One\n             is FN, pos:0, group:0, group mask:empty\n             reporting: default\n        23: FN Key                    , default: Do Nothing One              => Do Nothing One\n             nonstandard, pos:0, group:0, group mask:empty\n             reporting: default\n     Has 17 persistent remappable keys:\n         0: Brightness Down            => None\n         1: Brightness Up              => None\n         2: Mission Control/Task View  => Key: Meta+TAB\n         3: Dashboard Launchpad/Action Center => Key: Meta+A\n         4: Show Desktop               => Key: Meta+D\n         5: Backlight Down             => None\n         6: Backlight Up               => None\n         7: Previous Fn                => Consumer: Scan Previous Track\n         8: Play/Pause Fn              => Consumer: Play/Pause\n         9: Next Fn                    => Consumer: Scan Next Track\n        10: Mute Fn                    => Consumer: Mute\n        11: Volume Down Fn             => Consumer: Volume Down\n        12: Volume Up Fn               => Consumer: Volume Up\n        13: Calculator                 => Consumer: AL Calculator\n        14: Screen Capture/Print Screen => Key: SYSRQ\n        15: App Contextual Menu/Right Click => Key: COMPOSE\n        16: Lock PC                    => Key: Meta+L\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/ERGO M575 Trackball 4096.txt",
    "content": "Solaar version 1.1.4\n\n  1: ERGO M575 Trackball\n     Device path  : /dev/hidraw5\n     WPID         : 4096\n     Codename     : ERGO M575\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 460DFDC2\n     Model ID:      B02740960000\n     Unit ID:       460DFDC2\n        Bootloader: BOT 40.00.B0009\n          Firmware: MPM 26.00.B0009\n             Other:\n     The power switch is located on the base.\n     Supports 25 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 40.00.B0009 0000ABF1CB8B01\n            Firmware: Firmware MPM 26.00.B0009 4096ABF1CB8B01\n            Firmware: Other\n            Unit ID: 460DFDC2  Model ID: B02740960000  Transport IDs: {'btleid': 'B027', 'wpid': '4096'}\n         3: DEVICE NAME            {0005}\n            Name: ERGO M575 Trackball\n            Kind: trackball\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: ERGO M575\n         7: UNIFIED BATTERY        {1004}\n         8: REPROG CONTROLS V4     {1B04}\n            DPI Sliding Adjustment (saved): Off\n            DPI Sliding Adjustment        : Off\n            Mouse Gestures (saved): Off\n            Mouse Gestures        : Off\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular}\n         9: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 500\n            Sensitivity (DPI)        : 500\n        10: XY STATS               {2250}\n        11: DFUCONTROL SIGNED      {00C2}\n        12: DEVICE RESET           {1802}   internal, hidden\n        13: unknown:1803           {1803}   internal, hidden\n        14: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        15: unknown:1812           {1812}   internal, hidden\n        16: OOBSTATE               {1805}   internal, hidden\n        17: unknown:1830           {1830}   internal, hidden\n        18: unknown:1890           {1890}   internal, hidden\n        19: unknown:1891           {1891}   internal, hidden\n        20: unknown:18A1           {18A1}   internal, hidden\n        21: unknown:1E00           {1E00}   hidden\n        22: unknown:1EB0           {1EB0}   internal, hidden\n        23: unknown:1861           {1861}   internal, hidden\n        24: unknown:1E22           {1E22}   internal, hidden\n     Has 6 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Battery: 85%, discharging.\n"
  },
  {
    "path": "docs/devices/EX100 Receiver 27 Mhz C517.text",
    "content": "solaar version 1.1.11-80-gdea496f\n\nEX100 Receiver 27 Mhz\n  Device path  : /dev/hidraw2\n  USB id       : 046d:C517\n  Serial       : None\n  Has 2 paired device(s) out of a maximum of 4.\n  Notifications: wireless (0x000100)\n\n  1: Wireless Mouse EX100\n     Device path  : /dev/hidraw3\n     WPID         : 003F\n     Codename     : EX100m\n     Kind         : mouse\n     Protocol     : HID++ 1.0\n     Serial number:\n     The power switch is located on the (unknown).\n     Notifications: roller V, mouse extra buttons, battery status, roller H (0x3C0000).\n     Battery: good, discharging.\n\n  3: Wireless Keyboard EX100\n     Device path  : /dev/hidraw6\n     WPID         : 0065\n     Codename     : EX100\n     Kind         : keyboard\n     Protocol     : HID++ 1.0\n     Serial number:\n     The power switch is located on the (unknown).\n     Notifications: keyboard multimedia raw, battery status (0x110000).\n     Battery: good, discharging.\n\n\n  Register Dump\n    Notifications         0x00: 0x000100\n    Connection State      0x02: 0x000100\n    Device Activity       0xb3: None\n    Pairing Register 0xb5 0x00: None\n    Pairing Register 0xb5 0x01: None\n    Pairing Register 0xb5 0x02: None\n    Pairing Register 0xb5 0x03: None\n    Pairing Register 0xb5 0x04: None\n    Pairing Register 0xb5 0x05: None\n    Pairing Register 0xb5 0x06: None\n    Pairing Register 0xb5 0x07: None\n    Pairing Register 0xb5 0x08: None\n    Pairing Register 0xb5 0x09: None\n    Pairing Register 0xb5 0x0a: None\n    Pairing Register 0xb5 0x0b: None\n    Pairing Register 0xb5 0x0c: None\n    Pairing Register 0xb5 0x0d: None\n    Pairing Register 0xb5 0x0e: None\n    Pairing Register 0xb5 0x0f: None\n    Pairing Register 0xb5 0x10: None\n    Pairing Register 0xb5 0x20: None\n    Pairing Register 0xb5 0x30: None\n    Pairing Register 0xb5 0x50: None\n    Pairing Name     0xb5 0x40: None\n    Pairing Name     0xb5 0x60 0x1:  0 None\n    Pairing Name     0xb5 0x60 0x2:  0 None\n    Pairing Name     0xb5 0x60 0x3:  0 None\n    Pairing Register 0xb5 0x11: None\n    Pairing Register 0xb5 0x21: None\n    Pairing Register 0xb5 0x31: None\n    Pairing Register 0xb5 0x51: None\n    Pairing Name     0xb5 0x41: None\n    Pairing Name     0xb5 0x61 0x1:  0 None\n    Pairing Name     0xb5 0x61 0x2:  0 None\n    Pairing Name     0xb5 0x61 0x3:  0 None\n    Pairing Register 0xb5 0x12: None\n    Pairing Register 0xb5 0x22: None\n    Pairing Register 0xb5 0x32: None\n    Pairing Register 0xb5 0x52: None\n    Pairing Name     0xb5 0x42: None\n    Pairing Name     0xb5 0x62 0x1:  0 None\n    Pairing Name     0xb5 0x62 0x2:  0 None\n    Pairing Name     0xb5 0x62 0x3:  0 None\n    Pairing Register 0xb5 0x13: None\n    Pairing Register 0xb5 0x23: None\n    Pairing Register 0xb5 0x33: None\n    Pairing Register 0xb5 0x53: None\n    Pairing Name     0xb5 0x43: None\n    Pairing Name     0xb5 0x63 0x1:  0 None\n    Pairing Name     0xb5 0x63 0x2:  0 None\n    Pairing Name     0xb5 0x63 0x3:  0 None\n    Pairing Register 0xb5 0x14: None\n    Pairing Register 0xb5 0x24: None\n    Pairing Register 0xb5 0x34: None\n    Pairing Register 0xb5 0x54: None\n    Pairing Name     0xb5 0x44: None\n    Pairing Name     0xb5 0x64 0x1:  0 None\n    Pairing Name     0xb5 0x64 0x2:  0 None\n    Pairing Name     0xb5 0x64 0x3:  0 None\n    Pairing Register 0xb5 0x15: None\n    Pairing Register 0xb5 0x25: None\n    Pairing Register 0xb5 0x35: None\n    Pairing Register 0xb5 0x55: None\n    Pairing Name     0xb5 0x45: None\n    Pairing Name     0xb5 0x65 0x1:  0 None\n    Pairing Name     0xb5 0x65 0x2:  0 None\n    Pairing Name     0xb5 0x65 0x3:  0 None\n    Pairing Register 0xb5 0x16: None\n    Pairing Register 0xb5 0x26: None\n    Pairing Register 0xb5 0x36: None\n    Pairing Register 0xb5 0x56: None\n    Pairing Name     0xb5 0x46: None\n    Pairing Name     0xb5 0x66 0x1:  0 None\n    Pairing Name     0xb5 0x66 0x2:  0 None\n    Pairing Name     0xb5 0x66 0x3:  0 None\n    Firmware         0xf1 0x00: None\n    Firmware         0xf1 0x01: None\n    Firmware         0xf1 0x02: None\n    Firmware         0xf1 0x03: None\n    Firmware         0xf1 0x04: None\n\n    Register Short   0x00 0x00: 0x000100\n    Register Long    0x00 0x00: invalid SubID/command\n    ...\n    Register Long    0x00 0xfe: invalid SubID/command\n    Register Short   0x01 0x00: 0x000200\n    Register Long    0x01 0x00: invalid SubID/command\n    Register Long    0x01 0x01: invalid SubID/command\n    Register Long    0x01 0x02: invalid SubID/command\n    ...\n\n\n./scan-registers.sh ff /dev/hidraw4\n# Old notification flags: 000100\n>> (   0.035) [10 FF 8100 000100] '\\x10\\xff\\x81\\x00\\x00\\x01\\x00'\n<< (   0.015) [10 FF 8101 000000] '\\x10\\xff\\x81\\x01\\x00\\x00\\x00'\n>> (   0.020) [10 FF 8101 000200] '\\x10\\xff\\x81\\x01\\x00\\x02\\x00'\n<< (   0.030) [10 FF 8102 000000] '\\x10\\xff\\x81\\x02\\x00\\x00\\x00'\n>> (   0.036) [10 FF 8102 000200] '\\x10\\xff\\x81\\x02\\x00\\x02\\x00'\n--\n<< (   0.142) [10 FF 8109 000000] '\\x10\\xff\\x81\\t\\x00\\x00\\x00'\n>> (   0.148) [10 FF 8109 010000] '\\x10\\xff\\x81\\t\\x01\\x00\\x00'\n--\n<< (   1.790) [10 FF 8170 000000] '\\x10\\xff\\x81p\\x00\\x00\\x00'\n>> (   1.796) [10 FF 8170 012100] '\\x10\\xff\\x81p\\x01!\\x00'\n<< (   1.806) [10 FF 8171 000000] '\\x10\\xff\\x81q\\x00\\x00\\x00'\n>> (   1.812) [10 FF 8171 011200] '\\x10\\xff\\x81q\\x01\\x12\\x00'\n--\n<< (   1.838) [10 FF 8173 000000] '\\x10\\xff\\x81s\\x00\\x00\\x00'\n>> (   1.844) [10 FF 8173 643F00] '\\x10\\xff\\x81sd?\\x00'\n--\n<< (   2.046) [10 FF 8180 000000] '\\x10\\xff\\x81\\x80\\x00\\x00\\x00'\n>> (   2.052) [10 FF 8180 030000] '\\x10\\xff\\x81\\x80\\x03\\x00\\x00'\n--\n<< (   3.326) [10 FF 81D0 000000] '\\x10\\xff\\x81\\xd0\\x00\\x00\\x00'\n>> (   3.332) [10 FF 81D0 000000] '\\x10\\xff\\x81\\xd0\\x00\\x00\\x00'\n\ndevices\n01 mouse\nRed button pressed\n>> ( 1676.106) [10 01 0810 000000] '\\x10\\x01\\x08\\x10\\x00\\x00\\x00'\n>> ( 1676.114) [10 01 4600 000021] '\\x10\\x01F\\x00\\x00\\x00!'\n>> ( 1676.122) [10 FF 4600 211100] '\\x10\\xffF\\x00!\\x11\\x00'\n\nPower lewel?\n?? Input: 10 01 81 07 00 00 00\n<< ( 1739.032) [10 01 8107 000000] '\\x10\\x01\\x81\\x07\\x00\\x00\\x00'\n>> ( 1739.040) [10 01 8107 030000] '\\x10\\x01\\x81\\x07\\x03\\x00\\x00'\n               [10 01 8107 070000] '\\x10\\x01\\x81\\x07\\x07\\x00\\x00'\n\npower change\n>> ( 2441.563) [10 01 0703 000000] '\\x10\\x01\\x07\\x03\\x00\\x00\\x00'\n>> ( 100.159)  [10 01 0707 000000] '\\x10\\x01\\x07\\x07\\x00\\x00\\x00'\n\nenable power event\n<< (  59.190) [10 01 8000 100000] '\\x10\\x01\\x80\\x00\\x10\\x00\\x00'\n>> (  59.193) [10 01 8000 000000] '\\x10\\x01\\x80\\x00\\x00\\x00\\x00'\n\n\n03 keyboard\n\nPower level?\n?? Input: 10 03 81 07 00 00 00\n<< ( 1777.961) [10 03 8107 000000] '\\x10\\x03\\x81\\x07\\x00\\x00\\x00'\n>> ( 1777.967) [10 03 8107 070000] '\\x10\\x03\\x81\\x07\\x07\\x00\\x00'\n\npower on\n>> ( 1571.805) [10 03 0810 000000] '\\x10\\x03\\x08\\x10\\x00\\x00\\x00'\n>> ( 1574.709) [10 03 0800 000000] '\\x10\\x03\\x08\\x00\\x00\\x00\\x00'\n\nred button pressed\n>> ( 1619.043) [10 03 0810 000000] '\\x10\\x03\\x08\\x10\\x00\\x00\\x00'\n>> ( 1619.051) [10 03 4600 000011] '\\x10\\x03F\\x00\\x00\\x00\\x11'\n>> ( 1619.059) [10 FF 4600 221100] '\\x10\\xffF\\x00\"\\x11\\x00'\n>> ( 1621.747) [10 03 0800 000000] '\\x10\\x03\\x08\\x00\\x00\\x00\\x00'\n\nFn pressed\n>> ( 1651.715) [10 03 032C 100000] '\\x10\\x03\\x03,\\x10\\x00\\x00'\n>> ( 1652.170) [10 03 0300 000000] '\\x10\\x03\\x03\\x00\\x00\\x00\\x00'\n\n\n\n\nBattery status:\n1.9V critical\n2.3V low\n2.5V full\n"
  },
  {
    "path": "docs/devices/G Pro Wireless Gaming Mouse 4079.txt",
    "content": "Solaar version 1.1.4rc1\n\n  1: G Pro Wireless Gaming Mouse\n     Device path  : /dev/hidraw10\n     WPID         : 4079\n     Codename     : G Pro\n     Kind         : mouse\n     Protocol     : HID++ 4.2\n     Polling rate : 2 ms (500Hz)\n     Serial number: 40B217C0\n     Model ID:      4079C0880000\n     Unit ID:       40B217C0\n        Bootloader: BOT 74.02.B0026\n          Firmware: MPM 15.02.B0026\n             Other:\n     The power switch is located on the base.\n     Supports 28 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 74.02.B0026 AADF85EE714A\n            Firmware: Firmware MPM 15.02.B0026 407985EE714A\n            Firmware: Other\n            Unit ID: 40B217C0  Model ID: 4079C0880000  Transport IDs: {'wpid': '4079', 'usbid': 'C088'}\n         3: DEVICE NAME            {0005}\n            Name: G Pro Wireless Gaming Mouse\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: BATTERY VOLTAGE        {1001}\n            Battery: 3926mV, discharging, 70.\n         7: COLOR LED EFFECTS      {8070}\n         8: LED CONTROL            {1300}\n         9: ONBOARD PROFILES       {8100}\n            Device Mode: On-Board\n            Onboard Profiles (saved): Enable\n            Onboard Profiles        : Enable\n        10: MOUSE BUTTON SPY       {8110}\n        11: REPORT RATE            {8060}\n            Polling Rate (ms): 2\n            Polling Rate (ms) (saved): 2\n            Polling Rate (ms)        : 2\n        12: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 1600\n            Sensitivity (DPI)        : 1600\n        13: DEVICE RESET           {1802}   internal, hidden\n        14: unknown:1803           {1803}   internal, hidden\n        15: OOBSTATE               {1805}   internal, hidden\n        16: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        17: unknown:1811           {1811}   internal, hidden\n        18: unknown:1830           {1830}   internal, hidden\n        19: unknown:1890           {1890}   internal, hidden\n        20: unknown:1891           {1891}   internal, hidden\n        21: unknown:18A1           {18A1}   internal, hidden\n        22: unknown:1801           {1801}   internal, hidden\n        23: unknown:18B1           {18B1}   internal, hidden\n        24: unknown:1DF3           {1DF3}   internal, hidden\n        25: unknown:1E00           {1E00}   hidden\n        26: unknown:1EB0           {1EB0}   internal, hidden\n        27: unknown:1863           {1863}   internal, hidden\n     Battery: 3926mV, discharging, 70.\n"
  },
  {
    "path": "docs/devices/G213 Prodigy Gaming Keyboard C366.txt",
    "content": "Solaar version 1.1.5rc1\n\nUSB and Bluetooth Devices\n\n  1: G213 Prodigy Gaming Keyboard\n     Device path  : /dev/hidraw2\n     USB id       : 046d:C336\n     Codename     : G213\n     Kind         : keyboard\n     Protocol     : HID++ 4.2\n     Polling rate : 1 ms (1000Hz)\n     Serial number:\n     Model ID:      C33600000000\n     Unit ID:       31314709\n          Firmware: U1  09.00.B0006\n        Bootloader: BOT 31.00.B0002\n     Supports 15 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Firmware U1  09.00.B0006 C336\n            Firmware: Bootloader BOT 31.00.B0002 AAC8\n            Unit ID: 31314709  Model ID: C33600000000  Transport IDs: {'usbid': 'C336'}\n         3: KEYBOARD DISABLE BY USAGE {4522} V0\n         4: DEVICE NAME            {0005} V0\n            Name: Gaming Keyboard G213\n            Kind: keyboard\n         5: unknown:1E00           {1E00} V0    hidden\n         6: KEYBOARD LAYOUT 2      {4540} V0\n         7: unknown:1EB0           {1EB0} V0    internal, hidden\n         8: REPORT RATE            {8060} V0\n            Polling Rate (ms): 1\n            Polling Rate (ms)        : 1\n         9: DFUCONTROL SIGNED      {00C2} V0\n        10: unknown:1801           {1801} V0    internal, hidden\n        11: DEVICE RESET           {1802} V0    internal, hidden\n        12: COLOR LED EFFECTS      {8070} V5\n        13: unknown:1821           {1821} V0\n        14: REPORT HID USAGE       {1BC0} V0\n     Battery: N/A, None.\n"
  },
  {
    "path": "docs/devices/G304 Lightspeed Wireless Gaming Mouse 4074.txt",
    "content": "solaar version 1.1.8\n\n\n  1: G304 Lightspeed Wireless Gaming Mouse\n     Device path  : /dev/hidraw6\n     WPID         : 4074\n     Codename     : G304\n     Kind         : mouse\n     Protocol     : HID++ 4.2\n     Polling rate : 8 ms (125Hz)\n     Serial number: B2D05D23\n     Model ID:      407400000000\n     Unit ID:       EB490C63\n        Bootloader: BOT 69.02.B0021\n          Firmware: RQM 68.02.B0021\n     The power switch is located on the base.\n     Supports 27 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Bootloader BOT 69.02.B0021 4074452F3940\n            Firmware: Firmware RQM 68.02.B0021 4074452F3940\n            Unit ID: EB490C63  Model ID: 407400000000  Transport IDs: {'wpid': '4074'}\n         3: DEVICE NAME            {0005} V0\n            Name: G304 Lightspeed Wireless Gaming Mouse\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: BATTERY STATUS         {1000} V0\n            Battery: 90%, discharging, next level 50%.\n         6: COLOR LED EFFECTS      {8070} V6\n         7: ONBOARD PROFILES       {8100} V0\n            Device Mode: Host\n            Onboard Profiles (saved): Disable\n            Onboard Profiles        : Disable\n         8: MOUSE BUTTON SPY       {8110} V0\n         9: REPORT RATE            {8060} V0\n            Polling Rate (ms): 8\n            Polling Rate (ms) (saved): 8\n            Polling Rate (ms)        : 8\n        10: MODE STATUS            {8090} V1\n        11: DFUCONTROL SIGNED      {00C2} V0\n        12: DEVICE RESET           {1802} V0    internal, hidden\n        13: unknown:1803           {1803} V0    internal, hidden\n        14: CONFIG DEVICE PROPS    {1806} V4    internal, hidden\n        15: unknown:1811           {1811} V0    internal, hidden\n        16: OOBSTATE               {1805} V0    internal, hidden\n        17: unknown:1830           {1830} V0    internal, hidden\n        18: unknown:1890           {1890} V0    internal, hidden\n        19: unknown:1DF3           {1DF3} V0    internal, hidden\n        20: unknown:1E00           {1E00} V0    hidden\n        21: unknown:1EB0           {1EB0} V0    internal, hidden\n        22: unknown:1861           {1861} V0    internal, hidden\n        23: unknown:18B1           {18B1} V0    internal, hidden\n        24: unknown:1E22           {1E22} V0    internal, hidden\n        25: unknown:1801           {1801} V0    internal, hidden\n        26: ADJUSTABLE DPI         {2201} V1\n            Sensitivity (DPI) (saved): 2200\n            Sensitivity (DPI)        : 2200\n     Battery: 90%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/G305 Lightspeed Wireless Gaming Mouse 4074.text",
    "content": "solaar version 1.1.10\n\n  1: G305 Lightspeed Wireless Gaming Mouse\n     Device path  : /dev/hidraw7\n     WPID         : 4074\n     Codename     : G305\n     Kind         : mouse\n     Protocol     : HID++ 4.2\n     Polling rate : 1 ms (1000Hz)\n     Serial number: ED5E9515\n     Model ID:      407400000000\n     Unit ID:       F074D567\n        Bootloader: BOT 69.02.B0021\n          Firmware: RQM 68.02.B0021\n     The power switch is located on the base.\n     Supports 27 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Bootloader BOT 69.02.B0021 4074452F3940\n            Firmware: Firmware RQM 68.02.B0021 4074452F3940\n            Unit ID: F074D567  Model ID: 407400000000  Transport IDs: {'wpid': '4074'}\n         3: DEVICE NAME            {0005} V0\n            Name: G305 Lightspeed Wireless Gaming Mouse\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: BATTERY STATUS         {1000} V0\n            Battery: 50%, discharging, next level 30%.\n         6: COLOR LED EFFECTS      {8070} V6\n         7: ONBOARD PROFILES       {8100} V0\n            Device Mode: On-Board\n            Onboard Profiles (saved): Enable\n            Onboard Profiles        : Enable\n         8: MOUSE BUTTON SPY       {8110} V0\n         9: REPORT RATE            {8060} V0\n            Polling Rate (ms): 1\n            Polling Rate (ms) (saved): 1\n            Polling Rate (ms)        : 1\n        10: MODE STATUS            {8090} V1\n        11: DFUCONTROL SIGNED      {00C2} V0\n        12: DEVICE RESET           {1802} V0    internal, hidden\n        13: unknown:1803           {1803} V0    internal, hidden\n        14: CONFIG DEVICE PROPS    {1806} V4    internal, hidden\n        15: unknown:1811           {1811} V0    internal, hidden\n        16: OOBSTATE               {1805} V0    internal, hidden\n        17: unknown:1830           {1830} V0    internal, hidden\n        18: unknown:1890           {1890} V0    internal, hidden\n        19: unknown:1DF3           {1DF3} V0    internal, hidden\n        20: unknown:1E00           {1E00} V0    hidden\n        21: unknown:1EB0           {1EB0} V0    internal, hidden\n        22: unknown:1861           {1861} V0    internal, hidden\n        23: unknown:18B1           {18B1} V0    internal, hidden\n        24: unknown:1E22           {1E22} V0    internal, hidden\n        25: unknown:1801           {1801} V0    internal, hidden\n        26: ADJUSTABLE DPI         {2201} V1\n            Sensitivity (DPI) (saved): 1600\n            Sensitivity (DPI)        : 1600\n     Battery: 50%, discharging, next level 30%.\n"
  },
  {
    "path": "docs/devices/G502 Gaming Mouse C07D.text",
    "content": "Solaar version 1.1.5\n\n  1: G502 Gaming Mouse\n     Device path  : /dev/hidraw1\n     USB id       : 046d:C07D\n     Codename     : G502\n     Kind         : mouse\n     Protocol     : HID++ 4.2\n     Polling rate : 1 ms (1000Hz)\n     Serial number:\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: U   88.02.B0017\n        Bootloader: BOT 14.00.B0007\n          Hardware: 72\n             Other:\n     Supports 19 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: FEATURE INFO           {0002} V0\n         3: DEVICE FW VERSION      {0003} V0\n            Firmware: Firmware U   88.02.B0017\n            Firmware: Bootloader BOT 14.00.B0007\n            Firmware: Hardware  72\n            Firmware: Other\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         4: DEVICE NAME            {0005} V0\n            Name: Tunable FPS Gaming Mouse G502\n            Kind: mouse\n         5: LED CONTROL            {1300} V0\n         6: unknown:18A1           {18A1} V0    internal, hidden\n         7: unknown:1E00           {1E00} V0    hidden\n         8: unknown:1E20           {1E20} V0\n         9: unknown:1EB0           {1EB0} V0    internal, hidden\n        10: ADJUSTABLE DPI         {2201} V0\n            Sensitivity (DPI)        : 800\n        11: ANGLE SNAPPING         {2230} V0\n        12: SURFACE TUNING         {2240} V0\n        13: REPORT RATE            {8060} V0\n            Polling Rate (ms): 1\n            Polling Rate (ms)        : 1\n        14: ONBOARD PROFILES       {8100} V0\n            Device Mode: Host\n            Onboard Profiles        : Disable\n        15: MOUSE BUTTON SPY       {8110} V0\n        16: unknown:1850           {1850} V0    internal, hidden\n        17: DFUCONTROL UNSIGNED    {00C1} V0\n        18: unknown:1801           {1801} V0    internal, hidden\n     Battery: N/A, None.\n"
  },
  {
    "path": "docs/devices/G502 Lightspeed Wireless Gaming Mouse 407F.txt",
    "content": "solaar version 1.1.12rc1\n\n  1: G502 Gaming Mouse\n     Device path  : /dev/hidraw20\n     WPID         : 407F\n     Codename     : G502\n     Kind         : mouse\n     Protocol     : HID++ 4.2\n     Report Rate : 1ms\n     Serial number: DDDAADBC\n     Model ID:      407FC08D0000\n     Unit ID:       DDDAADBC\n                 1: BOT 92.00.B0008\n                 0: MPM 17.00.B0008\n                 3:\n     The power switch is located on the base.\n     Supports 30 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Bootloader BOT 92.00.B0008 AAEF21F1FA5F\n            Firmware: Firmware MPM 17.00.B0008 407F21F1FA5F\n            Firmware: Other\n            Unit ID: DDDAADBC  Model ID: 407FC08D0000  Transport IDs: {'wpid': '407F', 'usbid': 'C08D'}\n         3: DEVICE NAME            {0005} V0\n            Name: G502 LIGHTSPEED Wireless Gaming Mouse\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n            Configuration: 11000000000000000000000000000000\n         6: BATTERY VOLTAGE        {1001} V2\n            Battery: 90% 4166mV , discharging.\n         7: COLOR LED EFFECTS      {8070} V4\n            LED Control (saved): Device\n            LED Control        : Device\n            LEDs Primary (saved): !LEDEffectSetting {ID: 1, color: 16711680, intensity: 0, period: 100, ramp: 0, speed: 0}\n            LEDs Primary        : None\n            LEDs Logo        : None\n         8: LED CONTROL            {1300} V0\n         9: ONBOARD PROFILES       {8100} V0\n            Device Mode: On-Board\n            Onboard Profiles (saved): Profile 1\n            Onboard Profiles        : Profile 1\n        10: MOUSE BUTTON SPY       {8110} V0\n        11: REPORT RATE            {8060} V0\n            Report Rate: 1ms\n            Report Rate (saved): 1ms\n            Report Rate        : 1ms\n        12: ADJUSTABLE DPI         {2201} V1\n            Sensitivity (DPI) (saved): 900\n            Sensitivity (DPI)        : 900\n        13: DEVICE RESET           {1802} V0    internal, hidden\n        14: unknown:1803           {1803} V0    internal, hidden\n        15: OOBSTATE               {1805} V0    internal, hidden\n        16: CONFIG DEVICE PROPS    {1806} V4    internal, hidden\n        17: unknown:1811           {1811} V0    internal, hidden\n        18: unknown:1830           {1830} V0    internal, hidden\n        19: unknown:1890           {1890} V4    internal, hidden\n        20: unknown:1891           {1891} V4    internal, hidden\n        21: unknown:18A1           {18A1} V0    internal, hidden\n        22: unknown:1801           {1801} V0    internal, hidden\n        23: unknown:18B1           {18B1} V0    internal, hidden\n        24: unknown:1DF3           {1DF3} V0    internal, hidden\n        25: unknown:1E00           {1E00} V0    hidden\n        26: unknown:1EB0           {1EB0} V0    internal, hidden\n        27: unknown:1863           {1863} V0    internal, hidden\n        28: unknown:1E22           {1E22} V0    internal, hidden\n        29: HIRES WHEEL            {2121} V0\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            High resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): True\n            Scroll Wheel Resolution        : True\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n     Battery: 90% 4166mV , discharging.\n"
  },
  {
    "path": "docs/devices/G502 Proteus Spectrum Optical Mouse C332.txt",
    "content": "solaar version 1.1.9\n\n2: G502 Proteus Spectrum Optical Mouse\nDevice path  : /dev/hidraw4\nUSB id       : 046d:C332\nCodename     : G502 Proteus Spectrum\nKind         : mouse\nProtocol     : HID++ 4.2\nPolling rate : 1 ms (1000Hz)\nSerial number:\nModel ID:      C33200000000\nUnit ID:       31374706\nFirmware: U1  03.02.B0012\nBootloader: BOT 14.00.B0007\nSupports 20 HID++ 2.0 features:\n0: ROOT                   {0000} V0\n1: FEATURE SET            {0001} V0\n2: COLOR LED EFFECTS      {8070} V3\n3: DEVICE FW VERSION      {0003} V1\nFirmware: Firmware U1  03.02.B0012 C332\nFirmware: Bootloader BOT 14.00.B0007 AABF\nUnit ID: 31374706  Model ID: C33200000000  Transport IDs: {'usbid': 'C332'}\n4: DEVICE NAME            {0005} V0\nName: Tunable RGB Gaming Mouse G502\nKind: mouse\n5: LED CONTROL            {1300} V0\n6: unknown:18A1           {18A1} V0    internal, hidden\n7: unknown:1E00           {1E00} V0    hidden\n8: unknown:1E20           {1E20} V0\n9: unknown:1EB0           {1EB0} V0    internal, hidden\n10: ADJUSTABLE DPI         {2201} V1\nSensitivity (DPI) (saved): 7000\nSensitivity (DPI)        : 7000\n11: ANGLE SNAPPING         {2230} V0\n12: SURFACE TUNING         {2240} V0\n13: REPORT RATE            {8060} V0\nPolling Rate (ms): 1\nPolling Rate (ms) (saved): 1\nPolling Rate (ms)        : 1\n14: ONBOARD PROFILES       {8100} V0\nDevice Mode: On-Board\nOnboard Profiles (saved): Enable\nOnboard Profiles        : Enable\n15: MOUSE BUTTON SPY       {8110} V0\n16: unknown:1850           {1850} V0    internal, hidden\n17: DFUCONTROL UNSIGNED    {00C1} V0\n18: unknown:1801           {1801} V0    internal, hidden\n19: DEVICE RESET           {1802} V0    internal, hidden\nBattery status unavailable.\n"
  },
  {
    "path": "docs/devices/G502 SE Hero Gaming Mouse C08B.txt",
    "content": "1: G502 SE Hero Gaming Mouse\n     Device path  : /dev/hidraw7\n     USB id       : 046d:C08B\n     Codename     : G502 Hero\n     Kind         : mouse\n     Protocol     : HID++ 4.2\n     Polling rate : 1 ms (1000Hz)\n     Serial number:\n     Model ID:      C08B00000000\n     Unit ID:       30324703\n          Firmware: U1  27.03.B0010\n        Bootloader: BOT 81.00.B0002\n     Supports 19 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: COLOR LED EFFECTS      {8070}\n         3: DEVICE FW VERSION      {0003}\n            Firmware: Firmware U1  27.03.B0010 C08B\n            Firmware: Bootloader BOT 81.00.B0002 AAE6\n            Unit ID: 30324703  Model ID: C08B00000000  Transport IDs: {'usbid': 'C08B'}\n         4: DEVICE NAME            {0005}\n            Name: G502 HERO Gaming Mouse\n            Kind: mouse\n         5: LED CONTROL            {1300}\n         6: unknown:18A1           {18A1}   internal, hidden\n         7: unknown:1E00           {1E00}   hidden\n         8: unknown:1E22           {1E22}   internal, hidden\n         9: unknown:1EB0           {1EB0}   internal, hidden\n        10: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 2400\n            Sensitivity (DPI)        : 2400\n        11: REPORT RATE            {8060}\n            Polling Rate (ms): 1\n            Polling Rate (ms) (saved): 1\n            Polling Rate (ms)        : 1\n        12: ONBOARD PROFILES       {8100}\n            Device Mode: Host\n        13: MOUSE BUTTON SPY       {8110}\n        14: DFUCONTROL SIGNED      {00C2}\n        15: unknown:1801           {1801}   internal, hidden\n        16: DEVICE RESET           {1802}   internal, hidden\n        17: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        18: unknown:18B1           {18B1}   internal, hidden\n     Battery status unavailable.\n"
  },
  {
    "path": "docs/devices/G502 X C099.txt",
    "content": "Solaar version 1.1.7\n\n  1: G502 X\n     Device path  : /dev/hidraw2\n     USB id       : 046d:C099\n     Codename     : G502\n     Kind         : mouse\n     Protocol     : HID++ 4.2\n     Polling rate : 1 ms (1000Hz)\n     Serial number:\n     Model ID:      C09900000000\n     Unit ID:       42004C00\n        Bootloader: BL1 59.00.B0002\n          Firmware: U1  60.00.B0009\n     Supports 22 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BL1 59.00.B0002 AB17\n            Firmware: Firmware U1  60.00.B0009 C099\n            Unit ID: 42004C00  Model ID: C09900000000  Transport IDs: {'usbid': 'C099'}\n         3: DEVICE NAME            {0005} V0\n            Name: G502 X\n            Kind: mouse\n         4: RESET                  {0020} V0\n         5: DFUCONTROL SIGNED      {00C2} V0\n         6: unknown:1801           {1801} V0    internal, hidden, unknown:000010\n         7: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010\n         8: OOBSTATE               {1805} V0    internal, hidden\n         9: CONFIG DEVICE PROPS    {1806} V8    internal, hidden, unknown:000010\n        10: unknown:1875           {1875} V0    internal, hidden, unknown:000010\n        11: unknown:18A1           {18A1} V0    internal, hidden, unknown:000010\n        12: unknown:18B1           {18B1} V0    internal, hidden, unknown:000010\n        13: unknown:18C0           {18C0} V0    internal, hidden, unknown:000010\n        14: unknown:1E00           {1E00} V0    hidden\n        15: unknown:1E22           {1E22} V0    internal, hidden, unknown:000010\n        16: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010\n        17: HIRES WHEEL            {2121} V1\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            High resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): True\n            Scroll Wheel Resolution        : True\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        18: ADJUSTABLE DPI         {2201} V2\n            Sensitivity (DPI) (saved): 1600\n            Sensitivity (DPI)        : 1600\n        19: REPORT RATE            {8060} V0\n            Polling Rate (ms): 1\n            Polling Rate (ms) (saved): 1\n            Polling Rate (ms)        : 1\n        20: ONBOARD PROFILES       {8100} V0\n            Device Mode: On-Board\n            Onboard Profiles (saved): Enable\n            Onboard Profiles        : Enable\n        21: MOUSE BUTTON SPY       {8110} V0\n     Battery status unavailable.\n"
  },
  {
    "path": "docs/devices/G502 X PLUS 4099.txt",
    "content": "solaar version 1.1.19-25-g7520c9cc\n\n  1: G502 X PLUS\n     Device path  : /dev/hidraw8\n     WPID         : 4099\n     Codename     : G502 X PLUS\n     Kind         : mouse\n     Protocol     : HID++ 4.2\n     Report Rate : 1ms\n     Serial number: C6884511\n     Model ID:      4099C0950000\n     Unit ID:       C6884511\n                 1: BL1 42.00.B0016\n                 0: MPM 27.00.B0016\n                 3:\n                 3:\n                 3:\n                 3:\n                 3:\n                 3:\n                 3:\n                 3:\n                 3:\n                 3:\n     The power switch is located on the unknown.\n     Supports 32 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: 1 BL1 42.00.B0016 AB0BFBB13A33\n            Firmware: 0 MPM 27.00.B0016 4099FBB13A33\n            Firmware: 3\n            Firmware: 3\n            Firmware: 3\n            Firmware: 3\n            Firmware: 3\n            Firmware: 3\n            Firmware: 3\n            Firmware: 3\n            Firmware: 3\n            Firmware: 3\n            Unit ID: C6884511  Model ID: 4099C0950000  Transport IDs: {'wpid': '4099', 'usbid': 'C095'}\n         3: DEVICE NAME            {0005} V0\n            Name: G502 X PLUS\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n            Configuration: 11000000000000000000000000000000\n         6: UNIFIED BATTERY        {1004} V3\n            Battery: 77%, BatteryStatus.DISCHARGING.\n         7: ADJUSTABLE DPI         {2201} V2\n            Sensitivity (DPI) (saved): 800\n            Sensitivity (DPI)        : 800\n         8: HIRES WHEEL            {2121} V0\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            Low resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): False\n            Scroll Wheel Resolution        : False\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n         9: RGB EFFECTS            {8071} V2\n            LED Control (saved): Solaar\n            LED Control        : Solaar\n            LEDs Primary (saved): !LEDEffectSetting {ID: 0, color: 10820909, intensity: 0, period: 100, ramp: 0, speed: 0}\n            LEDs Primary        : !LEDEffectSetting {ID: 0, color: 10820909, intensity: 0, period: 100, ramp: 0, speed: 0}\n        10: PER KEY LIGHTING V2    {8081} V2\n            Per-key Lighting (saved): {A:No change, B:No change, C:No change, D:No change, E:No change, F:No change, G:No change, H:No change}\n            Per-key Lighting        : {A:No change, B:No change, C:No change, D:No change, E:No change, F:No change, G:No change, H:No change}\n        11: ONBOARD PROFILES       {8100} V0\n            Device Mode: On-Board\n            Onboard Profiles (saved): Profile 1\n            Onboard Profiles        : Profile 1\n        12: MOUSE BUTTON SPY       {8110} V0\n        13: REPORT RATE            {8060} V0\n            Report Rate: 1ms\n            Report Rate (saved): 1ms\n            Report Rate        : 1ms\n        14: FORCE PAIRING          {1500} V0\n        15: DFU                    {00D0} V3\n        16: DEVICE RESET           {1802} V0\n        17: unknown:1803           {0318} V0    internal, hidden, unknown:000010\n        18: CONFIG DEVICE PROPS    {1806} V8\n        19: unknown:1811           {1118} V0    internal, hidden, unknown:000010\n        20: OOBSTATE               {1805} V0\n        21: unknown:1830           {3018} V0    internal, hidden, unknown:000010\n        22: unknown:1875           {7518} V0    internal, hidden, unknown:000010\n        23: unknown:1861           {6118} V0    internal, hidden, unknown:000010\n        24: unknown:1890           {9018} V0    internal, hidden, unknown:000008\n        25: unknown:18A1           {A118} V0    internal, hidden, unknown:000010\n        26: unknown:1801           {0118} V0    internal, hidden, unknown:000010\n        27: unknown:1E00           {001E} V0    hidden\n        28: unknown:1E22           {221E} V0    internal, hidden, unknown:000010\n        29: unknown:1EB0           {B01E} V0    internal, hidden, unknown:000010\n        30: unknown:18B1           {B118} V0    internal, hidden, unknown:000010\n        31: unknown:18C0           {C018} V0    internal, hidden, unknown:000010\n     Battery: 77%, BatteryStatus.DISCHARGING.\n"
  },
  {
    "path": "docs/devices/G515 LS TKL 40B4.text",
    "content": "solaar version 1.1.13+dfsg-1\n\n  1: G515 LS TKL\n     Device path  : None\n     WPID         : 40B4\n     Codename     : G515 LS TKL\n     Kind         : keyboard\n     Protocol     : HID++ 4.2\n     Report Rate : 8ms\n     Serial number: 54FEF928\n     Model ID:      B38940B4C355\n     Unit ID:       54FEF928\n                 1: BL2 19.01.B0011\n                 3:\n                 0: MPK 25.01.B0011\n                 3:\n     The power switch is located on the top right corner.\n     Supports 34 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V6\n            Firmware: Bootloader BL2 19.01.B0011 ABD580558692\n            Firmware: Other\n            Firmware: Firmware MPK 25.01.B0011 40B480558692\n            Firmware: Other\n            Unit ID: 54FEF928  Model ID: B38940B4C355  Transport IDs: {'btleid': 'B389', 'wpid': '40B4', 'usbid': 'C355'}\n         3: DEVICE NAME            {0005} V3\n            Name: G515 LS TKL\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n            Configuration: 11000000000000000000000000000000\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: G515 LS TKL\n         7: unknown:0011           {0011} V0\n         8: UNIFIED BATTERY        {1004} V5\n            Battery: 82%, discharging.\n         9: RGB EFFECTS            {8071} V4\n            LED Control (saved): Solaar\n            LED Control        : Solaar\n            LEDs Primary (saved): !LEDEffectSetting {ID: 1, color: 16776960, intensity: 26, period: 2167, ramp: 1, speed: 0}\n            LEDs Primary        : HID++ error {'number': 1, 'request': 2537, 'error': 7, 'params': b'\\x00'}\n        10: PER KEY LIGHTING V2    {8081} V0\n            Per-key Lighting (saved): {A:indian red, B:indian red, C:indian red, D:indian red, E:indian red, F:indian red, G:indian red, H:indian red, I:indian red, J:indian red, K:indian red, L:indian red, M:indian red, N:indian red, O:indian red, P:indian red, Q:indian red, R:indian red, S:indian red, T:indian red, U:indian red, V:indian red, W:indian red, X:indian red, Y:indian red, Z:indian red, 1:orange, 2:orange, 3:orange, 4:orange, 5:orange, 6:orange, 7:orange, 8:orange, 9:orange, 0:yellow, ENTER:green, ESC:green, BACKSPACE:red, TAB:yellow, SPACE:yellow, -:indian red, =:indian red, [:indian red, \\:indian red, KEY 46:white, ~:indian red, ;:indian red, ':indian red, `:indian red, ,:indian red, .:indian red, /:indian red, CAPS LOCK:red, F1:indian red, F2:indian red, F3:indian red, F4:indian red, F5:indian red, F6:indian red, F7:indian red, F8:indian red, F9:indian red, F10:indian red, F11:indian red, F12:indian red, PRINT:red, SCROLL LOCK:orange, PASTE:indian red, INSERT:green, HOME:indian red, PAGE UP:yellow, DELETE:red, END:indian red, PAGE DOWN:yellow, RIGHT:indian red, LEFT:indian red, DOWN:indian red, UP:indian red, KEY 97:indian red, COMPOSE:white, POWER:white, KEY 100:indian red, KEY 101:red, KEY 102:red, KEY 103:red, LEFT CTRL:indian red, LEFT SHIFT:yellow, LEFT ALT:indian red, LEFT WINDOWS:blue, RIGHT CTRL:indian red, RIGHT SHIFT:yellow, RIGHT ALTGR:blue, RIGHT WINDOWS:indian red, KEY 254:white}\n            Per-key Lighting        : {A:No change, B:No change, C:No change, D:No change, E:No change, F:No change, G:No change, H:No change, I:No change, J:No change, K:No change, L:No change, M:No change, N:No change, O:No change, P:No change, Q:No change, R:No change, S:No change, T:No change, U:No change, V:No change, W:No change, X:No change, Y:No change, Z:No change, 1:No change, 2:No change, 3:No change, 4:No change, 5:No change, 6:No change, 7:No change, 8:No change, 9:No change, 0:No change, ENTER:No change, ESC:No change, BACKSPACE:No change, TAB:No change, SPACE:No change, -:No change, =:No change, [:No change, \\:No change, KEY 46:No change, ~:No change, ;:No change, ':No change, `:No change, ,:No change, .:No change, /:No change, CAPS LOCK:No change, F1:No change, F2:No change, F3:No change, F4:No change, F5:No change, F6:No change, F7:No change, F8:No change, F9:No change, F10:No change, F11:No change, F12:No change, PRINT:No change, SCROLL LOCK:No change, PASTE:No change, INSERT:No change, HOME:No change, PAGE UP:No change, DELETE:No change, END:No change, PAGE DOWN:No change, RIGHT:No change, LEFT:No change, DOWN:No change, UP:No change, KEY 97:No change, COMPOSE:No change, POWER:No change, KEY 100:No change, KEY 101:No change, KEY 102:No change, KEY 103:No change, LEFT CTRL:No change, LEFT SHIFT:No change, LEFT ALT:No change, LEFT WINDOWS:No change, RIGHT CTRL:No change, RIGHT SHIFT:No change, RIGHT ALTGR:No change, RIGHT WINDOWS:No change, KEY 254:No change}\n        11: unknown:1B10           {1B10} V0\n        12: unknown:4523           {4523} V1\n        13: KEYBOARD LAYOUT 2      {4540} V1\n        14: BRIGHTNESS CONTROL     {8040} V0\n            Brightness Control (saved): 40\n            Brightness Control        : 40\n        15: unknown:8101           {8101} V0\n        16: unknown:1B05           {1B05} V0\n        17: unknown:8051           {8051} V0\n        18: DFU                    {00D0} V3\n        19: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010\n        20: unknown:1803           {1803} V1    internal, hidden, unknown:000010\n        21: unknown:1807           {1807} V3    internal, hidden, unknown:000010\n        22: unknown:1817           {1817} V0    internal, hidden, unknown:000010\n        23: OOBSTATE               {1805} V0    internal, hidden\n        24: unknown:1830           {1830} V0    internal, hidden, unknown:000010\n        25: unknown:1890           {1890} V9    internal, hidden, unknown:000008\n        26: unknown:1891           {1891} V9    internal, hidden, unknown:000008\n        27: unknown:1E00           {1E00} V0    hidden\n        28: unknown:1E02           {1E02} V0    internal, hidden\n        29: unknown:1602           {1602} V0\n        30: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010\n        31: unknown:1861           {1861} V1    internal, hidden, unknown:000010\n        32: unknown:18B0           {18B0} V1    internal, hidden, unknown:000010\n        33: unknown:1801           {1801} V0    internal, hidden, unknown:000010\n     Battery: 82%, discharging.\n"
  },
  {
    "path": "docs/devices/G535 Wireless Gaming Headset 0AC4.txt",
    "content": "solaar version 1.1.8\n\nUSB and Bluetooth Devices\n\n  1: G535 Wireless Gaming Headset\n     Device path  : /dev/hidraw2\n     USB id       : 046d:0AC4\n     Codename     : G535\n     Kind         : ?\n     Protocol     : HID++ 4.2\n     Serial number:\n     Model ID:      000000000AC4\n     Unit ID:       FFFFFFFF\n          Firmware: U1  90.00.B0200\n     Supports 6 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Firmware U1  90.00.B0200 0AC4\n            Unit ID: FFFFFFFF  Model ID: 000000000AC4  Transport IDs: {'btid': '0000', 'btleid': '0000'}\n         3: DEVICE NAME            {0005} V0\n            Name: G535 Wireless Gaming Headset\n            Kind: None\n         4: SIDETONE               {8300} V0\n            Sidetone (saved): 0\n            Sidetone        : 0\n         5: ADC MEASUREMENT        {1F20} V0\n            Battery: 60% 3920mV , discharging.\n     Battery: 60% 3920mV , discharging.\n"
  },
  {
    "path": "docs/devices/G600 Gaming Mouse C24A.txt",
    "content": "This mouse does not use HID++\n\n\n[root@gpiro device]# lsusb -vv -d 046d:c24a\n\nBus 003 Device 002: ID 046d:c24a Logitech, Inc. G600 Gaming Mouse\nDevice Descriptor:\n  bLength                18\n  bDescriptorType         1\n  bcdUSB               2.00\n  bDeviceClass            0\n  bDeviceSubClass         0\n  bDeviceProtocol         0\n  bMaxPacketSize0        32\n  idVendor           0x046d Logitech, Inc.\n  idProduct          0xc24a G600 Gaming Mouse\n  bcdDevice           77.02\n  iManufacturer           1 Logitech\n  iProduct                2 Gaming Mouse G600\n  iSerial                 3 385226BFEFD20017\n  bNumConfigurations      1\n  Configuration Descriptor:\n    bLength                 9\n    bDescriptorType         2\n    wTotalLength       0x003b\n    bNumInterfaces          2\n    bConfigurationValue     1\n    iConfiguration          4 U77.02_B0017\n    bmAttributes         0xa0\n      (Bus Powered)\n      Remote Wakeup\n    MaxPower              500mA\n    Interface Descriptor:\n      bLength                 9\n      bDescriptorType         4\n      bInterfaceNumber        0\n      bAlternateSetting       0\n      bNumEndpoints           1\n      bInterfaceClass         3 Human Interface Device\n      bInterfaceSubClass      1 Boot Interface Subclass\n      bInterfaceProtocol      2 Mouse\n      iInterface              0\n        HID Device Descriptor:\n          bLength                 9\n          bDescriptorType        33\n          bcdHID               1.11\n          bCountryCode            0 Not supported\n          bNumDescriptors         1\n          bDescriptorType        34 Report\n          wDescriptorLength      67\n         Report Descriptors:\n           ** UNAVAILABLE **\n      Endpoint Descriptor:\n        bLength                 7\n        bDescriptorType         5\n        bEndpointAddress     0x81  EP 1 IN\n        bmAttributes            3\n          Transfer Type            Interrupt\n          Synch Type               None\n          Usage Type               Data\n        wMaxPacketSize     0x0009  1x 9 bytes\n        bInterval               1\n    Interface Descriptor:\n      bLength                 9\n      bDescriptorType         4\n      bInterfaceNumber        1\n      bAlternateSetting       0\n      bNumEndpoints           1\n      bInterfaceClass         3 Human Interface Device\n      bInterfaceSubClass      0\n      bInterfaceProtocol      1 Keyboard\n      iInterface              0\n        HID Device Descriptor:\n          bLength                 9\n          bDescriptorType        33\n          bcdHID               1.11\n          bCountryCode            0 Not supported\n          bNumDescriptors         1\n          bDescriptorType        34 Report\n          wDescriptorLength     135\n         Report Descriptors:\n           ** UNAVAILABLE **\n      Endpoint Descriptor:\n        bLength                 7\n        bDescriptorType         5\n        bEndpointAddress     0x82  EP 2 IN\n        bmAttributes            3\n          Transfer Type            Interrupt\n          Synch Type               None\n          Usage Type               Data\n        wMaxPacketSize     0x0020  1x 32 bytes\n        bInterval               1\ncan't get device qualifier: Resource temporarily unavailable\ncan't get debug descriptor: Resource temporarily unavailable\nDevice Status:     0x0000\n  (Bus Powered)\n\n/sys/devices/pci0000:00/0000:00:08.1/0000:05:00.4/usb3/3-2/3-2:1.1/0003:046D:C24A.0007/report_descriptor\nUsage Page (Desktop),               ; Generic desktop controls (01h)\nUsage (Keyboard),                   ; Keyboard (06h, application collection)\nCollection (Application),\n    Report ID (1),\n    Usage Page (Keyboard),          ; Keyboard/keypad (07h)\n    Usage Minimum (KB Leftcontrol), ; Keyboard left control (E0h, dynamic value)\n    Usage Maximum (KB Right GUI),   ; Keyboard right GUI (E7h, dynamic value)\n    Logical Minimum (0),\n    Logical Maximum (1),\n    Report Size (1),\n    Report Count (8),\n    Input (Variable),\n    Report Size (8),\n    Report Count (5),\n    Logical Minimum (0),\n    Logical Maximum (164),\n    Usage Minimum (None),           ; No event (00h, selector)\n    Usage Maximum (KB ExSel),       ; Keyboard ExSel (A4h, selector)\n    Input,\nEnd Collection,\nUsage Page (FF80h),                 ; FF80h, vendor-defined\nUsage (80h),\nCollection (Application),\n    Report ID (128),\n    Usage (80h),\n    Report Size (8),\n    Report Count (5),\n    Input (Variable),\n    Report ID (246),\n    Usage (F6h),\n    Report Size (8),\n    Report Count (7),\n    Input (Variable),\n    Report ID (240),\n    Usage (F0h),\n    Report Count (3),\n    Feature (Variable),\n    Report ID (241),\n    Usage (F1h),\n    Report Count (7),\n    Feature (Variable),\n    Report ID (242),\n    Usage (F2h),\n    Report Count (4),\n    Feature (Variable),\n    Report ID (243),\n    Usage (F3h),\n    Report Count (153),\n    Feature (Variable),\n    Report ID (244),\n    Usage (F4h),\n    Report Count (153),\n    Feature (Variable),\n    Report ID (245),\n    Usage (F5h),\n    Report Count (153),\n    Feature (Variable),\n    Report ID (246),\n    Usage (F6h),\n    Report Count (7),\n    Feature (Variable),\n    Report ID (247),\n    Usage (F7h),\n    Report Size (8),\n    Report Count (31),\n    Input (Variable),\nEnd Collection\n\n/sys/devices/pci0000:00/0000:00:08.1/0000:05:00.4/usb3/3-2/3-2:1.0/0003:046D:C24A.0006/report_descriptor\nUsage Page (Desktop),               ; Generic desktop controls (01h)\nUsage (Mouse),                      ; Mouse (02h, application collection)\nCollection (Application),\n    Usage (Pointer),                ; Pointer (01h, physical collection)\n    Collection (Physical),\n        Usage Page (Button),        ; Button (09h)\n        Usage Minimum (01h),\n        Usage Maximum (10h),\n        Logical Minimum (0),\n        Logical Maximum (1),\n        Report Size (1),\n        Report Count (16),\n        Input (Variable),\n        Usage Page (Desktop),       ; Generic desktop controls (01h)\n        Usage (X),                  ; X (30h, dynamic value)\n        Usage (Y),                  ; Y (31h, dynamic value)\n        Logical Minimum (-32767),\n        Logical Maximum (32767),\n        Report Size (16),\n        Report Count (2),\n        Input (Variable, Relative),\n        Usage (Wheel),              ; Wheel (38h, dynamic value)\n        Report Size (8),\n        Report Count (1),\n        Logical Minimum (-127),\n        Logical Maximum (127),\n        Input (Variable, Relative),\n        Usage Page (Consumer),      ; Consumer (0Ch)\n        Usage (AC Pan),             ; AC pan (0238h, linear control)\n        Report Count (1),\n        Input (Variable, Relative),\n    End Collection,\nEnd Collection\n"
  },
  {
    "path": "docs/devices/G604 Wireless Gaming Mouse 4085.txt",
    "content": "solaar version 03cfa128\n\n  1: G604 Wireless Gaming Mouse\n     Device path  : /dev/hidraw6\n     WPID         : 4085\n     Codename     : G604\n     Kind         : mouse\n     Protocol     : HID++ 4.2\n     Report Rate : 1ms\n     Serial number: XXXXXXXX\n     Model ID:      B02440850000\n     Unit ID:       XXXXXXXX\n                 1: BL1 04.01.B0014\n                 0: MPM 21.01.B0014\n                 3:\n     The power switch is located on the base.\n     Supports 33 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: 1 BL1 04.01.B0014 0000B01B3067\n            Firmware: 0 MPM 21.01.B0014 4085B01B3067\n            Firmware: 3\n            Unit ID: XXXXXXXX  Model ID: B02440850000  Transport IDs: {'btleid': 'B024', 'wpid': '4085'}\n         3: DEVICE NAME            {0005} V0\n            Name: G604 Wireless Gaming Mouse\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n            Configuration: 00000000000000000000000000000000\n         6: BATTERY STATUS         {1000} V0\n            Battery: 30%, BatteryStatus.DISCHARGING, next level 15%.\n         7: COLOR LED EFFECTS      {8070} V4\n            LED Control (saved): Device\n            LED Control        : Device\n            LEDs Primary        : None\n         8: LED CONTROL            {1300} V0\n         9: ONBOARD PROFILES       {8100} V0\n            Device Mode: On-Board\n            Onboard Profiles (saved): Profile 1\n            Onboard Profiles        : Profile 1\n        10: MOUSE BUTTON SPY       {8110} V0\n        11: REPORT RATE            {8060} V0\n            Report Rate: 1ms\n            Report Rate (saved): 1ms\n            Report Rate        : 1ms\n        12: ADJUSTABLE DPI         {2201} V1\n            Sensitivity (DPI) (saved): 800\n            Sensitivity (DPI)        : 800\n        13: DFUCONTROL SIGNED      {00C2} V0\n        14: DEVICE RESET           {1802} V0\n        15: unknown:1803           {0318} V0    internal, hidden\n        16: OOBSTATE               {1805} V0\n        17: CONFIG DEVICE PROPS    {1806} V4\n        18: unknown:1813           {1318} V0    internal, hidden\n        19: unknown:1830           {3018} V0    internal, hidden\n        20: unknown:1890           {9018} V0    internal, hidden\n        21: unknown:1891           {9118} V0    internal, hidden\n        22: unknown:1861           {6118} V0    internal, hidden\n        23: unknown:1801           {0118} V0    internal, hidden\n        24: unknown:18B1           {B118} V0    internal, hidden\n        25: unknown:1DF3           {F31D} V0    internal, hidden\n        26: unknown:1E00           {001E} V0    hidden\n        27: unknown:1EB0           {B01E} V0    internal, hidden\n        28: unknown:1E22           {221E} V0    internal, hidden\n        29: HIRES WHEEL            {2121} V0\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            High resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): True\n            Scroll Wheel Resolution        : True\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        30: unknown:18C0           {C018} V0    internal, hidden\n        31: CHANGE HOST            {1814} V1\n            Change Host        : 1:host1\n        32: HOSTS INFO             {1815} V1\n            Host 0 (unpaired): host1\n            Host 1 (paired):\n     Battery: 30%, BatteryStatus.DISCHARGING, next level 15%.\n"
  },
  {
    "path": "docs/devices/G613 Wireless Mechanical Gaming Keyboard 4065.txt",
    "content": "solaar version 1.1.19-25-g7520c9cc\n\n  1: G613 Wireless Mechanical Gaming Keyboard\n     Device path  : None\n     WPID         : 4065\n     Codename     : G613\n     Kind         : keyboard\n     Protocol     : HID++ 4.2\n     Report Rate : 1ms\n     Serial number: 710EC3A3\n     Model ID:      B34F40650000\n     Unit ID:       2A923B25\n                 1: BOT 46.00.B0006\n                 0: MPK 05.02.B0021\n                 3:\n     The power switch is located on the unknown.\n     Supports 32 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: 1 BOT 46.00.B0006 00006E86A7BD\n            Firmware: 0 MPK 05.02.B0021 40656E86A7BD\n            Firmware: 3\n            Unit ID: 2A923B25  Model ID: B34F40650000  Transport IDs: {'btleid': 'B34F', 'wpid': '4065'}\n         3: DEVICE NAME            {0005} V0\n            Name: G613 Wireless Mechanical Gaming Keyboard\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n            Configuration: 11000000000000000000000000000000\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: G613\n         7: BATTERY STATUS         {1000} V0\n            Battery: 80%, BatteryStatus.DISCHARGING, next level 50%.\n         8: CHANGE HOST            {1814} V1\n            Change Host        : 1:cosmo\n         9: HOSTS INFO             {1815} V1\n            Host 0 (paired): cosmo\n            Host 1 (paired): Mi 11\n        10: REPROG CONTROLS V4     {1B04} V3\n            Key/Button Diversion (saved): {Host Switch Channel 1:Regular, Host Switch Channel 2:Regular}\n            Key/Button Diversion        : {Host Switch Channel 1:Regular, Host Switch Channel 2:Regular}\n        11: REPORT HID USAGE       {1BC0} V1\n        12: ENCRYPTION             {4100} V0\n        13: KEYBOARD DISABLE BY USAGE {4522} V0\n        14: KEYBOARD LAYOUT 2      {4540} V0\n        15: GKEY                   {8010} V0\n            Divert G and M Keys (saved): False\n            Divert G and M Keys        : False\n        16: REPORT RATE            {8060} V0\n            Report Rate: 1ms\n            Report Rate (saved): 1ms\n            Report Rate        : 1ms\n        17: DFUCONTROL SIGNED      {00C2} V0\n        18: DEVICE RESET           {1802} V0\n        19: unknown:1803           {0318} V0    internal, hidden\n        20: CONFIG DEVICE PROPS    {1806} V3\n        21: unknown:1813           {1318} V0    internal, hidden\n        22: OOBSTATE               {1805} V0\n        23: unknown:1830           {3018} V0    internal, hidden\n        24: unknown:1890           {9018} V0    internal, hidden\n        25: unknown:1891           {9118} V0    internal, hidden\n        26: unknown:18A1           {A118} V0    internal, hidden\n        27: unknown:1DF3           {F31D} V0    internal, hidden\n        28: unknown:1E00           {001E} V0    hidden\n        29: unknown:1EB0           {B01E} V0    internal, hidden\n        30: unknown:1861           {6118} V0    internal, hidden\n        31: unknown:18B1           {B118} V0    internal, hidden\n     Has 2 reprogrammable keys:\n         0: Host Switch Channel 1     , default: Hostswitch Channel 1        => Hostswitch Channel 1\n             persistently_divertable, divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: Hostswitch Channel 2        => Hostswitch Channel 2\n             persistently_divertable, divertable, pos:2, group:0, group mask:empty\n             reporting: default\n     Battery: 80%, BatteryStatus.DISCHARGING, next level 50%.\n"
  },
  {
    "path": "docs/devices/G703 Wired-Wireless Gaming Mouse 4070.txt",
    "content": "  1: G703 Wired/Wireless Gaming Mouse\n     Codename     : G703\n     Kind         : mouse\n     Wireless PID : 4070\n     Protocol     : HID++ 4.2\n     Polling rate : 1 ms (1000Hz)\n     Serial number: AFE674F7\n          Firmware: MPM 14.02.B0007\n        Bootloader: BOT 64.02.B0007\n             Other:\n     The power switch is located on the base.\n     Supports 29 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n         3: DEVICE NAME            {0005}\n         4: BATTERY VOLTAGE        {1001}\n         5: unknown:1863           {1863}   internal, hidden\n         6: unknown:18A1           {18A1}   internal, hidden\n         7: unknown:1E00           {1E00}   hidden\n         8: unknown:1E20           {1E20}\n         9: unknown:1EB0           {1EB0}   internal, hidden\n        10: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI): 1600\n        11: ANGLE SNAPPING         {2230}\n        12: SURFACE TUNING         {2240}\n        13: REPORT RATE            {8060}\n        14: ONBOARD PROFILES       {8100}\n        15: MOUSE BUTTON SPY       {8110}\n        16: unknown:1850           {1850}   internal, hidden\n        17: DFUCONTROL SIGNED      {00C2}\n        18: unknown:1801           {1801}   internal, hidden\n        19: DEVICE RESET           {1802}   internal, hidden\n        20: unknown:1803           {1803}   internal, hidden\n        21: unknown:1890           {1890}   internal, hidden\n        22: unknown:1811           {1811}   internal, hidden\n        23: LATENCY MONITORING     {8111}\n        24: COLOR LED EFFECTS      {8070}\n        25: unknown:1809           {1809}\n        26: unknown:1830           {1830}   internal, hidden\n        27: OOBSTATE               {1805}   internal, hidden\n        28: CONFIG DEVICE PROPS    {1806}   internal, hidden\n     Battery: 3807mV, discharging, average\n"
  },
  {
    "path": "docs/devices/G733 Gaming Headset 0AB5.text",
    "content": "Solaar version 1.1.19\n\nG733 Gaming Headset\n     Device path  : /dev/hidraw0\n     USB id       : 046d:0AB5\n     Codename     : G733 Headset\n     Kind         : headset\n     Protocol     : HID++ 4.2\n     Serial number:\n     Model ID:      0AB500000000\n     Unit ID:       FFFFFFFF\n                 0: U1  37.00.B0131\n     Supports 9 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: 0 U1  37.00.B0131 0AB5\n            Unit ID: FFFFFFFF  Model ID: 0AB500000000  Transport IDs: {'usbid': '0AB5'}\n         3: DEVICE NAME            {0005} V0\n            Name: G733 Gaming Headset\n            Kind: None\n         4: COLOR LED EFFECTS      {8070} V3\n            Sterowanie diodami LED (saved): Device\n            Sterowanie diodami LED        : Device\n            Diody LED None (saved): !LEDEffectSetting {ID: 0}\n            Diody LED None        : !LEDEffectSetting {ID: 0}\n            Diody LED None (saved): !LEDEffectSetting {ID: 1, color: 131072, ramp: 0}\n            Diody LED None        : !LEDEffectSetting {ID: 1, color: 66048, ramp: 0}\n         5: GKEY                   {8010} V0\n            Przekieruj klawisze G i M (saved): False\n            Przekieruj klawisze G i M        : False\n         6: EQUALIZER              {8310} V1\n            Korektor (saved): {0: 5, 1: 4, 2: 3, 3: 5, 4: 5, 5: 5, 6: 4, 7: 3, 8: 4, 9: 5}\n            Korektor        : {0: 5, 1: 4, 2: 3, 3: 5, 4: 5, 5: 5, 6: 4, 7: 3, 8: 4, 9: 5}\n         7: SIDETONE               {8300} V0\n            Efekt lokalny (saved): 0\n            Efekt lokalny        : 0\n         8: ADC MEASUREMENT        {1F20} V4\n            Battery: 89% 4058mV , BatteryStatus.DISCHARGING.\n            Zarządzanie energią (saved): 30\n            Zarządzanie energią        : 30\n     Battery: 89% 4058mV , BatteryStatus.DISCHARGING.\n"
  },
  {
    "path": "docs/devices/G733 Gaming Headset 0AFE.text",
    "content": "solaar version 1.1.11\n\nG733 Gaming Headset\n     Device path  : /dev/hidraw3\n     USB id       : 046d:0AFE\n     Codename     : G733 Headset New\n     Kind         : headset\n     Protocol     : HID++ 4.2\n     Serial number:\n     Model ID:      0AFE00000000\n     Unit ID:       FFFFFFFF\n          Firmware: U2  00.06\n     Supports 9 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Firmware U2  00.06 0AFE\n            Unit ID: FFFFFFFF  Model ID: 0AFE00000000  Transport IDs: {'usbid': '0AFE'}\n         3: DEVICE NAME            {0005} V0\n            Name: G733 Gaming Headset\n            Kind: None\n         4: COLOR LED EFFECTS      {8070} V3\n            LED Control (saved): Device\n            LED Control        : Device\n            LEDs Logo (saved): !LEDEffectSetting {ID: 0x0}\n            LEDs Logo        : !LEDEffectSetting {ID: 0}\n            LEDs Primary (saved): !LEDEffectSetting {ID: 0x1, color: 0x0, ramp: 0x0}\n            LEDs Primary        : !LEDEffectSetting {ID: 1, color: 0x10000, ramp: 0x0}\n         5: GKEY                   {8010} V0\n            Divert G and M Keys (saved): False\n            Divert G and M Keys        : False\n         6: EQUALIZER              {8310} V1\n            Equalizer (saved): {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0}\n            Equalizer        : {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0}\n         7: SIDETONE               {8300} V0\n            Sidetone (saved): 0\n            Sidetone        : 0\n         8: ADC MEASUREMENT        {1F20} V4\n            Battery: 60% 3867mV , discharging.\n            Power Management (saved): 0\n            Power Management        : 0\n     Battery: 60% 3867mV , discharging.\n"
  },
  {
    "path": "docs/devices/G815 Mechanical Keyboard C33F.txt",
    "content": "solaar version 1.1.9\n\n1: G815 Mechanical Keyboard\nDevice path  : /dev/hidraw2\nUSB id       : 046d:C33F\nCodename     : G815\nKind         : keyboard\nProtocol     : HID++ 4.2\nPolling rate : 1 ms (1000Hz)\nSerial number:\nModel ID:      C33F00000000\nUnit ID:       35304716\nBootloader: BOT 84.00.B0003\nFirmware: U1  31.02.B0018\nOther:\nOther:\nOther:\nSupports 24 HID++ 2.0 features:\n0: ROOT                   {0000} V0\n1: FEATURE SET            {0001} V0\n2: DEVICE FW VERSION      {0003} V2\nFirmware: Bootloader BOT 84.00.B0003 AAEA\nFirmware: Firmware U1  31.02.B0018 C33F\nFirmware: Other\nFirmware: Other\nFirmware: Other\nUnit ID: 35304716  Model ID: C33F00000000  Transport IDs: {'usbid': 'C33F'}\n3: DEVICE NAME            {0005} V0\nName: G815 RGB MECHANICAL GAMING KEYBOARD\nKind: keyboard\n4: CONFIG CHANGE          {0020} V0\n5: DFUCONTROL SIGNED      {00C2} V0\n6: DFU                    {00D0} V0\n7: REPORT HID USAGE       {1BC0} V0\n8: KEYBOARD DISABLE BY USAGE {4522} V0\n9: KEYBOARD LAYOUT 2      {4540} V0\n10: GKEY                   {8010} V0\nDivert G Keys (saved): True\nDivert G Keys        : False\n11: MKEYS                  {8020} V0\nM-Key LEDs (saved): {M1:False, M2:False, M3:False}\nM-Key LEDs        : {M1:False, M2:False, M3:False}\n12: MR                     {8030} V0\nMR-Key LED (saved): False\nMR-Key LED        : False\n13: BRIGHTNESS CONTROL     {8040} V0\n14: REPORT RATE            {8060} V0\nPolling Rate (ms): 1\nPolling Rate (ms) (saved): 1\nPolling Rate (ms)        : 1\n15: RGB EFFECTS            {8071} V0\n16: PER KEY LIGHTING V2    {8081} V2\n17: ONBOARD PROFILES       {8100} V0\nDevice Mode: Host\nOnboard Profiles (saved): Disable\nOnboard Profiles        : Disable\n18: unknown:1801           {1801} V0    internal, hidden\n19: DEVICE RESET           {1802} V0    internal, hidden\n20: CONFIG DEVICE PROPS    {1806} V5    internal, hidden\n21: unknown:18B0           {18B0} V0    internal, hidden\n22: unknown:1E00           {1E00} V0    hidden\n23: unknown:1EB0           {1EB0} V0    internal, hidden\nBattery status unavailable.\n"
  },
  {
    "path": "docs/devices/G903 LIGHTSPEED Wireless Gaming Mouse 4087.txt",
    "content": "solaar version 1.1.8rc3+git1940-4e7b6b3\n\n  1: G903 LIGHTSPEED Wireless Gaming Mouse w/ HERO\n     Device path  : /dev/hidraw13\n     WPID         : 4087\n     Codename     : G903 LS\n     Kind         : mouse\n     Protocol     : HID++ 4.2\n     Polling rate : 1 ms (1000Hz)\n     Serial number: 3EF038B9\n     Model ID:      4087C0910000\n     Unit ID:       3EF038B9\n        Bootloader: BL1 06.01.B0013\n          Firmware: MPM 23.01.B0013\n             Other:\n     The power switch is located on the base.\n     Supports 31 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Bootloader BL1 06.01.B0013 0000047072FE\n            Firmware: Firmware MPM 23.01.B0013 4087047072FE\n            Firmware: Other\n            Unit ID: 3EF038B9  Model ID: 4087C0910000  Transport IDs: {'wpid': '4087', 'usbid': 'C091'}\n         3: DEVICE NAME            {0005} V0\n            Name: G903 LIGHTSPEED Wireless Gaming Mouse w/ HERO\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n         6: BATTERY VOLTAGE        {1001} V2\n            Battery: 90% 4079mV , discharging.\n         7: RGB EFFECTS            {8071} V0\n         8: ONBOARD PROFILES       {8100} V0\n            Device Mode: On-Board\n            Onboard Profiles (saved): Enable\n            Onboard Profiles        : Enable\n         9: MOUSE BUTTON SPY       {8110} V0\n        10: REPORT RATE            {8060} V0\n            Polling Rate (ms): 1\n            Polling Rate (ms) (saved): 1\n            Polling Rate (ms)        : 1\n        11: ADJUSTABLE DPI         {2201} V1\n            Sensitivity (DPI) (saved): 6400\n            Sensitivity (DPI)        : 6400\n        12: DFUCONTROL SIGNED      {00C2} V0\n        13: DEVICE RESET           {1802} V0    internal, hidden\n        14: unknown:1803           {1803} V0    internal, hidden\n        15: OOBSTATE               {1805} V0    internal, hidden\n        16: CONFIG DEVICE PROPS    {1806} V4    internal, hidden\n        17: unknown:1811           {1811} V0    internal, hidden\n        18: unknown:1830           {1830} V0    internal, hidden\n        19: unknown:1890           {1890} V4    internal, hidden\n        20: unknown:1891           {1891} V4    internal, hidden\n        21: unknown:18A1           {18A1} V0    internal, hidden\n        22: unknown:1801           {1801} V0    internal, hidden\n        23: unknown:18B1           {18B1} V0    internal, hidden\n        24: unknown:1DF3           {1DF3} V0    internal, hidden\n        25: unknown:1E00           {1E00} V0    hidden\n        26: unknown:1EB0           {1EB0} V0    internal, hidden\n        27: unknown:1863           {1863} V0    internal, hidden\n        28: unknown:1E22           {1E22} V0    internal, hidden\n        29: HIRES WHEEL            {2121} V0\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            Low resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): False\n            Scroll Wheel Resolution        : False\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        30: unknown:18C0           {18C0} V0    internal, hidden\n     Battery: 90% 4079mV , discharging.\n\n  7: Candy companion chip\n     Device path  : /dev/hidraw14\n     Codename     : Candy\n     Kind         : touchpad\n     Protocol     : HID++ 4.2\n     Serial number: 4E4E9946\n     Model ID:      405F00000000\n     Unit ID:       34304713\n          Firmware: CC  07.00.B0010\n        Bootloader: BOT 32.00.B0010\n     Supports 12 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Firmware CC  07.00.B0010 405F\n            Firmware: Bootloader BOT 32.00.B0010 405F\n            Unit ID: 34304713  Model ID: 405F00000000  Transport IDs: {'wpid': '405F'}\n         3: DEVICE NAME            {0005} V0\n            Name: Candy companion chip\n            Kind: touchpad\n         4: unknown:18A1           {18A1} V0    internal, hidden\n         5: unknown:1E00           {1E00} V0    hidden\n         6: unknown:1EB0           {1EB0} V0    internal, hidden\n         7: DFUCONTROL SIGNED      {00C2} V0\n         8: unknown:1801           {1801} V0    internal, hidden\n         9: DEVICE RESET           {1802} V0    internal, hidden\n        10: unknown:1803           {1803} V0    internal, hidden\n        11: COLOR LED EFFECTS      {8070} V4\n     Battery status unavailable.\n"
  },
  {
    "path": "docs/devices/G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard 408E.txt",
    "content": "Solaar version 1.1.4\n\n  1: G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard\n     Device path  : None\n     WPID         : 408E\n     Codename     : G915 TKL\n     Kind         : keyboard\n     Protocol     : HID++ 4.2\n     Polling rate : 1 ms (1000Hz)\n     Serial number: F085CB9D\n     Model ID:      B35F408EC343\n     Unit ID:       F085CB9D\n        Bootloader: BL1 12.00.B0017\n             Other:\n          Firmware: MPK 14.01.B0021\n             Other:\n             Other:\n     The power switch is located on the top left corner.\n     Supports 37 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BL1 12.00.B0017 00008B79E978\n            Firmware: Other\n            Firmware: Firmware MPK 14.01.B0021 408E5E599E54\n            Firmware: Other\n            Firmware: Other\n            Unit ID: F085CB9D  Model ID: B35F408EC343  Transport IDs: {'btleid': 'B35F', 'wpid': '408E', 'usbid': 'C343'}\n         3: DEVICE NAME            {0005}\n            Name: G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: G915 TKL\n         7: BATTERY VOLTAGE        {1001}\n            Battery: 3923mV, discharging, 70.\n         8: CHANGE HOST            {1814}\n            Change Host        : 1:archlinux\n         9: HOSTS INFO             {1815}\n            Host 0 (paired): archlinux\n            Host 1 (paired):\n        10: RGB EFFECTS            {8071}\n        11: PER KEY LIGHTING V2    {8081}\n        12: REPROG CONTROLS V4     {1B04}\n            Key/Button Diversion (saved): {Host Switch Channel 1:Regular, Host Switch Channel 2:Regular}\n            Key/Button Diversion        : {Host Switch Channel 1:Regular, Host Switch Channel 2:Regular}\n        13: REPORT HID USAGE       {1BC0}\n        14: ENCRYPTION             {4100}\n        15: KEYBOARD DISABLE BY USAGE {4522}\n        16: KEYBOARD LAYOUT 2      {4540}\n        17: GKEY                   {8010}\n            Divert G Keys (saved): False\n            Divert G Keys        : False\n        18: MKEYS                  {8020}\n            M-Key LEDs (saved): {M1:False, M2:False, M3:False}\n            M-Key LEDs        : {M1:False, M2:False, M3:False}\n        19: MR                     {8030}\n            MR-Key LED (saved): False\n            MR-Key LED        : False\n        20: BRIGHTNESS CONTROL     {8040}\n        21: ONBOARD PROFILES       {8100}\n            Device Mode: On-Board\n            Onboard Profiles (saved): Enable\n            Onboard Profiles        : Enable\n        22: REPORT RATE            {8060}\n            Polling Rate (ms): 1\n            Polling Rate (ms) (saved): 1\n            Polling Rate (ms)        : 1\n        23: DFUCONTROL SIGNED      {00C2}\n        24: DFU                    {00D0}\n        25: DEVICE RESET           {1802}   internal, hidden\n        26: unknown:1803           {1803}   internal, hidden\n        27: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        28: unknown:1813           {1813}   internal, hidden\n        29: OOBSTATE               {1805}   internal, hidden\n        30: unknown:1830           {1830}   internal, hidden\n        31: unknown:1890           {1890}   internal, hidden\n        32: unknown:1891           {1891}   internal, hidden\n        33: unknown:18A1           {18A1}   internal, hidden\n        34: unknown:1E00           {1E00}   hidden\n        35: unknown:1EB0           {1EB0}   internal, hidden\n        36: unknown:1861           {1861}   internal, hidden\n     Has 2 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             divertable, persistently divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             divertable, persistently divertable, pos:2, group:0, group mask:empty\n             reporting: default\n     Battery: 3923mV, discharging, 70.\n"
  },
  {
    "path": "docs/devices/G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD 407C.text",
    "content": "solaar version 1.1.12rc1\n\n  1: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD\n     Device path  : None\n     WPID         : 407C\n     Codename     : G915 KEYBOARD\n     Kind         : keyboard\n     Protocol     : HID++ 4.2\n     Report Rate : 1ms\n     Serial number: A502B0E1\n     Model ID:      B354407CC33E\n     Unit ID:       A502B0E1\n                 1: BOT 77.02.B0039\n                 3:\n                 0: MPK 09.03.B0041\n                 3:\n                 3:\n     The power switch is located on the top left corner.\n     Supports 38 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BOT 77.02.B0039 0000EC44D534\n            Firmware: Other\n            Firmware: Firmware MPK 09.03.B0041 407C3791543D\n            Firmware: Other\n            Firmware: Other\n            Unit ID: A502B0E1  Model ID: B354407CC33E  Transport IDs: {'btleid': 'B354', 'wpid': '407C', 'usbid': 'C33E'}\n         3: DEVICE NAME            {0005} V0\n            Name: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n            Configuration: 11000000000000000000000000000000\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: G915 KEYBOARD�\n         7: BATTERY VOLTAGE        {1001} V3\n            Battery: 80% 3998mV , discharging.\n         8: CHANGE HOST            {1814} V1\n            Change Host        : 1:Yon\n         9: HOSTS INFO             {1815} V1\n            Host 0 (paired): Yon\n            Host 1 (paired):\n        10: RGB EFFECTS            {8071} V0\n            RGB Control (saved): Device\n            RGB Control        : Device\n            LEDs Logo (saved): !LEDEffectSetting {ID: 1, color: 11546720, intensity: 0, period: 100, ramp: 0, speed: 0}\n            LEDs Logo        : HID++ error {'number': 1, 'request': 2799, 'error': 7, 'params': b'\\x00'}\n            LEDs Primary (saved): !LEDEffectSetting {ID: 1, color: 16776960, intensity: 0, period: 100, ramp: 0, speed: 0}\n            LEDs Primary        : HID++ error {'number': 1, 'request': 2796, 'error': 7, 'params': b'\\x01'}\n        11: PER KEY LIGHTING V2    {8081} V2\n            Per-key Lighting (saved): {A:white, B:red, C:white, D:white, E:white, F:white, G:white, H:white, I:white, J:white, K:white, L:white, M:white, N:white, O:white, P:white, Q:white, R:white, S:white, T:white, U:white, V:white, W:white, X:white, Y:white, Z:white, 1:white, 2:white, 3:white, 4:white, 5:white, 6:white, 7:white, 8:white, 9:white, 0:white, ENTER:white, ESC:white, BACKSPACE:white, TAB:white, SPACE:white, -:white, =:white, [:white, \\:white, KEY 46:white, ~:white, ;:white, ':white, `:white, ,:white, .:white, /:white, CAPS LOCK:white, F1:white, F2:white, F3:white, F4:white, F5:white, F6:white, F7:white, F8:white, F9:white, F10:white, F11:white, F12:white, PRINT:white, SCROLL LOCK:white, PASTE:white, INSERT:white, HOME:white, PAGE UP:white, DELETE:white, END:white, PAGE DOWN:white, RIGHT:white, LEFT:white, DOWN:white, UP:white, NUMLOCK:white, KEYPAD /:white, KEYPAD *:white, KEYPAD -:white, KEYPAD +:white, KEYPAD ENTER:white, KEYPAD 1:white, KEYPAD 2:white, KEYPAD 3:white, KEYPAD 4:white, KEYPAD 5:white, KEYPAD 6:white, KEYPAD 7:white, KEYPAD 8:white, KEYPAD 9:white, KEYPAD 0:white, KEYPAD .:white, KEY 97:white, COMPOSE:white, POWER:white, KEY 100:white, KEY 101:white, KEY 102:white, KEY 103:white, LEFT CTRL:white, LEFT SHIFT:white, LEFT ALT:white, LEFT WINDOWS:white, RIGHT CTRL:white, RIGHT SHIFT:white, RIGHT ALTGR:white, RIGHT WINDOWS:white, BRIGHTNESS:white, PAUSE:white, MUTE:white, NEXT:white, PREVIOUS:white, G1:white, G2:white, G3:white, G4:white, G5:white, LOGO:white}\n            Per-key Lighting        : {A:white, B:white, C:white, D:white, E:white, F:white, G:white, H:white, I:white, J:white, K:white, L:white, M:white, N:white, O:white, P:white, Q:white, R:white, S:white, T:white, U:white, V:white, W:white, X:white, Y:white, Z:white, 1:white, 2:white, 3:white, 4:white, 5:white, 6:white, 7:white, 8:white, 9:white, 0:white, ENTER:white, ESC:white, BACKSPACE:white, TAB:white, SPACE:white, -:white, =:white, [:white, \\:white, KEY 46:white, ~:white, ;:white, ':white, `:white, ,:white, .:white, /:white, CAPS LOCK:white, F1:white, F2:white, F3:white, F4:white, F5:white, F6:white, F7:white, F8:white, F9:white, F10:white, F11:white, F12:white, PRINT:white, SCROLL LOCK:white, PASTE:white, INSERT:white, HOME:white, PAGE UP:white, DELETE:white, END:white, PAGE DOWN:white, RIGHT:white, LEFT:white, DOWN:white, UP:white, NUMLOCK:white, KEYPAD /:white, KEYPAD *:white, KEYPAD -:white, KEYPAD +:white, KEYPAD ENTER:white, KEYPAD 1:white, KEYPAD 2:white, KEYPAD 3:white, KEYPAD 4:white, KEYPAD 5:white, KEYPAD 6:white, KEYPAD 7:white, KEYPAD 8:white, KEYPAD 9:white, KEYPAD 0:white, KEYPAD .:white, KEY 97:white, COMPOSE:white, POWER:white, KEY 100:white, KEY 101:white, KEY 102:white, KEY 103:white, LEFT CTRL:white, LEFT SHIFT:white, LEFT ALT:white, LEFT WINDOWS:white, RIGHT CTRL:white, RIGHT SHIFT:white, RIGHT ALTGR:white, RIGHT WINDOWS:white, BRIGHTNESS:white, PAUSE:white, MUTE:white, NEXT:white, PREVIOUS:white, G1:white, G2:white, G3:white, G4:white, G5:white, LOGO:white}\n        12: REPROG CONTROLS V4     {1B04} V4\n            Key/Button Diversion (saved): {Host Switch Channel 1:Regular, Host Switch Channel 2:Regular}\n            Key/Button Diversion        : {Host Switch Channel 1:Regular, Host Switch Channel 2:Regular}\n        13: REPORT HID USAGE       {1BC0} V1\n        14: ENCRYPTION             {4100} V0\n        15: KEYBOARD DISABLE BY USAGE {4522} V0\n        16: KEYBOARD LAYOUT 2      {4540} V0\n        17: GKEY                   {8010} V0\n            Divert G and M Keys (saved): False\n            Divert G and M Keys        : False\n        18: MKEYS                  {8020} V0\n            M-Key LEDs (saved): {M1:False, M2:False, M3:False}\n            M-Key LEDs        : {M1:False, M2:False, M3:False}\n        19: MR                     {8030} V0\n            MR-Key LED (saved): False\n            MR-Key LED        : False\n        20: BRIGHTNESS CONTROL     {8040} V0\n            Brightness Control (saved): 12\n            Brightness Control        : 12\n        21: ONBOARD PROFILES       {8100} V0\n            Device Mode: Host\n            Onboard Profiles (saved): Disabled\n            Onboard Profiles        : Disabled\n        22: REPORT RATE            {8060} V0\n            Report Rate: 1ms\n            Report Rate (saved): 1ms\n            Report Rate        : 1ms\n        23: DFUCONTROL SIGNED      {00C2} V0\n        24: DFU                    {00D0} V3\n        25: DEVICE RESET           {1802} V0    internal, hidden\n        26: unknown:1803           {1803} V0    internal, hidden\n        27: CONFIG DEVICE PROPS    {1806} V8    internal, hidden\n        28: unknown:1813           {1813} V0    internal, hidden\n        29: OOBSTATE               {1805} V0    internal, hidden\n        30: unknown:1830           {1830} V0    internal, hidden\n        31: unknown:1890           {1890} V5    internal, hidden\n        32: unknown:1891           {1891} V5    internal, hidden\n        33: unknown:18A1           {18A1} V0    internal, hidden\n        34: unknown:1E00           {1E00} V0    hidden\n        35: unknown:1EB0           {1EB0} V0    internal, hidden\n        36: unknown:1861           {1861} V0    internal, hidden\n        37: unknown:18B0           {18B0} V0    internal, hidden\n     Has 2 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             divertable, persistently divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             divertable, persistently divertable, pos:2, group:0, group mask:empty\n             reporting: default\n     Battery: 80% 3998mV , discharging.\n"
  },
  {
    "path": "docs/devices/G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD C33E.text",
    "content": "solaar version 1.1.10\n\nUSB and Bluetooth Devices\n\n  1: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD\n     Device path  : /dev/hidraw13\n     USB id       : 046d:C33E\n     Codename     : G915\n     Kind         : ?\n     Protocol     : HID++ 4.2\n     Polling rate : 1 ms (1000Hz)\n     Serial number:\n     Model ID:      B354407CC33E\n     Unit ID:       8816D0DF\n        Bootloader: BOT 77.03.B0041\n             Other:\n          Firmware: MPK 09.04.B0042\n             Other:\n             Other:\n     Supports 37 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BOT 77.03.B0041 00003791543D\n            Firmware: Other\n            Firmware: Firmware MPK 09.04.B0042 C33E8A23A76B\n            Firmware: Other\n            Firmware: Other\n            Unit ID: 8816D0DF  Model ID: B354407CC33E  Transport IDs: {'btleid': 'B354', 'wpid': '407C', 'usbid': 'C33E'}\n         3: DEVICE NAME            {0005} V0\n            Name: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n         6: BATTERY VOLTAGE        {1001} V3\n            Battery: 70% 3965mV , recharging.\n         7: CHANGE HOST            {1814} V1\n            Changer d'hôte        : 1:stagcrown\n         8: HOSTS INFO             {1815} V1\n            Host 0 (paired): stagcrown\n            Host 1 (paired):\n         9: RGB EFFECTS            {8071} V0\n        10: PER KEY LIGHTING V2    {8081} V2\n        11: REPROG CONTROLS V4     {1B04} V4\n            Interception des boutons/touches (saved): {Host Switch Channel 1:Interception, Host Switch Channel 2:Interception}\n            Interception des boutons/touches        : {Host Switch Channel 1:Interception, Host Switch Channel 2:Interception}\n        12: REPORT HID USAGE       {1BC0} V1\n        13: ENCRYPTION             {4100} V0\n        14: KEYBOARD DISABLE BY USAGE {4522} V0\n        15: KEYBOARD LAYOUT 2      {4540} V0\n        16: GKEY                   {8010} V0\n            Définir les touches G (saved): True\n            Définir les touches G        : False\n        17: MKEYS                  {8020} V0\n            LEDs de touche M (saved): {M1:False, M2:False, M3:False}\n            LEDs de touche M        : {M1:False, M2:False, M3:False}\n        18: MR                     {8030} V0\n            LED de touche MR (saved): False\n            LED de touche MR        : False\n        19: BRIGHTNESS CONTROL     {8040} V0\n        20: ONBOARD PROFILES       {8100} V0\n            Device Mode: On-Board\n            Profils embarqués (saved): Enable\n            Profils embarqués        : Enable\n        21: REPORT RATE            {8060} V0\n            Polling Rate (ms): 1\n            Taux de scrutation (ms) (saved): 1\n            Taux de scrutation (ms)        : 1\n        22: DFUCONTROL SIGNED      {00C2} V0\n        23: DFU                    {00D0} V3\n        24: DEVICE RESET           {1802} V0    internal, hidden\n        25: unknown:1803           {1803} V0    internal, hidden\n        26: CONFIG DEVICE PROPS    {1806} V8    internal, hidden\n        27: unknown:1813           {1813} V0    internal, hidden\n        28: OOBSTATE               {1805} V0    internal, hidden\n        29: unknown:1830           {1830} V0    internal, hidden\n        30: unknown:1890           {1890} V9    internal, hidden\n        31: unknown:1891           {1891} V9    internal, hidden\n        32: unknown:18A1           {18A1} V0    internal, hidden\n        33: unknown:1E00           {1E00} V0    hidden\n        34: unknown:1EB0           {1EB0} V0    internal, hidden\n        35: unknown:1861           {1861} V0    internal, hidden\n        36: unknown:18B0           {18B0} V0    internal, hidden\n     Has 2 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             divertable, persistently divertable, pos:1, group:0, group mask:empty\n             reporting: diverted\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             divertable, persistently divertable, pos:2, group:0, group mask:empty\n             reporting: diverted\n     Battery: 70% 3965mV , recharging.\n"
  },
  {
    "path": "docs/devices/G915 WIRELESS RGB Mechanical Gaming Keyboard 407E.txt",
    "content": "Solaar version 1.1.1\n\n  1: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD\n     Device path  : None\n     WPID         : 407C\n     Codename     : G915 KEYBOARD\n     Kind         : keyboard\n     Protocol     : HID++ 4.2\n     Polling rate : 8 ms (125Hz)\n     Serial number: 7FDC464D\n     Model ID:      B354407CC33E\n     Unit ID:       7FDC464D\n        Bootloader: BOT 77.01.B0035\n             Other:\n          Firmware: MPK 09.01.B0035\n             Other:\n             Other:\n     The power switch is located on the top left corner.\n     Supports 39 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 77.01.B0035 0000691BEBFB\n            Firmware: Other\n            Firmware: Firmware MPK 09.01.B0035 407C691BEBFB\n            Firmware: Other\n            Firmware: Other\n            Unit ID: 7FDC464D  Model ID: B354407CC33E  Transport IDs: {'btleid': 'B354', 'wpid': '407C', 'usbid': 'C33E'}\n         3: DEVICE NAME            {0005}\n            Name: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: G915 KEYBOARD\n         7: BATTERY VOLTAGE        {1001}\n            Battery: 3914mV, discharging, 60.\n         8: CHANGE HOST            {1814}\n            Change Host        : 1:evoxs\n         9: HOSTS INFO             {1815}\n            Host 0 (paired): evoxs\n            Host 1 (unpaired):\n        10: RGB EFFECTS            {8071}\n        11: PER KEY LIGHTING V2    {8081}\n        12: REPROG CONTROLS V4     {1B04}\n            Key/Button Diversion (saved): {'209': 0, '210': 0}\n            Key/Button Diversion        : {'209': 0, '210': 0}\n        13: REPORT HID USAGE       {1BC0}\n        14: ENCRYPTION             {4100}\n        15: KEYBOARD DISABLE BY USAGE {4522}\n        16: KEYBOARD LAYOUT 2      {4540}\n        17: GKEY                   {8010}\n            Divert G Keys (saved): False\n            Divert G Keys        : False\n        18: MKEYS                  {8020}\n        19: MR                     {8030}\n        20: BRIGHTNESS CONTROL     {8040}\n        21: ONBOARD PROFILES       {8100}\n            Device Mode: Host\n        22: REPORT RATE            {8060}\n            Polling Rate (ms): 1\n            Polling Rate (ms) (saved): 1\n            Polling Rate (ms)        : 1\n        23: DFUCONTROL SIGNED      {00C2}\n        24: DFU                    {00D0}\n        25: DEVICE RESET           {1802}   internal, hidden\n        26: unknown:1803           {1803}   internal, hidden\n        27: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        28: unknown:1813           {1813}   internal, hidden\n        29: OOBSTATE               {1805}   internal, hidden\n        30: unknown:1830           {1830}   internal, hidden\n        31: unknown:1890           {1890}   internal, hidden\n        32: unknown:1891           {1891}   internal, hidden\n        33: unknown:18A1           {18A1}   internal, hidden\n        34: unknown:1DF3           {1DF3}   internal, hidden\n        35: unknown:1E00           {1E00}   hidden\n        36: unknown:1EB0           {1EB0}   internal, hidden\n        37: unknown:1861           {1861}   internal, hidden\n        38: unknown:18B0           {18B0}   internal, hidden\n     Has 2 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             divertable, persistently divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             divertable, persistently divertable, pos:2, group:0, group mask:empty\n             reporting: default\n     Battery: 3914mV, discharging, 60.\n"
  },
  {
    "path": "docs/devices/G935 Gaming Headset 0A87.txt",
    "content": "Solaar version 1.1.7\n\n  1: G935 Gaming Headset\n     Device path  : /dev/hidraw2\n     USB id       : 046d:0A87\n     Codename     : G935 Headset\n     Kind         : headset\n     Protocol     : HID++ 4.2\n     Serial number:\n     Model ID:      000000000A87\n     Unit ID:       FFFFFFFF\n          Firmware: U1  29.00.B0012\n     Supports 9 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Firmware U1  29.00.B0012 0A87\n\t    Unit ID: FFFFFFFF  Model ID: 000000000A87\n \t    Transport IDs: {'btid': '0000', 'btleid': '0000'}\n         3: DEVICE NAME            {0005} V0\n            Name: G935 Gaming Headset\n            Kind: None\n         4: COLOR LED EFFECTS      {8070} V0\n         5: GKEY                   {8010} V0\n            Divert G Keys (saved): False\n            Divert G Keys        : False\n         6: EQUALIZER              {8310} V0\n         7: SIDETONE               {8300} V0\n            Sidetone (saved): 0\n            Sidetone        : 0\n         8: ADC MEASUREMENT        {1F20} V0\n            Battery status unavailable.\n     Battery status unavailable.\n"
  },
  {
    "path": "docs/devices/Illuminated Keyboard C318.txt",
    "content": "solaar version 1.1.8-29-g0ae14c7\n\n  1: Illuminated Keyboard\n     Device path  : /dev/hidraw1\n     USB id       : 046d:C318\n     Codename     : Illuminated\n     Kind         : keyboard\n     Protocol     : HID++ 1.0\n     Serial number:\n          Firmware: 55.01.B0025\n     Notifications: (none).\n     Features: (none)\n     Battery status unavailable.\n"
  },
  {
    "path": "docs/devices/Illuminated Living-Room Keyboard K830 4032.txt",
    "content": "# Provided by Mikkel Munch Mortensen\n\n(solaar)\n  3: Illuminated Living-Room Keyboard K830\n     Codename     : K830\n     Kind         : keyboard\n     Wireless PID : 4032\n     Protocol     : HID++ 4.1\n     Polling rate : 8 ms (125Hz)\n     Serial number: 9F7C6FD7\n          Firmware: RQK 56.00.B0020\n     The power switch is located on the edge of top right corner.\n     Supports 27 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n         3: DEVICE NAME            {0005}\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: unknown:0020           {0020}\n         6: BATTERY STATUS         {1000}\n         7: BACKLIGHT              {1981}\n         8: unknown:1B04           {1B04}\n         9: unknown:2005           {2005}\n        10: NEW FN INVERSION       {40A2}\n        11: ENCRYPTION             {4100}\n        12: unknown:4521           {4521}\n        13: TOUCHPAD RAW XY        {6100}   hidden\n        14: unknown:6501           {6501}\n        15: unknown:00C1           {00C1}\n        16: unknown:1811           {1811}   internal, hidden\n        17: unknown:1830           {1830}   internal, hidden\n        18: unknown:1890           {1890}   internal, hidden\n        19: unknown:18A0           {18A0}   internal, hidden\n        20: unknown:1DF3           {1DF3}   internal, hidden\n        21: unknown:1E00           {1E00}   hidden\n        22: unknown:1EB0           {1EB0}   internal, hidden\n        23: unknown:1861           {1861}   internal, hidden\n        24: unknown:1A20           {1A20}   internal, hidden\n        25: unknown:18B0           {18B0}   internal, hidden\n        26: unknown:1F07           {1F07}   internal, hidden\n     Battery: 50%, discharging.\n"
  },
  {
    "path": "docs/devices/K850 Performance Wireless Keyboard 4062.txt",
    "content": "Solaar version 1.1.1\n\n  2: K850 Performance Wireless Keyboard\n     Device path  : /dev/hidraw2\n     WPID         : 4062\n     Codename     : K850\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Polling rate : 20 ms (50Hz)\n     Serial number: E2A15F0B\n     Model ID:      B34D40620000\n     Unit ID:       178D05AD\n        Bootloader: BOT 43.01.B0004\n          Firmware: MPK 04.03.B0015\n             Other:\n     The power switch is located on the edge of top right corner.\n     Supports 31 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 43.01.B0004 00002FD362F001\n            Firmware: Firmware MPK 04.03.B0015 40622FD362F001\n            Firmware: Other\n            Unit ID: 178D05AD  Model ID: B34D40620000  Transport IDs: {'btleid': 'B34D', 'wpid': '4062'}\n         3: DEVICE NAME            {0005}\n            Name: K850 Performance Wireless Keyboard\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: Keyboard K850\n         7: BATTERY STATUS         {1000}\n            Battery: 90%, discharging, next level 50%.\n         8: CHANGE HOST            {1814}\n            Change Host        : 2:desktop\n         9: HOSTS INFO             {1815}\n            Host 0 (paired): rpi\n            Host 1 (paired): desktop\n            Host 2 (paired): laptop\n        10: REPROG CONTROLS V4     {1B04}\n            Key/Button Diversion (saved): {'1': 0, '10': 0, '189': 0, '191': 0, '192': 0, '193': 0, '194': 0, '2': 0, '209': 0, '210': 0, '211': 0, '212': 0, '213': 0, '214': 0, '221': 0, '3': 0, '4': 0, '5': 0, '6': 0}\n            Key/Button Diversion        : {'209': 0, '210': 0, '211': 0, '213': 0, '214': 0, '189': 0, '212': 0, '6': 0, '4': 0, '5': 0, '3': 0, '2': 0, '1': 0, '194': 0, '221': 0, '191': 0, '10': 0, '193': 0, '192': 0}\n        11: PERSISTENT REMAPPABLE ACTION {1C00}\n        12: K375S FN INVERSION     {40A3}\n            Swap Fx function (saved): False\n            Swap Fx function        : False\n        13: ENCRYPTION             {4100}\n        14: LOCK KEY STATE         {4220}\n        15: KEYBOARD DISABLE KEYS  {4521}\n            Disable keys (saved): {'1': False, '16': False, '2': False, '4': False, '8': False}\n            Disable keys        : {'1': False, '2': False, '4': False, '8': False, '16': False}\n        16: MULTIPLATFORM          {4531}\n            Set OS (saved): 0\n            Set OS        : Windows\n        17: DFUCONTROL SIGNED      {00C2}\n        18: unknown:1803           {1803}   internal, hidden\n        19: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        20: OOBSTATE               {1805}   internal, hidden\n        21: unknown:1813           {1813}   internal, hidden\n        22: unknown:1830           {1830}   internal, hidden\n        23: unknown:1861           {1861}   internal, hidden\n        24: unknown:1890           {1890}   internal, hidden\n        25: unknown:1891           {1891}   internal, hidden\n        26: unknown:18A1           {18A1}   internal, hidden\n        27: unknown:1DF3           {1DF3}   internal, hidden\n        28: unknown:1E00           {1E00}   hidden\n        29: unknown:1EB0           {1EB0}   internal, hidden\n        30: unknown:18B0           {18B0}   internal, hidden\n     Has 21 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n         3: MultiPlatform Home/Mission Control, default: Multiplatform Home/Mission Control => Multiplatform Home/Mission Control\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         4: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad, default: Multiplatform Menu/Launchpad => Multiplatform Menu/Launchpad\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:2, group:0, group mask:empty\n             reporting: default\n         5: Multiplatform Back        , default: MultiPlatform Back          => MultiPlatform Back\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:3, group:0, group mask:empty\n             reporting: default\n         6: MultiPlatform Search      , default: Multiplatform Search        => Multiplatform Search\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty\n             reporting: default\n         7: Previous                  , default: Previous                    => Previous\n             is FN, FN sensitive, divertable, persistently divertable, pos:5, group:0, group mask:empty\n             reporting: default\n         8: Play/Pause                , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, divertable, persistently divertable, pos:6, group:0, group mask:empty\n             reporting: default\n         9: Next                      , default: Next                        => Next\n             is FN, FN sensitive, divertable, persistently divertable, pos:7, group:0, group mask:empty\n             reporting: default\n        10: Mute                      , default: Mute                        => Mute\n             is FN, FN sensitive, divertable, persistently divertable, pos:8, group:0, group mask:empty\n             reporting: default\n        11: Volume Down               , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, divertable, persistently divertable, pos:9, group:0, group mask:empty\n             reporting: default\n        12: Volume Up                 , default: Volume Up                   => Volume Up\n             is FN, FN sensitive, divertable, persistently divertable, pos:10, group:0, group mask:empty\n             reporting: default\n        13: Multiplatform Lock        , default: WindowsLock                 => WindowsLock\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, group mask:empty\n             reporting: default\n        14: Multi Platform Language Switch, default: Multiplatform Language Switch => Multiplatform Language Switch\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, group mask:empty\n             reporting: default\n        15: Screen Capture/Print Screen, default: Screen Capture              => Screen Capture\n             is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Calculator                , default: Calculator                  => Calculator\n             is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Fn Up                     , default: unknown:0070                => unknown:0070\n             is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        18: Fn Down                   , default: unknown:006F                => unknown:006F\n             is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        19: F Lock                    , default: Do Nothing One              => Do Nothing One\n             is FN, pos:0, group:0, group mask:empty\n             reporting: default\n        20: unknown:0034              , default: Do Nothing One              => Do Nothing One\n             nonstandard, pos:0, group:0, group mask:empty\n             reporting: default\n     Battery: 90%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/K850 Performance Wireless Keyboard B34D.txt",
    "content": "Solaar version 1.1.4\n\n  2: K850 Performance Wireless Keyboard\n     Device path  : /dev/hidraw1\n     USB id       : 046d:B34D\n     Codename     : Keyboard K850\n     Kind         : ?\n     Protocol     : HID++ 4.5\n     Serial number:\n     Model ID:      B34D40620000\n     Unit ID:       420F6F9D\n        Bootloader: BOT 43.01.B0004\n          Firmware: MPK 04.03.B0015\n             Other:\n     Supports 17 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 43.01.B0004 00002FD362F001\n            Firmware: Firmware MPK 04.03.B0015 B34D2FD362F001\n            Firmware: Other\n            Unit ID: 420F6F9D  Model ID: B34D40620000  Transport IDs: {'btleid': 'B34D', 'wpid': '4062'}\n         3: DEVICE NAME            {0005}\n            Name: K850 Performance Wireless Keyboard\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: Keyboard K850\n         7: BATTERY STATUS         {1000}\n            Battery: 90%, discharging, next level 50%.\n         8: CHANGE HOST            {1814}\n            Change Host        : 3:shoaib-MacBookPro\n         9: HOSTS INFO             {1815}\n            Host 0 (paired):\n            Host 1 (paired): Shoaib’s MacBook Pro\n            Host 2 (paired): shoaib-MacBookPro\n        10: REPROG CONTROLS V4     {1B04}\n            Key/Button Diversion (saved): {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Calculator:Regular, Multiplatform Back:Regular, Screen Capture/Print Screen:Regular, Fn Down:Regular, Fn Up:Regular, Multiplatform Lock:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, MultiPlatform Search:Regular, MultiPlatform Home/Mission Control:Regular, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Regular, Multi Platform Language Switch:Regular}\n            Key/Button Diversion        : {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Calculator:Regular, Multiplatform Back:Regular, Screen Capture/Print Screen:Regular, Fn Down:Regular, Fn Up:Regular, Multiplatform Lock:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, MultiPlatform Search:Regular, MultiPlatform Home/Mission Control:Regular, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Regular, Multi Platform Language Switch:Regular}\n        11: PERSISTENT REMAPPABLE ACTION {1C00}\n            Persistent Key/Button Mapping        : {Volume Up:Volume Up, Volume Down:Volume Down, Mute:Mute, Play/Pause:Play/Pause, Next:Scan Next Track, Previous:Scan Previous Track, Calculator:AL Calculator, Multiplatform Back:AC Back, Screen Capture/Print Screen:SYSRQ, Multiplatform Lock:Default, MultiPlatform Search:AC Search, MultiPlatform Home/Mission Control:AC Home, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:COMPOSE, Multi Platform Language Switch:Alt+Shift+No Output}\n        12: K375S FN INVERSION     {40A3}\n            Swap Fx function (saved): False\n            Swap Fx function        : False\n        13: ENCRYPTION             {4100}\n        14: LOCK KEY STATE         {4220}\n        15: KEYBOARD DISABLE KEYS  {4521}\n            Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        16: MULTIPLATFORM          {4531}\n            Set OS (saved): Windows\n            Set OS        : Windows\n     Has 21 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n         3: MultiPlatform Home/Mission Control, default: Multiplatform Home/Mission Control => Multiplatform Home/Mission Control\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         4: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad, default: Multiplatform Menu/Launchpad => Multiplatform Menu/Launchpad\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:2, group:0, group mask:empty\n             reporting: default\n         5: Multiplatform Back        , default: MultiPlatform Back          => MultiPlatform Back\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:3, group:0, group mask:empty\n             reporting: default\n         6: MultiPlatform Search      , default: Multiplatform Search        => Multiplatform Search\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty\n             reporting: default\n         7: Previous                  , default: Previous                    => Previous\n             is FN, FN sensitive, divertable, persistently divertable, pos:5, group:0, group mask:empty\n             reporting: default\n         8: Play/Pause                , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, divertable, persistently divertable, pos:6, group:0, group mask:empty\n             reporting: default\n         9: Next                      , default: Next                        => Next\n             is FN, FN sensitive, divertable, persistently divertable, pos:7, group:0, group mask:empty\n             reporting: default\n        10: Mute                      , default: Mute                        => Mute\n             is FN, FN sensitive, divertable, persistently divertable, pos:8, group:0, group mask:empty\n             reporting: default\n        11: Volume Down               , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, divertable, persistently divertable, pos:9, group:0, group mask:empty\n             reporting: default\n        12: Volume Up                 , default: Volume Up                   => Volume Up\n             is FN, FN sensitive, divertable, persistently divertable, pos:10, group:0, group mask:empty\n             reporting: default\n        13: Multiplatform Lock        , default: WindowsLock                 => WindowsLock\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, group mask:empty\n             reporting: default\n        14: Multi Platform Language Switch, default: Multiplatform Language Switch => Multiplatform Language Switch\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, group mask:empty\n             reporting: default\n        15: Screen Capture/Print Screen, default: Screen Capture              => Screen Capture\n             is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Calculator                , default: Calculator                  => Calculator\n             is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Fn Up                     , default: unknown:0070                => unknown:0070\n             is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        18: Fn Down                   , default: unknown:006F                => unknown:006F\n             is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        19: F Lock                    , default: Do Nothing One              => Do Nothing One\n             is FN, pos:0, group:0, group mask:empty\n             reporting: default\n        20: FN Key                    , default: Do Nothing One              => Do Nothing One\n             nonstandard, pos:0, group:0, group mask:empty\n             reporting: default\n     Has 14 persistent remappable keys:\n         0: MultiPlatform Home/Mission Control => Consumer: AC Home\n         1: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad => Key: COMPOSE\n         2: Multiplatform Back         => Consumer: AC Back\n         3: MultiPlatform Search       => Consumer: AC Search\n         4: Previous                   => Consumer: Scan Previous Track\n         5: Play/Pause                 => Consumer: Play/Pause\n         6: Next                       => Consumer: Scan Next Track\n         7: Mute                       => Consumer: Mute\n         8: Volume Down                => Consumer: Volume Down\n         9: Volume Up                  => Consumer: Volume Up\n        10: Multiplatform Lock         => Unknown\n        11: Multi Platform Language Switch => Key: Alt+Shift+No Output\n        12: Screen Capture/Print Screen => Key: SYSRQ\n        13: Calculator                 => Consumer: AL Calculator\n     Battery: 90%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/Keyboard K600 TV 4078.txt",
    "content": "Solaar version 1.1.7\n\n  1: Keyboard K600 TV\n     Device path  : /dev/hidraw3\n     WPID         : 4078\n     Codename     : K600 TV\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: C4E873FC\n     Model ID:      B35340780000\n     Unit ID:       CA575869\n        Bootloader: BOT 73.00.B0015\n          Firmware: MPK 08.00.B0015\n             Other:\n             Other:\n     Supports 36 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Bootloader BOT 73.00.B0015 00001E30DA07\n            Firmware: Firmware MPK 08.00.B0015 40781E30DA07\n            Firmware: Other\n            Firmware: Other\n            Unit ID: CA575869  Model ID: B35340780000  Transport IDs: {'btleid': 'B353', 'wpid': '4078'}\n         3: DEVICE NAME            {0005} V0\n            Name: Keyboard K600 TV\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: RESET                  {0020} V0\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: Keyboard K600 T\n         7: BATTERY STATUS         {1000} V1\n            Battery: 90%, discharging, next level 50%.\n         8: REPROG CONTROLS V4     {1B04} V4\n            Desvio de Tecla/Botón (saved): {Fn Left Click:Normal, Multiplatform App Switch:Normal, Multiplatform Back:Normal, Multiplatform Insert:Normal, Brightness Down:Normal, Brightness Up:Normal, Host Switch Channel 1:Normal, Host Switch Channel 2:Normal, Host Switch Channel 3:Normal, MultiPlatform Search:Normal, MultiPlatform Home/Mission Control:Normal, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Normal, Previous Fn:Normal, Play/Pause Fn:Normal, Next Fn:Normal, Mute Fn:Normal, Volume Down Fn:Normal, Volume Up Fn:Normal}\n            Desvio de Tecla/Botón        : {Fn Left Click:Normal, Multiplatform App Switch:Normal, Multiplatform Back:Normal, Multiplatform Insert:Normal, Brightness Down:Normal, Brightness Up:Normal, Host Switch Channel 1:Normal, Host Switch Channel 2:Normal, Host Switch Channel 3:Normal, MultiPlatform Search:Normal, MultiPlatform Home/Mission Control:Normal, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Normal, Previous Fn:Normal, Play/Pause Fn:Normal, Next Fn:Normal, Mute Fn:Normal, Volume Down Fn:Normal, Volume Up Fn:Normal}\n         9: PERSISTENT REMAPPABLE ACTION {1C00} V0\n            Persistent Key/Button Mapping        : {Multiplatform App Switch:No Output (only as default), Multiplatform Back:No Output (only as default), Multiplatform Insert:No Output (only as default), Brightness Down:No Output (only as default), Brightness Up:No Output (only as default), MultiPlatform Search:No Output (only as default), MultiPlatform Home/Mission Control:No Output (only as default), MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:No Output (only as default), Previous Fn:No Output (only as default), Play/Pause Fn:No Output (only as default), Next Fn:No Output (only as default), Mute Fn:No Output (only as default), Volume Down Fn:No Output (only as default), Volume Up Fn:No Output (only as default)}\n        10: SWAP BUTTON CANCEL     {2005} V0\n        11: CHANGE HOST            {1814} V1\n            Cambiar Host        : 1:romanescu\n        12: HOSTS INFO             {1815} V1\n            Host 0 (paired): romanescu\n            Host 1 (unpaired):\n            Host 2 (unpaired):\n        13: NEW FN INVERSION       {40A2} V0\n            Fn-swap: enabled\n            Fn-swap default: enabled\n            Intercambiar función Fx (saved): True\n            Intercambiar función Fx        : True\n        14: ENCRYPTION             {4100} V0\n        15: LOCK KEY STATE         {4220} V0\n        16: KEYBOARD DISABLE KEYS  {4521} V0\n            Desactivar teclas (saved): {Caps Lock:False, Insert:False, Win:False}\n            Desactivar teclas        : {Caps Lock:False, Insert:False, Win:False}\n        17: MULTIPLATFORM          {4531} V1\n            Especificar SO (saved): Windows\n            Especificar SO        : Windows\n        18: TOUCHPAD RAW XY        {6100} V0\n        19: GESTURE 2              {6501} V0\n            Gestos (saved): {1: True, 2: True, 4: True, 5: True, 10: True, 30: True, 34: False, 42: True, 43: True, 45: False, 84: True}\n            Gestos        : {1: True, 2: True, 4: True, 5: True, 30: True, 10: True, 45: False, 42: True, 43: True, 84: True, 34: False}\n            Gestures Diversion (saved): {1: False, 2: False, 4: False, 5: False, 10: False, 44: False, 84: False, 85: False, 100: False}\n            Gestures Diversion        : {1: False, 2: False, 4: False, 5: False, 10: False, 44: False, 84: False, 85: False, 100: False}\n            Parámetros de gestos (saved): {4: {'scale': 256}}\n            Parámetros de gestos        : {4: {'scale': 256}}\n        20: DFUCONTROL SIGNED      {00C2} V0\n        21: DEVICE RESET           {1802} V0    internal, hidden\n        22: unknown:1803           {1803} V0    internal, hidden\n        23: CONFIG DEVICE PROPS    {1806} V5    internal, hidden\n        24: unknown:1813           {1813} V0    internal, hidden\n        25: OOBSTATE               {1805} V0    internal, hidden\n        26: unknown:1830           {1830} V0    internal, hidden\n        27: unknown:1890           {1890} V2    internal, hidden\n        28: unknown:1891           {1891} V2    internal, hidden\n        29: unknown:18A1           {18A1} V0    internal, hidden\n        30: unknown:1DF3           {1DF3} V0    internal, hidden\n        31: unknown:1E00           {1E00} V0    hidden\n        32: unknown:1EB0           {1EB0} V0    internal, hidden\n        33: unknown:1861           {1861} V0    internal, hidden\n        34: unknown:18B0           {18B0} V0    internal, hidden\n        35: unknown:1F11           {1F11} V0    internal, hidden\n     Has 19 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             is FN, FN sensitive, divertable, persistently divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             is FN, FN sensitive, divertable, persistently divertable, pos:2, group:0, group mask:empty\n             reporting: default\n         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             is FN, FN sensitive, divertable, persistently divertable, pos:3, group:0, group mask:empty\n             reporting: default\n         3: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad, default: Multiplatform Menu/Launchpad => Multiplatform Menu/Launchpad\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty\n             reporting: default\n         4: Brightness Down           , default: Brightness Down             => Brightness Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:5, group:0, group mask:empty\n             reporting: default\n         5: Brightness Up             , default: Brightness Up               => Brightness Up\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:6, group:0, group mask:empty\n             reporting: default\n         6: Previous Fn               , default: Previous                    => Previous\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:7, group:0, group mask:empty\n             reporting: default\n         7: Play/Pause Fn             , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:8, group:0, group mask:empty\n             reporting: default\n         8: Next Fn                   , default: Next                        => Next\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:9, group:0, group mask:empty\n             reporting: default\n         9: Mute Fn                   , default: Mute                        => Mute\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:10, group:0, group mask:empty\n             reporting: default\n        10: Volume Down Fn            , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, group mask:empty\n             reporting: default\n        11: Volume Up Fn              , default: Volume Up                   => Volume Up\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, group mask:empty\n             reporting: default\n        12: Multiplatform Insert      , default: Switch Language             => Switch Language\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        13: MultiPlatform Home/Mission Control, default: Multiplatform Home/Mission Control => Multiplatform Home/Mission Control\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        14: Multiplatform Back        , default: MultiPlatform Back          => MultiPlatform Back\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        15: Multiplatform App Switch  , default: MultiPlatform App Switch    => MultiPlatform App Switch\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        16: MultiPlatform Search      , default: Multiplatform Search        => Multiplatform Search\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Fn Left Click             , default: ShowUI                      => ShowUI\n             divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        18: FN Key                    , default: Do Nothing One              => Do Nothing One\n             nonstandard, pos:0, group:0, group mask:empty\n             reporting: default\n     Has 14 persistent remappable keys:\n         0: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad => None\n         1: Brightness Down            => None\n         2: Brightness Up              => None\n         3: Previous Fn                => None\n         4: Play/Pause Fn              => None\n         5: Next Fn                    => None\n         6: Mute Fn                    => None\n         7: Volume Down Fn             => None\n         8: Volume Up Fn               => None\n         9: Multiplatform Insert       => None\n        10: MultiPlatform Home/Mission Control => None\n        11: Multiplatform Back         => None\n        12: Multiplatform App Switch   => None\n        13: MultiPlatform Search       => None\n     Has 16 gesture(s), 1 param(s) and 5 spec(s):\n        Track1Finger               Enabled(None): None   Diverted:(None) None\n        TapGestures                Enabled(None): None   Diverted:(None) None\n        Tap1Finger                 Enabled(   0): True   Diverted:(   0) False\n        Tap2Finger                 Enabled(   1): True   Diverted:(   1) False\n        Click1Finger               Enabled(   2): True   Diverted:(   2) False\n        Click2Finger               Enabled(   3): True   Diverted:(   3) False\n        TapDrag1Finger             Enabled(   4): True   Diverted:(None) None\n        DoubleTap1Finger           Enabled(   5): True   Diverted:(   4) False\n        Scroll2FingerStateless     Enabled(None): None   Diverted:(   5) False\n        NaturalScrolling           Enabled(   6): False  Diverted:(None) None\n        Scroll2FingerHoriz         Enabled(   7): True   Diverted:(None) None\n        Scroll2FingerVert          Enabled(   8): True   Diverted:(None) None\n        Zoom2FingerStateless       Enabled(   9): True   Diverted:(   6) False\n        FnClickGestureSuppression  Enabled(  10): False  Diverted:(None) None\n        TwoFingersPresent          Enabled(None): None   Diverted:(   7) False\n        DeviceSpecificRawData      Enabled(None): None   Diverted:(   8) False\n        ScaleFactor                Value  (   0): 256 [Default: 256]\n        period unit                Spec   (   3): 2048\n        DVI field width            Spec   (   1): 8\n        field widths               Spec   (   2): 8\n        multiplier                 Spec   (   5): None\n        resolution                 Spec   (   4): 4\n     Battery: 90%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/LIFT For Business B033.txt",
    "content": "solaar version 1.1.8\n\n  2: LIFT For Business\n     Device path  : None\n     WPID         : B033\n     Codename     : LIFT B\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number: A67F904D\n     Model ID:      B03300000000\n     Unit ID:       A67F904D\n        Bootloader: BL1 56.01.B0010\n          Firmware: RBM 21.01.B0010\n             Other:\n     The power switch is located on the (unknown).\n     Supports 32 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BL1 56.01.B0010 B033B0706FCD\n            Firmware: Firmware RBM 21.01.B0010 B033B0706FCD\n            Firmware: Other\n            Unit ID: A67F904D  Model ID: B03300000000  Transport IDs: {'btleid': 'B033'}\n         3: DEVICE NAME            {0005} V0\n            Name: LIFT For Business\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n         6: CRYPTO ID              {0021} V1\n         7: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: LIFT B\n         8: UNIFIED BATTERY        {1004} V3\n            Battery: 100%, discharging.\n         9: REPROG CONTROLS V4     {1B04} V5\n            Key/Button Actions (saved): {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, DPI Switch:DPI Switch}\n            Key/Button Actions        : {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, DPI Switch:DPI Switch}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, DPI Switch:Regular}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, DPI Switch:Regular}\n        10: CHANGE HOST            {1814} V1\n            Change Host        : 1:feathora\n        11: HOSTS INFO             {1815} V2\n            Host 0 (paired): feathora\n            Host 1 (unpaired):\n            Host 2 (unpaired):\n        12: XY STATS               {2250} V1\n        13: LOWRES WHEEL           {2130} V0\n            Wheel Reports: HID\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        14: ADJUSTABLE DPI         {2201} V2\n            Sensitivity (DPI) (saved): 1600\n            Sensitivity (DPI)        : 1600\n        15: DFUCONTROL             {00C3} V0\n        16: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010\n        17: unknown:1803           {1803} V0    internal, hidden, unknown:000010\n        18: CONFIG DEVICE PROPS    {1806} V8    internal, hidden, unknown:000010\n        19: unknown:1816           {1816} V0    internal, hidden, unknown:000010\n        20: OOBSTATE               {1805} V0    internal, hidden\n        21: unknown:1830           {1830} V0    internal, hidden, unknown:000010\n        22: unknown:1891           {1891} V7    internal, hidden, unknown:000008\n        23: unknown:18A1           {18A1} V0    internal, hidden, unknown:000010\n        24: unknown:1E00           {1E00} V0    hidden\n        25: unknown:1E02           {1E02} V0    internal, hidden\n        26: unknown:1E22           {1E22} V1    internal, hidden, unknown:000010\n        27: unknown:1602           {1602} V0\n        28: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010\n        29: unknown:1861           {1861} V1    internal, hidden, unknown:000010\n        30: unknown:18B1           {18B1} V0    internal, hidden, unknown:000010\n        31: unknown:920A           {920A} V0    internal, hidden, unknown:000010\n     Has 7 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, analytics key events, pos:0, group:1, group mask:empty\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, analytics key events, pos:0, group:1, group mask:empty\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: DPI Switch                , default: DPI Switch                  => DPI Switch\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         6: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty\n             reporting: default\n     Battery: 100%, discharging.\n"
  },
  {
    "path": "docs/devices/LIFT VERTICAL ERGONOMIC MOUSE B031.txt",
    "content": "Solaar version 1.1.4\n\n  2: LIFT VERTICAL ERGONOMIC MOUSE\n     Device path  : None\n     WPID         : B031\n     Codename     : LIFT\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number: E86E35D0\n     Model ID:      B03100000000\n     Unit ID:       E86E35D0\n        Bootloader: BL1 56.00.B0008\n          Firmware: RBM 21.00.B0008\n             Other:\n     The power switch is located on the (unknown).\n     Supports 31 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BL1 56.00.B0008 B0317599BD37\n            Firmware: Firmware RBM 21.00.B0008 B0317599BD37\n            Firmware: Other\n            Unit ID: E86E35D0  Model ID: B03100000000  Transport IDs: {'btleid': 'B031'}\n         3: DEVICE NAME            {0005}\n            Name: LIFT VERTICAL ERGONOMIC MOUSE\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: CRYPTO ID              {0021}\n         7: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: LIFT\n         8: UNIFIED BATTERY        {1004}\n         9: REPROG CONTROLS V4     {1B04}\n            DPI Sliding Adjustment (saved): DPI Switch\n            DPI Sliding Adjustment        : Off\n            Mouse Gestures (saved): Off\n            Mouse Gestures        : Off\n            Key/Button Actions (saved): {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, DPI Switch:DPI Switch}\n            Key/Button Actions        : {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, DPI Switch:DPI Switch}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, DPI Switch:Diverted}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, DPI Switch:Diverted}\n        10: CHANGE HOST            {1814}\n            Change Host        : 1:gtronick\n        11: HOSTS INFO             {1815}\n            Host 0 (paired): gtronick\n            Host 1 (paired): LAP0707\n            Host 2 (unpaired):\n        12: XY STATS               {2250}\n        13: LOWRES WHEEL           {2130}\n            Wheel Reports: HID\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        14: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 2400\n            Sensitivity (DPI)        : 2400\n        15: DFUCONTROL             {00C3}\n        16: DEVICE RESET           {1802}   internal, hidden, unknown:000010\n        17: unknown:1803           {1803}   internal, hidden, unknown:000010\n        18: CONFIG DEVICE PROPS    {1806}   internal, hidden, unknown:000010\n        19: unknown:1816           {1816}   internal, hidden, unknown:000010\n        20: OOBSTATE               {1805}   internal, hidden\n        21: unknown:1830           {1830}   internal, hidden, unknown:000010\n        22: unknown:1891           {1891}   internal, hidden, unknown:000008\n        23: unknown:18A1           {18A1}   internal, hidden, unknown:000010\n        24: unknown:1E00           {1E00}   hidden\n        25: unknown:1E02           {1E02}   internal, hidden\n        26: unknown:1E22           {1E22}   internal, hidden, unknown:000010\n        27: unknown:1602           {1602}\n        28: unknown:1EB0           {1EB0}   internal, hidden, unknown:000010\n        29: unknown:1861           {1861}   internal, hidden, unknown:000010\n        30: unknown:18B1           {18B1}   internal, hidden, unknown:000010\n     Has 7 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, analytics key events, pos:0, group:1, group mask:empty\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, analytics key events, pos:0, group:1, group mask:empty\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: DPI Switch                , default: DPI Switch                  => DPI Switch\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3\n             reporting: diverted, raw XY diverted\n         6: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty\n             reporting: default\n     Battery: 100%, discharging.\n"
  },
  {
    "path": "docs/devices/Lightspeed Receiver C539.txt",
    "content": "Solaar version 1.1.4\n\nLightspeed Receiver\n  Device path  : /dev/hidraw8\n  USB id       : 046d:C539\n  Serial       : C1469DD4\n    Firmware   : 39.06.B0040\n    Bootloader : 02.09\n    Other      : AA.BE\n  Has 1 paired device(s) out of a maximum of 1.\n  Notifications: wireless, software present (0x000900)\n  Device activity counters: (empty)\n\nSeen paired with G502 Gaming Mouse 407F\nSeen paired with G Pro Wireless Gaming Mouse 4079\n"
  },
  {
    "path": "docs/devices/Lightspeed Receiver C53A.txt",
    "content": "Lightspeed Receiver\n  Device path  : /dev/hidraw9\n  USB id       : 046d:C53A\n  Serial       : 5B2B9A98\n    Firmware   : 40.03.B0014\n    Bootloader : 02.09\n    Other      : AA.CA\n  Has 2 paired device(s) out of a maximum of 1.\n  Notifications: wireless, software present (0x000900)\n  Device activity counters: (empty)\n\nSeen as part of a G PowerPlay Wireless Mouse Pad with a Candy companion chip paired a number 7\nSeen paired with a G502 Gaming Mouse 407F.\n"
  },
  {
    "path": "docs/devices/Lightspeed Receiver C53D.txt",
    "content": "Solaar version 1.1.3\n\nLightspeed Receiver\n  Device path  : /dev/hidraw2\n  USB id       : 046d:C53D\n  Serial       : C271A999\n    Firmware   : 43.01.B0009\n    Bootloader : 02.10\n    Other      : AA.D2\n  Has 1 paired device(s) out of a maximum of 1.\n  Notifications: wireless, software present (0x000900)\n  Device activity counters: (empty)\n\nSeen paired with G613 Wireless Mechanical Gaming Keyboard 4065\n"
  },
  {
    "path": "docs/devices/Lightspeed Receiver C53F.txt",
    "content": "Lightspeed Receiver\n  Device path  : /dev/hidraw3\n  USB id       : 046d:C53F\n  Serial       :\n    Firmware   : 44.01.B0005\n    Bootloader : 00.02\n    Other      : AA.DE\n  Has 0 paired device(s) out of a maximum of 1.\n  Notifications: wireless, software present (0x000900)\n  Device activity counters: (empty)\n"
  },
  {
    "path": "docs/devices/Lightspeed Receiver C541.txt",
    "content": "Solaar version 1.1.1\n\nLightspeed Receiver\n  Device path  : /dev/hidraw4\n  USB id       : 046d:C541\n  Serial       : 18E8EC31\n    Firmware   : 01.01.B0027\n    Bootloader : 01.27\n    Other      : B9.BC\n  Has 1 paired device(s) out of a maximum of 1.\n  Notifications: wireless, software present (0x000900)\n  Device activity counters: (empty)\n\nSeen paired with G915 WIRELESS RGB Mechanical Gaming Keyboard 407E\n"
  },
  {
    "path": "docs/devices/Lightspeed Receiver C545.txt",
    "content": "Solaar version 1.1.4\n\nLightspeed Receiver\n  Device path  : /dev/hidraw5\n  USB id       : 046d:C545\n  Serial       : AD1567FD\n    Firmware   : 02.01.B0006\n    Bootloader : 00.01\n    Other      : 3D.88\n  Has 1 paired device(s) out of a maximum of 2.\n  Notifications: wireless, software present (0x000900)\n  Device activity counters: 1=22\n\nSeen paired with G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard 408E\n"
  },
  {
    "path": "docs/devices/Lightspeed Receiver C547.txt",
    "content": "Solaar version 1.1.3\n\nLightspeed Receiver\n  Device path  : /dev/hidraw6\n  USB id       : 046d:C547\n  Serial       : 9B341CD1\n    Firmware   : 04.02.B0009\n    Bootloader : 00.05\n    Other      : F3.24\n  Has 1 paired device(s) out of a maximum of 2.\n  Notifications: wireless, software present (0x000900)\n  Device activity counters: 1=171\n\nSeen paired with the PRO X Wireless 4093\n"
  },
  {
    "path": "docs/devices/Logi Pop Keys B365.txt",
    "content": "solaar version 1.1.8\n\nBolt Receiver\n  Device path  : /dev/hidraw2\n  USB id       : 046d:C548\n  Serial       : 31454343464242444143334635323035\n  Has 1 paired device(s) out of a maximum of 6.\n  Notifications: wireless, software present (0x000900)\n  Device activity counters: 1=28\n\n  1: Logi POP Keys\n     Device path  : None\n     WPID         : B365\n     Codename     : Logi POP Keys\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Serial number: D1F99582\n     Model ID:      B36500000000\n     Unit ID:       D1F99582\n        Bootloader: BL1 44.01.B0008\n          Firmware: RBK 69.01.B0008\n             Other:\n     The power switch is located on the (unknown).\n     Supports 31 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BL1 44.01.B0008 B3652BE8BAF4\n            Firmware: Firmware RBK 69.01.B0008 B3652BE8BAF4\n            Firmware: Other\n            Unit ID: D1F99582  Model ID: B36500000000  Transport IDs: {'btleid': 'B365'}\n         3: DEVICE NAME            {0005} V0\n            Name: Logi POP Keys\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: Logi POP Keys\n         7: UNIFIED BATTERY        {1004} V3\n            Battery: 100%, discharging.\n         8: REPROG CONTROLS V4     {1B04} V5\n            Key/Button Diversion (saved): {Show Desktop:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, Voice Dictation:Regular, Emoji Smiley Heart Eyes:Regular, Emoji Crying Face:Regular, Emoji Smiley:Regular, Emoji Smilie With Tears:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Mute Microphone:Regular}\n            Key/Button Diversion        : {Show Desktop:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, Voice Dictation:Regular, Emoji Smiley Heart Eyes:Regular, Emoji Crying Face:Regular, Emoji Smiley:Regular, Emoji Smilie With Tears:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Mute Microphone:Regular}\n         9: CHANGE HOST            {1814} V1\n            Change Host        : 1:astra\n        10: HOSTS INFO             {1815} V2\n            Host 0 (paired): astra\n            Host 1 (unpaired):\n            Host 2 (unpaired):\n        11: K375S FN INVERSION     {40A3} V0\n            Swap Fx function (saved): False\n            Swap Fx function        : False\n        12: LOCK KEY STATE         {4220} V0\n        13: KEYBOARD DISABLE KEYS  {4521} V0\n            Disable keys (saved): {Caps Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Insert:False, Win:False}\n        14: MULTIPLATFORM          {4531} V1\n            Set OS (saved): Windows\n            Set OS        : Windows\n        15: KEYBOARD LAYOUT 2      {4540} V0\n        16: DFUCONTROL             {00C3} V0\n        17: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010\n        18: unknown:1803           {1803} V0    internal, hidden, unknown:000010\n        19: CONFIG DEVICE PROPS    {1806} V8    internal, hidden, unknown:000010\n        20: unknown:1816           {1816} V0    internal, hidden, unknown:000010\n        21: OOBSTATE               {1805} V0    internal, hidden\n        22: unknown:1830           {1830} V0    internal, hidden, unknown:000010\n        23: unknown:1891           {1891} V7    internal, hidden, unknown:000008\n        24: unknown:18A1           {18A1} V0    internal, hidden, unknown:000010\n        25: unknown:1E00           {1E00} V0    hidden\n        26: unknown:1E02           {1E02} V0    internal, hidden\n        27: unknown:1602           {1602} V0\n        28: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010\n        29: unknown:1861           {1861} V1    internal, hidden, unknown:000010\n        30: unknown:18B0           {18B0} V0    internal, hidden, unknown:000010\n     Has 20 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             is FN, FN sensitive, analytics key events, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             is FN, FN sensitive, analytics key events, pos:2, group:0, group mask:empty\n             reporting: default\n         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             is FN, FN sensitive, analytics key events, pos:3, group:0, group mask:empty\n             reporting: default\n         3: Show Desktop              , default: Show Desktop                => Show Desktop\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:4, group:0, group mask:empty\n             reporting: default\n         4: Snipping Tool             , default: Snipping Tool               => Snipping Tool\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:5, group:0, group mask:empty\n             reporting: default\n         5: Mute Microphone           , default: Mute Microphone             => Mute Microphone\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:6, group:0, group mask:empty\n             reporting: default\n         6: Previous Fn               , default: Previous                    => Previous\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:7, group:0, group mask:empty\n             reporting: default\n         7: Play/Pause Fn             , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:8, group:0, group mask:empty\n             reporting: default\n         8: Next Fn                   , default: Next                        => Next\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:9, group:0, group mask:empty\n             reporting: default\n         9: Mute Fn                   , default: Mute                        => Mute\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:10, group:0, group mask:empty\n             reporting: default\n        10: Volume Down Fn            , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:11, group:0, group mask:empty\n             reporting: default\n        11: Volume Up Fn              , default: Volume Up                   => Volume Up\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:12, group:0, group mask:empty\n             reporting: default\n        12: Voice Dictation           , default: Voice Dictation             => Voice Dictation\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        13: Emoji Smiley Heart Eyes   , default: Emoji Smiling Face With Heart Shaped Eyes => Emoji Smiling Face With Heart Shaped Eyes\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        14: Emoji Crying Face         , default: Emoji Loudly Crying Face    => Emoji Loudly Crying Face\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        15: Emoji Smiley              , default: Emoji Smiley                => Emoji Smiley\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Emoji Smilie With Tears   , default: Emoji Smiley With Tears     => Emoji Smiley With Tears\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Open Emoji Panel          , default: Open Emoji Panel            => Open Emoji Panel\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        18: F Lock                    , default: Do Nothing One              => Do Nothing One\n             is FN, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        19: FN Key                    , default: Do Nothing One              => Do Nothing One\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n     Battery: 100%, discharging.\n"
  },
  {
    "path": "docs/devices/Logitech G933 Gaming Wireless Headset 0A5B.txt",
    "content": "solaar version 1.1.19-25-g7520c9cc\n\nLogitech G933 Gaming Wireless Headset\n     Device path  : /dev/hidraw4\n     USB id       : 046d:0A5B\n     Codename     : Logitech\n     Kind         : ?\n     Protocol     : HID++ 4.2\n     Serial number:\n     Model ID:      000000000A5B\n     Unit ID:       FFFFFFFF\n                 0: U   98.03.B0027\n     Supports 9 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: 0 U   98.03.B0027 0A5B\n            Unit ID: FFFFFFFF  Model ID: 000000000A5B  Transport IDs: {'btid': '0000', 'btleid': '0000'}\n         3: DEVICE NAME            {0005} V0\n            Name: Logitech G933 Gaming Wireless Headset\n            Kind: None\n         4: COLOR LED EFFECTS      {8070} V3\n            LED Control        : HID++ error {'number': 255, 'request': 1147, 'error': 7, 'params': b''}\n            LEDs None (saved): !LEDEffectSetting {ID: 0}\n            LEDs None        : !LEDEffectSetting {ID: 0}\n            LEDs None (saved): !LEDEffectSetting {ID: 0, color: 9519532, intensity: 0, period: 100, ramp: 0, speed: 0}\n            LEDs None        : !LEDEffectSetting {ID: 1, color: 0, ramp: 0}\n         5: GKEY                   {8010} V0\n            Divert G and M Keys (saved): False\n            Divert G and M Keys        : False\n         6: EQUALIZER              {8310} V1\n            Equalizer (saved): {0: 8, 1: 8, 2: 4, 3: 2, 4: 1, 5: 4, 6: 7, 7: 10, 8: 5, 9: 11}\n            Equalizer        : {0: 8, 1: 8, 2: 4, 3: 2, 4: 1, 5: 4, 6: 7, 7: 10, 8: 5, 9: 11}\n         7: SIDETONE               {8300} V0\n            Sidetone (saved): 30\n            Sidetone        : 30\n         8: ADC MEASUREMENT        {1F20} V3\n            Battery: 100% 4183mV , BatteryStatus.RECHARGING.\n            Power Management (saved): 30\n            Power Management        : 30\n     Battery: 100% 4183mV , BatteryStatus.RECHARGING.\n"
  },
  {
    "path": "docs/devices/Logitech PRO X Wireless Gaming Headset 0ABA.txt",
    "content": "\n  1: Logitech PRO X Wireless Gaming Headset\n     Device path  : /dev/hidraw2\n     USB id       : 046d:0ABA\n     Codename     : PRO Headset\n     Kind         : headset\n     Protocol     : HID++ 4.2\n     Serial number:\n     Model ID:      000000000ABA\n     Unit ID:       FFFFFFFF\n          Firmware: U1  12.01.B0203\n     Supports 6 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Firmware U1  12.01.B0203 0ABA\n            Unit ID: FFFFFFFF  Model ID: 000000000ABA  Transport IDs: {'btid': '0000', 'btleid': '0000'}\n         3: DEVICE NAME            {0005}\n            Name: PRO X Wireless Gaming Headset\n            Kind: None\n         4: EQUALIZER              {8310}\n         5: SIDETONE               {8300}\n         6: ADC MEASUREMENT        {1F20}\n     Battery status unavailable.\n\n\n  2: Logitech PRO X Wireless Gaming Headset\n     Device path  : /dev/hidraw5\n     USB id       : 046d:0ABA\n     Codename     : PRO Headset\n     Kind         : headset\n     Protocol     : HID++ 4.2\n     Serial number:\n     Model ID:      000000000ABA\n     Unit ID:       FFFFFFFF\n          Firmware: U1  12.01.B0203\n     Supports 6 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Firmware U1  12.01.B0203 0ABA\n            Unit ID: FFFFFFFF  Model ID: 000000000ABA  Transport IDs: {'btid': '0000', 'btleid': '0000'}\n         3: DEVICE NAME            {0005}\n            Name: PRO X Wireless Gaming Headset\n            Kind: None\n         4: EQUALIZER              {8310}\n         5: SIDETONE               {8300}\n            Sidetone (saved): 0\n            Sidetone        : 0\n     Battery status unavailable.\n"
  },
  {
    "path": "docs/devices/M720 Triathlon Multi-Device Mouse 405E.txt",
    "content": "Solaar version 1.1.1\n\n  1: M720 Triathlon Multi-Device Mouse\n     Device path  : /dev/hidraw1\n     WPID         : 405E\n     Codename     : M720 Triathlon\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 205F2717\n     Model ID:      B015405E0000\n     Unit ID:       C738473C\n        Bootloader: BOT 34.01.B0005\n          Firmware: MPM 04.10.B0013\n             Other:\n     The power switch is located on the base.\n     Supports 36 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 34.01.B0005 000000A96719\n            Firmware: Firmware MPM 04.10.B0013 405E00A96719\n            Firmware: Other\n            Unit ID: C738473C  Model ID: B015405E0000  Transport IDs: {'btleid': 'B015', 'wpid': '405E'}\n         3: DEVICE NAME            {0005}\n            Name: M720 Triathlon Multi-Device Mouse\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: CRYPTO ID              {0021}\n         7: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: M720 Triathlon\n         8: BATTERY STATUS         {1000}\n            Battery: 90%, discharging, next level 50%.\n         9: CHANGE HOST            {1814}\n            Change Host        : 2:desktop\n        10: HOSTS INFO             {1815}\n            Host 0 (paired): rpi\n            Host 1 (paired): desktop\n            Host 2 (paired): laptop\n        11: REPROG CONTROLS V4     {1B04}\n            Key/Button Actions (saved): {'208': 208, '80': 80, '81': 81, '82': 82, '83': 83, '86': 86, '91': 91, '93': 93}\n            Key/Button Actions        : {'80': 80, '81': 81, '82': 82, '83': 83, '86': 86, '91': 91, '93': 93, '208': 208}\n            Key/Button Diversion (saved): {'208': 0, '82': 0, '83': 0, '86': 0, '91': 0, '93': 0}\n            Key/Button Diversion        : {'82': 0, '83': 0, '86': 0, '91': 0, '93': 0, '208': 0}\n        12: PERSISTENT REMAPPABLE ACTION {1C00}\n        13: POINTER SPEED          {2205}\n            Pointer Speed: 1.0\n            Sensitivity (Pointer Speed) (saved): 256\n            Sensitivity (Pointer Speed)        : 256\n        14: VERTICAL SCROLLING     {2100}\n            Roller type: 3G\n            Ratchet per turn: 24\n            Scroll lines: 0\n        15: DFUCONTROL UNSIGNED    {00C1}\n        16: DFUCONTROL SIGNED      {00C2}\n        17: DEVICE RESET           {1802}   internal, hidden\n        18: unknown:1803           {1803}   internal, hidden\n        19: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        20: OOBSTATE               {1805}   internal, hidden\n        21: unknown:1813           {1813}   internal, hidden\n        22: unknown:1830           {1830}   internal, hidden\n        23: unknown:1861           {1861}   internal, hidden\n        24: unknown:1890           {1890}   internal, hidden\n        25: unknown:1891           {1891}   internal, hidden\n        26: unknown:18A1           {18A1}   internal, hidden\n        27: unknown:1DF3           {1DF3}   internal, hidden\n        28: unknown:1E00           {1E00}   hidden\n        29: unknown:1EB0           {1EB0}   internal, hidden\n        30: unknown:18B1           {18B1}   internal, hidden\n        31: unknown:1850           {1850}   internal, hidden\n        32: unknown:1E22           {1E22}\n        33: unknown:1F03           {1F03}   internal, hidden\n        34: unknown:18C0           {18C0}   internal, hidden\n        35: HIRES WHEEL            {2121}\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            High resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): True\n            Scroll Wheel Resolution        : True\n     Has 9 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Left Tilt                 , default: Mouse Scroll Left Button    => Mouse Scroll Left Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         6: Right Tilt                , default: Mouse Scroll Right Button   => Mouse Scroll Right Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         7: MultiPlatform Gesture Button, default: Multiplatform Gesture Button => Multiplatform Gesture Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         8: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Battery: 90%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/M720 Triathlon Multi-Device Mouse B015.txt",
    "content": "Solaar version 1.1.4\n\n  1: M720 Triathlon Multi-Device Mouse\n     Device path  : /dev/hidraw0\n     USB id       : 046d:B015\n     Codename     : M720 Triathlon\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number:\n     Model ID:      B015405E0000\n     Unit ID:       E167BBCD\n        Bootloader: BOT 34.01.B0005\n          Firmware: MPM 04.10.B0013\n             Other:\n     Supports 30 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 34.01.B0005 000000A96719\n            Firmware: Firmware MPM 04.10.B0013 B01500A96719\n            Firmware: Other\n            Unit ID: E167BBCD  Model ID: B015405E0000  Transport IDs: {'btleid': 'B015', 'wpid': '405E'}\n         3: DEVICE NAME            {0005}\n            Name: M720 Triathlon Multi-Device Mouse\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: CRYPTO ID              {0021}\n         7: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: M720 Triathlon\n         8: BATTERY STATUS         {1000}\n            Battery: 50%, discharging, next level 20%.\n         9: CHANGE HOST            {1814}\n            Change Host        : 3:shoaib-MacBookPro\n        10: HOSTS INFO             {1815}\n            Host 0 (paired):\n            Host 1 (paired): Shoaib’s MacBook Pro\n            Host 2 (paired): shoaib-MacBookPro\n        11: REPROG CONTROLS V4     {1B04}\n            Mouse Gestures (saved): Off\n            Mouse Gestures        : Off\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button, MultiPlatform Gesture Button:Multiplatform Gesture Button}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button, MultiPlatform Gesture Button:Multiplatform Gesture Button}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular, MultiPlatform Gesture Button:Regular}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular, MultiPlatform Gesture Button:Regular}\n        12: PERSISTENT REMAPPABLE ACTION {1C00}\n            Persistent Key/Button Mapping        : {Left Button:Mouse Button Left, Right Button:Mouse Button Right, Middle Button:Mouse Button Middle, Back Button:Mouse Button Back, Forward Button:Mouse Button Forward, Left Tilt:Horizontal Scroll Left, Right Tilt:Horizontal Scroll Right, MultiPlatform Gesture Button:Alt+Cntrl+TAB}\n        13: POINTER SPEED          {2205}\n            Pointer Speed: 1.0\n            Sensitivity (Pointer Speed) (saved): 256\n            Sensitivity (Pointer Speed)        : 256\n        14: VERTICAL SCROLLING     {2100}\n            Roller type: 3G\n            Ratchet per turn: 24\n            Scroll lines: 0\n        15: DFUCONTROL UNSIGNED    {00C1}\n        16: DFUCONTROL SIGNED      {00C2}\n        17: unknown:1803           {1803}   internal, hidden\n        18: unknown:1813           {1813}   internal, hidden\n        19: unknown:1830           {1830}   internal, hidden\n        20: unknown:18A1           {18A1}   internal, hidden\n        21: unknown:1DF3           {1DF3}   internal, hidden\n        22: unknown:1E00           {1E00}   hidden\n        23: unknown:1EB0           {1EB0}   internal, hidden\n        24: unknown:1861           {1861}   internal, hidden\n        25: unknown:18B1           {18B1}   internal, hidden\n        26: unknown:1850           {1850}   internal, hidden\n        27: unknown:1E22           {1E22}\n        28: unknown:1F03           {1F03}   internal, hidden\n        29: unknown:18C0           {18C0}   internal, hidden\n     Has 9 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Left Tilt                 , default: Mouse Scroll Left Button    => Mouse Scroll Left Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         6: Right Tilt                , default: Mouse Scroll Right Button   => Mouse Scroll Right Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         7: MultiPlatform Gesture Button, default: Multiplatform Gesture Button => Multiplatform Gesture Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         8: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Has 8 persistent remappable keys:\n         0: Left Button                => Mouse Button: Mouse Button Left\n         1: Right Button               => Mouse Button: Mouse Button Right\n         2: Middle Button              => Mouse Button: Mouse Button Middle\n         3: Back Button                => Mouse Button: Mouse Button Back\n         4: Forward Button             => Mouse Button: Mouse Button Forward\n         5: Left Tilt                  => Horizontal Scroll: Horizontal Scroll Left\n         6: Right Tilt                 => Horizontal Scroll: Horizontal Scroll Right\n         7: MultiPlatform Gesture Button => Key: Alt+Cntrl+TAB\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/MX Anywhere 3 4090.txt",
    "content": "Solaar version 1.1.4\n\n\n  1: MX Anywhere 3\n     Device path  : /dev/hidraw3\n     WPID         : 4090\n     Codename     : MX Anywhere 3\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 8F4A05EA\n     Model ID:      B02540900000\n     Unit ID:       8F4A05EA\n        Bootloader: BL1 13.01.B0015\n          Firmware: MPM 24.01.B0015\n             Other:\n     The power switch is located on the base.\n     Supports 32 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BL1 13.01.B0015 0000AACD8D78\n            Firmware: Firmware MPM 24.01.B0015 4090AACD8D78\n            Firmware: Other\n            Unit ID: 8F4A05EA  Model ID: B02540900000  Transport IDs: {'btleid': 'B025', 'wpid': '4090'}\n         3: DEVICE NAME            {0005} V0\n            Name: MX Anywhere 3\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: RESET                  {0020} V0\n         6: CRYPTO ID              {0021} V1\n         7: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: MX Anywhere 3\n         8: UNIFIED BATTERY        {1004} V0\n            Battery: 65%, discharging.\n         9: REPROG CONTROLS V4     {1B04} V5\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Smart Shift:Smart Shift}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Smart Shift:Smart Shift}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Smart Shift:Regular}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Smart Shift:Regular}\n        10: CHANGE HOST            {1814} V1\n            Change Host        : 1:apollo\n        11: XY STATS               {2250} V1\n        12: ADJUSTABLE DPI         {2201} V1\n            Sensibilidade (DPI) (saved): 4000\n            Sensibilidade (DPI)        : 4000\n        13: SMART SHIFT ENHANCED   {2111} V0\n            Scroll Wheel Rachet (saved): 12\n            Scroll Wheel Rachet        : 12\n        14: HIRES WHEEL            {2121} V1\n            Multiplier: 15\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            Low resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): False\n            Scroll Wheel Resolution        : False\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        15: WHEEL STATS            {2251} V0\n        16: DFUCONTROL SIGNED      {00C2} V0\n        17: DEVICE RESET           {1802} V0    internal, hidden\n        18: unknown:1803           {1803} V0    internal, hidden\n        19: CONFIG DEVICE PROPS    {1806} V7    internal, hidden\n        20: unknown:1812           {1812} V0    internal, hidden\n        21: OOBSTATE               {1805} V0    internal, hidden\n        22: unknown:1830           {1830} V0    internal, hidden\n        23: unknown:1890           {1890} V5    internal, hidden\n        24: unknown:1891           {1891} V5    internal, hidden\n        25: unknown:18A1           {18A1} V0    internal, hidden\n        26: unknown:1E00           {1E00} V0    hidden\n        27: unknown:1EB0           {1EB0} V0    internal, hidden\n        28: unknown:1861           {1861} V0    internal, hidden\n        29: unknown:9001           {9001} V0    internal, hidden\n        30: unknown:1E22           {1E22} V0    internal, hidden\n        31: unknown:9205           {9205} V0    internal, hidden\n     Has 7 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Smart Shift               , default: Smart Shift                 => Smart Shift\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         6: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Battery: 65%, discharging.\n"
  },
  {
    "path": "docs/devices/MX Anywhere 3 B025.txt",
    "content": "Solaar version 1.1.4\n\n  1: MX Anywhere 3\n     Device path  : /dev/hidraw1\n     USB id       : 046d:B025\n     Codename     : MX Anywhere 3\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number:\n     Model ID:      B02540900000\n     Unit ID:       179ADDDA\n        Bootloader: BL1 13.00.B0014\n          Firmware: MPM 24.00.B0014\n             Other:\n     Supports 29 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BL1 13.00.B0014 000095D7D19A\n            Firmware: Firmware MPM 24.00.B0014 B02595D7D19A\n            Firmware: Other\n            Unit ID: 179ADDDA  Model ID: B02540900000  Transport IDs: {'btleid': 'B025', 'wpid': '4090'}\n         3: DEVICE NAME            {0005}\n            Name: MX Anywhere 3\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: CRYPTO ID              {0021}\n         7: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: MX Anywhere 3\n         8: UNIFIED BATTERY        {1004}\n            Battery: N/A, None.\n         9: REPROG CONTROLS V4     {1B04}\n            DPI Sliding Adjustment (saved): Off\n            DPI Sliding Adjustment        : Off\n            Mouse Gestures (saved): Off\n            Mouse Gestures        : Off\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Smart Shift:Smart Shift}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Smart Shift:Smart Shift}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Smart Shift:Regular}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Smart Shift:Regular}\n        10: CHANGE HOST            {1814}\n            Change Host        : 1:zerocool\n        11: XY STATS               {2250}\n        12: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 1000\n            Sensitivity (DPI)        : 1000\n        13: SMART SHIFT ENHANCED   {2111}\n            Scroll Wheel Rachet (saved): 12\n            Scroll Wheel Rachet        : 12\n        14: HIRES WHEEL            {2121}\n            Multiplier: 15\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            Low resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): False\n            Scroll Wheel Resolution        : False\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        15: WHEEL STATS            {2251}\n        16: DFUCONTROL SIGNED      {00C2}\n        17: DEVICE RESET           {1802}   internal, hidden\n        18: unknown:1803           {1803}   internal, hidden\n        19: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        20: unknown:1812           {1812}   internal, hidden\n        21: OOBSTATE               {1805}   internal, hidden\n        22: unknown:1830           {1830}   internal, hidden\n        23: unknown:18A1           {18A1}   internal, hidden\n        24: unknown:1E00           {1E00}   hidden\n        25: unknown:1EB0           {1EB0}   internal, hidden\n        26: unknown:1861           {1861}   internal, hidden\n        27: unknown:9300           {9300}   internal, hidden\n        28: unknown:9001           {9001}   internal, hidden\n     Has 7 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Smart Shift               , default: Smart Shift                 => Smart Shift\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         6: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Battery: N/A, None.\n"
  },
  {
    "path": "docs/devices/MX Anywhere 3 for Business B02D.txt",
    "content": "solaar version 1.1.14\n\n  1: MX Anywhere 3 for Business\n     Device path  : None\n     WPID         : B02D\n     Codename     : MX Anywhere 3\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number: 00000000\n     Model ID:      B02D00000000\n     Unit ID:       00000000\n                 1: BL1 36.01.B0011\n                 0: RBM 15.01.B0011\n                 3:\n     The power switch is located on the (unknown).\n     Supports 35 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: 1 BL1 36.01.B0011 B02D1EEFD8F8\n            Firmware: 0 RBM 15.01.B0011 B02D1EEFD8F8\n            Firmware: 3\n            Unit ID: 00000000  Model ID: B02D00000000  Transport IDs: {'btleid': 'B02D'}\n         3: DEVICE NAME            {0005} V0\n            Name: MX Anywhere 3 for Business\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n            Configuration: 11000000000000000000000000000000\n         6: CRYPTO ID              {0021} V1\n         7: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: MX Anywhere 3B\n         8: UNIFIED BATTERY        {1004} V3\n            Battery: 75%, 0.\n         9: REPROG CONTROLS V4     {1B04} V5\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Smart Shift:Smart Shift}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Smart Shift:Diverted}\n        10: CHANGE HOST            {1814} V1\n            Change Host        : 2:archlinux\n        11: HOSTS INFO             {1815} V2\n            Host 0 (paired): archlinux\n            Host 1 (paired): archlinux\n            Host 2 (unpaired):\n        12: XY STATS               {2250} V1\n        13: ADJUSTABLE DPI         {2201} V2\n            Sensitivity (DPI)        : 1000\n        14: SMART SHIFT ENHANCED   {2111} V0\n            Scroll Wheel Ratcheted        : Ratcheted\n            Scroll Wheel Ratchet Speed        : 15\n        15: HIRES WHEEL            {2121} V1\n            Multiplier: 15\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            Low resolution mode\n            HID notification\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution        : False\n            Scroll Wheel Diversion        : False\n        16: WHEEL STATS            {2251} V0\n        17: DFUCONTROL             {00C3} V0\n        18: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010\n        19: unknown:1803           {1803} V0    internal, hidden, unknown:000010\n        20: CONFIG DEVICE PROPS    {1806} V8    internal, hidden, unknown:000010\n        21: unknown:1816           {1816} V0    internal, hidden, unknown:000010\n        22: OOBSTATE               {1805} V0    internal, hidden\n        23: unknown:1830           {1830} V0    internal, hidden, unknown:000010\n        24: unknown:1891           {1891} V7    internal, hidden, unknown:000008\n        25: unknown:18A1           {18A1} V0    internal, hidden, unknown:000010\n        26: unknown:1E00           {1E00} V0    hidden\n        27: unknown:1E02           {1E02} V0    internal, hidden\n        28: unknown:1602           {1602} V0\n        29: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010\n        30: unknown:1861           {1861} V1    internal, hidden, unknown:000010\n        31: unknown:9300           {9300} V1    internal, hidden, unknown:000010\n        32: unknown:9001           {9001} V0    internal, hidden, unknown:000010\n        33: unknown:1E22           {1E22} V0    internal, hidden, unknown:000010\n        34: unknown:9205           {9205} V0    internal, hidden, unknown:000010\n     Has 7 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Smart Shift               , default: Smart Shift                 => Smart Shift\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: diverted, raw XY diverted\n         6: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Battery: 75%, 0.\n"
  },
  {
    "path": "docs/devices/MX Ergo Multi-Device Trackball 406F.txt",
    "content": "Solaar version 1.1.4\n\n  1: MX Ergo Multi-Device Trackball\n     Device path  : /dev/hidraw4\n     WPID         : 406F\n     Codename     : MX Ergo\n     Kind         : trackball\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 0E0F20E7\n     Model ID:      B01D406F0000\n     Unit ID:       13AF9325\n        Bootloader: BOT 49.00.B0001\n          Firmware: MPM 06.03.B0022\n             Other:\n     The power switch is located on the base.\n     Supports 35 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 49.00.B0001 0000CDE885F3\n            Firmware: Firmware MPM 06.03.B0022 406FCDE885F3\n            Firmware: Other\n            Unit ID: 13AF9325  Model ID: B01D406F0000  Transport IDs: {'btleid': 'B01D', 'wpid': '406F'}\n         3: DEVICE NAME            {0005}\n            Name: MX Ergo Multi-Device Trackball\n            Kind: trackball\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: MX Ergo\n         6: RESET                  {0020}\n         7: CRYPTO ID              {0021}\n         8: BATTERY STATUS         {1000}\n            Battery: 50%, discharging, next level 20%.\n         9: LED CONTROL            {1300}\n        10: REPROG CONTROLS V4     {1B04}\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button, DPI Change:DPI Change}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button, DPI Change:DPI Change}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular, DPI Change:Regular}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular, DPI Change:Regular}\n        11: PERSISTENT REMAPPABLE ACTION {1C00}\n            Persistent Key/Button Mapping        : {Left Button:Mouse Button Left, Right Button:Mouse Button Right, Middle Button:Mouse Button Middle, Back Button:Mouse Button Back, Forward Button:Mouse Button Forward, Left Tilt:Horizontal Scroll Left, Right Tilt:Horizontal Scroll Right, DPI Change:Mouse Button DPI}\n        12: POINTER AXIS ORIENTATION {2006}\n        13: POINTER SPEED          {2205}\n            Pointer Speed: 1.046875\n            Sensitivity (Pointer Speed) (saved): 268\n            Sensitivity (Pointer Speed)        : 268\n            Sensitivity Switching (saved): Off\n            Sensitivity Switching        : Off\n        14: VERTICAL SCROLLING     {2100}\n            Roller type: standard\n            Ratchet per turn: 18\n            Scroll lines: 0\n        15: DFUCONTROL SIGNED      {00C2}\n        16: DEVICE RESET           {1802}   internal, hidden\n        17: unknown:1803           {1803}   internal, hidden\n        18: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        19: OOBSTATE               {1805}   internal, hidden\n        20: unknown:1813           {1813}   internal, hidden\n        21: CHANGE HOST            {1814}\n            Change Host        : 1:razorback\n        22: HOSTS INFO             {1815}\n            Host 0 (paired): razorback\n            Host 1 (unpaired):\n            Host 2 (unpaired):\n        23: unknown:1830           {1830}   internal, hidden\n        24: unknown:1861           {1861}   internal, hidden\n        25: unknown:1890           {1890}   internal, hidden\n        26: unknown:1891           {1891}   internal, hidden\n        27: unknown:18A1           {18A1}   internal, hidden\n        28: unknown:1DF3           {1DF3}   internal, hidden\n        29: unknown:1E00           {1E00}   hidden\n        30: unknown:1EB0           {1EB0}   internal, hidden\n        31: unknown:18B1           {18B1}   internal, hidden\n        32: unknown:1850           {1850}   internal, hidden\n        33: unknown:1F03           {1F03}   internal, hidden\n        34: unknown:18C0           {18C0}   internal, hidden\n     Has 9 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: DPI Change                , default: DPI Change                  => DPI Change\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         6: Left Tilt                 , default: Mouse Scroll Left Button    => Mouse Scroll Left Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         7: Right Tilt                , default: Mouse Scroll Right Button   => Mouse Scroll Right Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         8: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Has 8 persistent remappable keys:\n         0: Left Button                => Mouse Button: Mouse Button Left\n         1: Right Button               => Mouse Button: Mouse Button Right\n         2: Middle Button              => Mouse Button: Mouse Button Middle\n         3: Back Button                => Mouse Button: Mouse Button Back\n         4: Forward Button             => Mouse Button: Mouse Button Forward\n         5: DPI Change                 => Mouse Button: Mouse Button DPI\n         6: Left Tilt                  => Horizontal Scroll: Horizontal Scroll Left\n         7: Right Tilt                 => Horizontal Scroll: Horizontal Scroll Right\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/MX Keys Keyboard 408A.txt",
    "content": "Solaar version 1.1.4\n\n  1: MX Keys Keyboard\n     Device path  : /dev/hidraw1\n     WPID         : 408A\n     Codename     : MX Keys\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Polling rate : 20 ms (50Hz)\n     Serial number: F359F7AC\n     Model ID:      B35B408A0000\n     Unit ID:       F359F7AC\n        Bootloader: BL1 08.00.B0011\n          Firmware: MPK 12.00.B0011\n             Other:\n     The power switch is located on the edge of top right corner.\n     Supports 32 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Bootloader BL1 08.00.B0011 00008169E8BB\n            Firmware: Firmware MPK 12.00.B0011 408A8169E8BB\n            Firmware: Other\n            Unit ID: F359F7AC  Model ID: B35B408A0000  Transport IDs: {'btleid': 'B35B', 'wpid': '408A'}\n         3: DEVICE NAME            {0005} V0\n            Name: MX Keys Wireless Keyboard\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: RESET                  {0020} V0\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: MX Keys\n         7: BATTERY STATUS         {1000} V1\n            Battery: 50%, discharging, next level 20%.\n         8: REPROG CONTROLS V4     {1B04} V4\n            Key/Button Diversion (saved): {Calculator:Regular, Show Desktop:Regular, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular}\n            Key/Button Diversion        : {Calculator:Regular, Show Desktop:Regular, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular}\n         9: CHANGE HOST            {1814} V1\n        10: HOSTS INFO             {1815} V1\n            Host 0 (paired): brandy\n            Host 1 (paired): Pixel 2\n            Host 2 (paired): devlaptop002\n        11: BACKLIGHT2             {1982} V1\n            Backlight (saved): True\n            Backlight        : True\n        12: K375S FN INVERSION     {40A3} V0\n            Swap Fx function (saved): False\n            Swap Fx function        : False\n        13: ENCRYPTION             {4100} V0\n        14: LOCK KEY STATE         {4220} V0\n        15: KEYBOARD DISABLE KEYS  {4521} V0\n            Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        16: MULTIPLATFORM          {4531} V1\n            Set OS (saved): Windows\n            Set OS        : Windows\n        17: DFUCONTROL SIGNED      {00C2} V0\n        18: DEVICE RESET           {1802} V0    internal, hidden\n        19: unknown:1803           {1803} V0    internal, hidden\n        20: CONFIG DEVICE PROPS    {1806} V5    internal, hidden\n        21: unknown:1813           {1813} V0    internal, hidden\n        22: OOBSTATE               {1805} V0    internal, hidden\n        23: unknown:1830           {1830} V0    internal, hidden\n        24: unknown:1890           {1890} V5    internal, hidden\n        25: unknown:1891           {1891} V5    internal, hidden\n        26: unknown:18A1           {18A1} V0    internal, hidden\n        27: unknown:1DF3           {1DF3} V0    internal, hidden\n        28: unknown:1E00           {1E00} V0    hidden\n        29: unknown:1EB0           {1EB0} V0    internal, hidden\n        30: unknown:1861           {1861} V0    internal, hidden\n        31: unknown:1A20           {1A20} V0    internal, hidden\n     Has 24 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n         3: Brightness Down           , default: Brightness Down             => Brightness Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:1, group:0, group mask:empty\n             reporting: default\n         4: Brightness Up             , default: Brightness Up               => Brightness Up\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:2, group:0, group mask:empty\n             reporting: default\n         5: Mission Control/Task View , default: Mission Control/Task View   => Mission Control/Task View\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:3, group:0, group mask:empty\n             reporting: default\n         6: Dashboard Launchpad/Action Center, default: Dashboard Launchpad/Action Center => Dashboard Launchpad/Action Center\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:4, group:0, group mask:empty\n             reporting: default\n         7: Show Desktop              , default: Show Desktop                => Show Desktop\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:5, group:0, group mask:empty\n             reporting: default\n         8: Backlight Down            , default: Backlight Down              => Backlight Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:6, group:0, group mask:empty\n             reporting: default\n         9: Backlight Up              , default: Backlight Up                => Backlight Up\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:7, group:0, group mask:empty\n             reporting: default\n        10: Previous Fn               , default: Previous                    => Previous\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:8, group:0, group mask:empty\n             reporting: default\n        11: Play/Pause Fn             , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:9, group:0, group mask:empty\n             reporting: default\n        12: Next Fn                   , default: Next                        => Next\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:10, group:0, group mask:empty\n             reporting: default\n        13: Mute Fn                   , default: Mute                        => Mute\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:11, group:0, group mask:empty\n             reporting: default\n        14: Volume Down Fn            , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:12, group:0, group mask:empty\n             reporting: default\n        15: Volume Up Fn              , default: Volume Up                   => Volume Up\n             nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Calculator                , default: Calculator                  => Calculator\n             nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Screen Capture/Print Screen, default: Screen Capture              => Screen Capture\n             nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        18: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu\n             nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        19: Lock PC                   , default: WindowsLock                 => WindowsLock\n             nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        20: Left Arrow                , default: Keyboard Left Arrow         => Keyboard Left Arrow\n             nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        21: Right Arrow               , default: Keyboard Right Arrow        => Keyboard Right Arrow\n             nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        22: F Lock                    , default: Do Nothing One              => Do Nothing One\n             is FN, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        23: FN Key                    , default: Do Nothing One              => Do Nothing One\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/MX Keys Keyboard B35B.txt",
    "content": "Solaar version 1.1.4rc1\n\n  1: MX Keys Keyboard\n     Device path  : /dev/hidraw8\n     USB id       : 046d:B35B\n     Codename     : MX Keys\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Serial number:\n     Model ID:      B35B408A0000\n     Unit ID:       EC96CD5C\n        Bootloader: BL1 08.00.B0011\n          Firmware: MPK 12.01.B0013\n             Other:\n     Supports 29 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BL1 08.00.B0011 00008169E8BB\n            Firmware: Firmware MPK 12.01.B0013 B35BFE037737\n            Firmware: Other\n            Unit ID: EC96CD5C  Model ID: B35B408A0000  Transport IDs: {'btleid': 'B35B', 'wpid': '408A'}\n         3: DEVICE NAME            {0005}\n            Name: MX Keys Wireless Keyboard\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: MX Keys\n         7: BATTERY STATUS         {1000}\n            Battery: 100%, discharging, next level 50%.\n         8: REPROG CONTROLS V4     {1B04}\n            Key/Button Diversion (saved): {Calculator:Regular, Show Desktop:Regular, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular}\n            Key/Button Diversion        : {Calculator:Regular, Show Desktop:Regular, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular}\n         9: CHANGE HOST            {1814}\n            Change Host        : 1:ak\n        10: HOSTS INFO             {1815}\n            Host 0 (paired): ak\n            Host 1 (unpaired):\n            Host 2 (unpaired):\n        11: BACKLIGHT2             {1982}\n            Backlight (saved): True\n            Backlight        : True\n        12: K375S FN INVERSION     {40A3}\n            Swap Fx function (saved): True\n            Swap Fx function        : True\n        13: ENCRYPTION             {4100}\n        14: LOCK KEY STATE         {4220}\n        15: KEYBOARD DISABLE KEYS  {4521}\n            Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        16: MULTIPLATFORM          {4531}\n            Set OS (saved): MacOS\n            Set OS        : MacOS\n        17: DFUCONTROL SIGNED      {00C2}\n        18: DEVICE RESET           {1802}   internal, hidden\n        19: unknown:1803           {1803}   internal, hidden\n        20: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        21: unknown:1813           {1813}   internal, hidden\n        22: OOBSTATE               {1805}   internal, hidden\n        23: unknown:1830           {1830}   internal, hidden\n        24: unknown:18A1           {18A1}   internal, hidden\n        25: unknown:1E00           {1E00}   hidden\n        26: unknown:1EB0           {1EB0}   internal, hidden\n        27: unknown:1861           {1861}   internal, hidden\n        28: unknown:1A20           {1A20}   internal, hidden\n     Has 24 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n         3: Brightness Down           , default: Brightness Down             => Brightness Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:1, group:0, group mask:empty\n             reporting: default\n         4: Brightness Up             , default: Brightness Up               => Brightness Up\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:2, group:0, group mask:empty\n             reporting: default\n         5: Mission Control/Task View , default: Mission Control/Task View   => Mission Control/Task View\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:3, group:0, group mask:empty\n             reporting: default\n         6: Dashboard Launchpad/Action Center, default: Dashboard Launchpad/Action Center => Dashboard Launchpad/Action Center\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:4, group:0, group mask:empty\n             reporting: default\n         7: Show Desktop              , default: Show Desktop                => Show Desktop\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:5, group:0, group mask:empty\n             reporting: default\n         8: Backlight Down            , default: Backlight Down              => Backlight Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:6, group:0, group mask:empty\n             reporting: default\n         9: Backlight Up              , default: Backlight Up                => Backlight Up\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:7, group:0, group mask:empty\n             reporting: default\n        10: Previous Fn               , default: Previous                    => Previous\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:8, group:0, group mask:empty\n             reporting: default\n        11: Play/Pause Fn             , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:9, group:0, group mask:empty\n             reporting: default\n        12: Next Fn                   , default: Next                        => Next\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:10, group:0, group mask:empty\n             reporting: default\n        13: Mute Fn                   , default: Mute                        => Mute\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:11, group:0, group mask:empty\n             reporting: default\n        14: Volume Down Fn            , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:12, group:0, group mask:empty\n             reporting: default\n        15: Volume Up Fn              , default: Volume Up                   => Volume Up\n             nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Calculator                , default: Calculator                  => Calculator\n             nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Screen Capture/Print Screen, default: Screen Capture              => Screen Capture\n             nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        18: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu\n             nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        19: Lock PC                   , default: WindowsLock                 => WindowsLock\n             nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        20: Left Arrow                , default: Keyboard Left Arrow         => Keyboard Left Arrow\n             nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        21: Right Arrow               , default: Keyboard Right Arrow        => Keyboard Right Arrow\n             nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        22: F Lock                    , default: Do Nothing One              => Do Nothing One\n             is FN, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        23: FN Key                    , default: Do Nothing One              => Do Nothing One\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n     Battery: 100%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/MX Keys Mini B369.txt",
    "content": "Solaar version 1.1.4\n\n  255: MX Keys Mini\n     Device path  : /dev/hidraw6\n     USB id       : 046d:B369\n     Codename     : MX Keys Mini\n     Kind         : ?\n     Protocol     : HID++ 4.5\n     Serial number:\n     Model ID:      B36900000000\n     Unit ID:       42BABA25\n        Bootloader: BL1 53.01.B0006\n          Firmware: RBK 73.01.B0006\n             Other:\n     Supports 31 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BL1 53.01.B0006 B369FD70F4\n            Firmware: Firmware RBK 73.01.B0006 B369FD70F4\n            Firmware: Other\n            Unit ID: 42BABA25  Model ID: B36900000000  Transport IDs: {'btleid': 'B369'}\n         3: DEVICE NAME            {0005}\n            Name: MX Keys Mini\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: MX Keys Mini\n         7: UNIFIED BATTERY        {1004}\n         8: REPROG CONTROLS V4     {1B04}\n            Key/Button Diversion (saved): {Backlight Down:Regular, Backlight Up:Regular, Play/Pause Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Delete:Regular, Mute Microphone:Regular}\n            Key/Button Diversion        : {Backlight Down:Regular, Backlight Up:Regular, Play/Pause Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Delete:Regular, Mute Microphone:Regular}\n         9: CHANGE HOST            {1814}\n            Change Host        : 3:fedora\n        10: HOSTS INFO             {1815}\n            Host 0 (paired): U308198\n            Host 1 (paired): DESKTOP-9C4GF7M\n            Host 2 (paired): fedora\n        11: BACKLIGHT2             {1982}\n            Backlight (saved): True\n            Backlight        : True\n        12: K375S FN INVERSION     {40A3}\n            Swap Fx function (saved): False\n            Swap Fx function        : False\n        13: LOCK KEY STATE         {4220}\n        14: KEYBOARD DISABLE KEYS  {4521}\n            Disable keys (saved): {Caps Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Insert:False, Win:False}\n        15: MULTIPLATFORM          {4531}\n            Set OS (saved): Windows\n            Set OS        : Windows\n        16: DFUCONTROL             {00C3}\n        17: DEVICE RESET           {1802}   internal, hidden, unknown:000010\n        18: unknown:1803           {1803}   internal, hidden, unknown:000010\n        19: CONFIG DEVICE PROPS    {1806}   internal, hidden, unknown:000010\n        20: unknown:1816           {1816}   internal, hidden, unknown:000010\n        21: OOBSTATE               {1805}   internal, hidden\n        22: unknown:1830           {1830}   internal, hidden, unknown:000010\n        23: unknown:1891           {1891}   internal, hidden, unknown:000008\n        24: unknown:18A1           {18A1}   internal, hidden, unknown:000010\n        25: unknown:1E00           {1E00}   hidden\n        26: unknown:1E02           {1E02}   internal, hidden\n        27: unknown:1602           {1602}\n        28: unknown:1EB0           {1EB0}   internal, hidden, unknown:000010\n        29: unknown:1861           {1861}   internal, hidden, unknown:000010\n        30: unknown:1A20           {1A20}   internal, hidden, unknown:000010\n     Has 16 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             is FN, FN sensitive, analytics key events, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             is FN, FN sensitive, analytics key events, pos:2, group:0, group mask:empty\n             reporting: default\n         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             is FN, FN sensitive, analytics key events, pos:3, group:0, group mask:empty\n             reporting: default\n         3: Backlight Down            , default: Backlight Down              => Backlight Down\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:4, group:0, group mask:empty\n             reporting: default\n         4: Backlight Up              , default: Backlight Up                => Backlight Up\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:5, group:0, group mask:empty\n             reporting: default\n         5: Voice Dictation           , default: Voice Dictation             => Voice Dictation\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:6, group:0, group mask:empty\n             reporting: default\n         6: Open Emoji Panel          , default: Open Emoji Panel            => Open Emoji Panel\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:7, group:0, group mask:empty\n             reporting: default\n         7: Snipping Tool             , default: Snipping Tool               => Snipping Tool\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:8, group:0, group mask:empty\n             reporting: default\n         8: Mute Microphone           , default: Mute Microphone             => Mute Microphone\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:9, group:0, group mask:empty\n             reporting: default\n         9: Play/Pause Fn             , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:10, group:0, group mask:empty\n             reporting: default\n        10: Mute Fn                   , default: Mute                        => Mute\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:11, group:0, group mask:empty\n             reporting: default\n        11: Volume Down Fn            , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:12, group:0, group mask:empty\n             reporting: default\n        12: Volume Up Fn              , default: Volume Up                   => Volume Up\n             nonstandard, reprogrammable, divertable, analytics key events, pos:13, group:0, group mask:empty\n             reporting: default\n        13: Delete                    , default: Delete                      => Delete\n             nonstandard, reprogrammable, divertable, analytics key events, pos:14, group:0, group mask:empty\n             reporting: default\n        14: F Lock                    , default: Do Nothing One              => Do Nothing One\n             is FN, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        15: FN Key                    , default: Do Nothing One              => Do Nothing One\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n     Battery: 40%, discharging.\n"
  },
  {
    "path": "docs/devices/MX Keys S B378.text",
    "content": "solaar version 1.1.10\n\n  1: MX Keys S\n     Device path  : None\n     WPID         : B378\n     Codename     : MX KEYS S\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Serial number: 48548420\n     Model ID:      B37800000000\n     Unit ID:       48548420\n        Bootloader: BL1 88.00.B0013\n          Firmware: RBK 81.00.B0013\n             Other:\n     The power switch is located on the (unknown).\n     Supports 34 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BL1 88.00.B0013 B37851DB9520\n            Firmware: Firmware RBK 81.00.B0013 B37851DB9520\n            Firmware: Other\n            Unit ID: 48548420  Model ID: B37800000000  Transport IDs: {'btleid': 'B378'}\n         3: DEVICE NAME            {0005} V0\n            Name: MX Keys S\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: MX KEYS S\n         7: unknown:0011           {0011} V0\n         8: UNIFIED BATTERY        {1004} V3\n            Battery: 75%, discharging.\n         9: REPROG CONTROLS V4     {1B04} V5\n            Key/Button Diversion (saved): {Calculator:Regular, Lock PC:Regular, Brightness Down:Regular, Brightness Up:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Diverted, Mute Microphone:Regular}\n            Key/Button Diversion        : {Calculator:Regular, Lock PC:Regular, Brightness Down:Regular, Brightness Up:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Diverted, Mute Microphone:Regular}\n        10: CHANGE HOST            {1814} V1\n            Change Host        : 1:vs\n        11: HOSTS INFO             {1815} V2\n            Host 0 (paired): vs\n            Host 1 (paired): DEV\n            Host 2 (unpaired):\n        12: BACKLIGHT2             {1982} V3\n            Backlight (saved): False\n            Backlight        : True\n        13: K375S FN INVERSION     {40A3} V0\n            Swap Fx function (saved): False\n            Swap Fx function        : False\n        14: LOCK KEY STATE         {4220} V0\n        15: KEYBOARD DISABLE KEYS  {4521} V0\n            Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        16: MULTIPLATFORM          {4531} V1\n            Set OS (saved): Linux\n            Set OS        : Linux\n        17: KEYBOARD LAYOUT 2      {4540} V0\n        18: DFUCONTROL             {00C3} V0\n        19: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010\n        20: unknown:1803           {1803} V0    internal, hidden, unknown:000010\n        21: unknown:1807           {1807} V0    internal, hidden, unknown:000010\n        22: unknown:1816           {1816} V0    internal, hidden, unknown:000010\n        23: OOBSTATE               {1805} V0    internal, hidden\n        24: unknown:1830           {1830} V0    internal, hidden, unknown:000010\n        25: unknown:1891           {1891} V7    internal, hidden, unknown:000008\n        26: unknown:18A1           {18A1} V0    internal, hidden, unknown:000010\n        27: unknown:1E00           {1E00} V0    hidden\n        28: unknown:1E02           {1E02} V0    internal, hidden\n        29: unknown:1602           {1602} V0\n        30: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010\n        31: unknown:1861           {1861} V1    internal, hidden, unknown:000010\n        32: unknown:1A20           {1A20} V1    internal, hidden, unknown:000010\n        33: unknown:18B0           {18B0} V1    internal, hidden, unknown:000010\n     Has 21 reprogrammable keys:\n         0: Brightness Down           , default: Brightness Down             => Brightness Down\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Brightness Up             , default: Brightness Up               => Brightness Up\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:2, group:0, group mask:empty\n             reporting: default\n         2: Backlight Down            , default: Backlight Down              => Backlight Down\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:3, group:0, group mask:empty\n             reporting: default\n         3: Backlight Up              , default: Backlight Up                => Backlight Up\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:4, group:0, group mask:empty\n             reporting: default\n         4: Voice Dictation           , default: Voice Dictation             => Voice Dictation\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:5, group:0, group mask:empty\n             reporting: default\n         5: Open Emoji Panel          , default: Open Emoji Panel            => Open Emoji Panel\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:6, group:0, group mask:empty\n             reporting: default\n         6: Mute Microphone           , default: Mute Microphone             => Mute Microphone\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:7, group:0, group mask:empty\n             reporting: default\n         7: Previous Fn               , default: Previous                    => Previous\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:8, group:0, group mask:empty\n             reporting: default\n         8: Play/Pause Fn             , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:9, group:0, group mask:empty\n             reporting: default\n         9: Next Fn                   , default: Next                        => Next\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:10, group:0, group mask:empty\n             reporting: default\n        10: Mute Fn                   , default: Mute                        => Mute\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:11, group:0, group mask:empty\n             reporting: default\n        11: Volume Down Fn            , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:12, group:0, group mask:empty\n             reporting: default\n        12: Volume Up Fn              , default: Volume Up                   => Volume Up\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        13: Calculator                , default: Calculator                  => Calculator\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        14: Snipping Tool             , default: Snipping Tool               => Snipping Tool\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: diverted\n        15: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Lock PC                   , default: WindowsLock                 => WindowsLock\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        18: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        19: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        20: F Lock                    , default: Do Nothing One              => Do Nothing One\n             analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n     Battery: 75%, discharging.\n"
  },
  {
    "path": "docs/devices/MX Keys for Business B363.text",
    "content": "Solaar version 1.1.5\n\n  1: MX Keys for Business\n     Device path  : None\n     WPID         : B363\n     Codename     : MX Keys B\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Serial number: C8457F05\n     Model ID:      B36300000000\n     Unit ID:       C8457F05\n        Bootloader: BL1 31.00.B0009\n          Firmware: RBK 68.00.B0009\n             Other:\n     The power switch is located on the (unknown).\n     Supports 32 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BL1 31.00.B0009 B3636927CBB5\n            Firmware: Firmware RBK 68.00.B0009 B3636927CBB5\n            Firmware: Other\n            Unit ID: C8457F05  Model ID: B36300000000  Transport IDs: {'btleid': 'B363'}\n         3: DEVICE NAME            {0005} V0\n            Name: MX Keys for Business\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: RESET                  {0020} V0\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: MX Keys B\n         7: UNIFIED BATTERY        {1004} V2\n            Battery: 60%, discharging.\n         8: REPROG CONTROLS V4     {1B04} V5\n            Key/Button Diversion (saved): {Calculator:Regular, Lock PC:Regular, Brightness Down:Diverted, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Mute Microphone:Regular}\n            Key/Button Diversion        : {Calculator:Regular, Lock PC:Regular, Brightness Down:Diverted, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Mute Microphone:Regular}\n         9: CHANGE HOST            {1814} V1\n            Change Host        : 1:Ryzen\n        10: HOSTS INFO             {1815} V1\n            Host 0 (paired): Ryzen\n            Host 1 (paired): Ryzen\n            Host 2 (paired): Mi 10 Lite 5G\n        11: BACKLIGHT2             {1982} V1\n            Backlight (saved): True\n            Backlight        : True\n        12: K375S FN INVERSION     {40A3} V0\n            Swap Fx function (saved): False\n            Swap Fx function        : False\n        13: LOCK KEY STATE         {4220} V0\n        14: KEYBOARD DISABLE KEYS  {4521} V0\n            Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        15: MULTIPLATFORM          {4531} V1\n            Set OS (saved): Windows\n            Set OS        : Windows\n        16: DFUCONTROL             {00C3} V0\n        17: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010\n        18: unknown:1803           {1803} V0    internal, hidden, unknown:000010\n        19: CONFIG DEVICE PROPS    {1806} V8    internal, hidden, unknown:000010\n        20: unknown:1816           {1816} V0    internal, hidden, unknown:000010\n        21: OOBSTATE               {1805} V0    internal, hidden\n        22: unknown:1830           {1830} V0    internal, hidden, unknown:000010\n        23: unknown:1891           {1891} V6    internal, hidden, unknown:000008\n        24: unknown:18A1           {18A1} V0    internal, hidden, unknown:000010\n        25: unknown:1E00           {1E00} V0    hidden\n        26: unknown:1E02           {1E02} V0    internal, hidden\n        27: unknown:1602           {1602} V0\n        28: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010\n        29: unknown:1861           {1861} V0    internal, hidden, unknown:000010\n        30: unknown:1A20           {1A20} V0    internal, hidden, unknown:000010\n        31: unknown:18B0           {18B0} V0    internal, hidden, unknown:000010\n     Has 24 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             nonstandard, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             nonstandard, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             nonstandard, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n         3: Brightness Down           , default: Brightness Down             => Brightness Down\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:1, group:0, group mask:empty\n             reporting: diverted\n         4: Brightness Up             , default: Brightness Up               => Brightness Up\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:2, group:0, group mask:empty\n             reporting: default\n         5: Backlight Down            , default: Backlight Down              => Backlight Down\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:3, group:0, group mask:empty\n             reporting: default\n         6: Backlight Up              , default: Backlight Up                => Backlight Up\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:4, group:0, group mask:empty\n             reporting: default\n         7: Voice Dictation           , default: Voice Dictation             => Voice Dictation\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:5, group:0, group mask:empty\n             reporting: default\n         8: Open Emoji Panel          , default: Open Emoji Panel            => Open Emoji Panel\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:6, group:0, group mask:empty\n             reporting: default\n         9: Mute Microphone           , default: Mute Microphone             => Mute Microphone\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:7, group:0, group mask:empty\n             reporting: default\n        10: Previous Fn               , default: Previous                    => Previous\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:8, group:0, group mask:empty\n             reporting: default\n        11: Play/Pause Fn             , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:9, group:0, group mask:empty\n             reporting: default\n        12: Next Fn                   , default: Next                        => Next\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:10, group:0, group mask:empty\n             reporting: default\n        13: Mute Fn                   , default: Mute                        => Mute\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:11, group:0, group mask:empty\n             reporting: default\n        14: Volume Down Fn            , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:12, group:0, group mask:empty\n             reporting: default\n        15: Volume Up Fn              , default: Volume Up                   => Volume Up\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Calculator                , default: Calculator                  => Calculator\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Snipping Tool             , default: Snipping Tool               => Snipping Tool\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        18: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        19: Lock PC                   , default: WindowsLock                 => WindowsLock\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        20: Left Arrow                , default: Keyboard Left Arrow         => Keyboard Left Arrow\n             nonstandard, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        21: Right Arrow               , default: Keyboard Right Arrow        => Keyboard Right Arrow\n             nonstandard, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        22: F Lock                    , default: Do Nothing One              => Do Nothing One\n             is FN, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        23: FN Key                    , default: Do Nothing One              => Do Nothing One\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n     Battery: 60%, discharging.\n"
  },
  {
    "path": "docs/devices/MX Master 3 Wireless Mouse 4082.txt",
    "content": "Solaar version 1.1.4\n\n  1: MX Master 3 Wireless Mouse\n     Device path  : /dev/hidraw2\n     WPID         : 4082\n     Codename     : MX Master 3\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 198E3EB8\n     Model ID:      B02340820000\n     Unit ID:       198E3EB8\n        Bootloader: BOT 95.01.B0015\n          Firmware: MPM 19.01.B0015\n             Other:\n     The power switch is located on the base.\n     Supports 34 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 95.01.B0015 00006A9CA89D\n            Firmware: Firmware MPM 19.01.B0015 40826A9CA89D\n            Firmware: Other\n            Unit ID: 198E3EB8  Model ID: B02340820000  Transport IDs: {'btleid': 'B023', 'wpid': '4082'}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Mouse MX Master 3\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: CRYPTO ID              {0021}\n         7: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: MX Master 3\n         8: BATTERY STATUS         {1000}\n            Battery: 100%, discharging, next level 50%.\n         9: REPROG CONTROLS V4     {1B04}\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Mouse Gestures, Smart Shift:Sliding DPI}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular}\n        10: CHANGE HOST            {1814}\n            Change Host        : 1:idefix\n        11: XY STATS               {2250}\n        12: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 1600\n            Sensitivity (DPI)        : 1600\n        13: SMART SHIFT            {2110}\n            Scroll Wheel Rachet (saved): 32\n            Scroll Wheel Rachet        : 32\n        14: HIRES WHEEL            {2121}\n            Multiplier: 15\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            High resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): True\n            Scroll Wheel Resolution        : True\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        15: THUMB WHEEL            {2150}\n            Thumb Wheel Direction (saved): False\n            Thumb Wheel Direction        : False\n            Thumb Wheel Diversion (saved): False\n            Thumb Wheel Diversion        : False\n        16: WHEEL STATS            {2251}\n        17: DFUCONTROL SIGNED      {00C2}\n        18: DEVICE RESET           {1802}   internal, hidden\n        19: unknown:1803           {1803}   internal, hidden\n        20: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        21: unknown:1813           {1813}   internal, hidden\n        22: OOBSTATE               {1805}   internal, hidden\n        23: unknown:1830           {1830}   internal, hidden\n        24: unknown:1890           {1890}   internal, hidden\n        25: unknown:1891           {1891}   internal, hidden\n        26: unknown:18A1           {18A1}   internal, hidden\n        27: unknown:1DF3           {1DF3}   internal, hidden\n        28: unknown:1E00           {1E00}   hidden\n        29: unknown:1EB0           {1EB0}   internal, hidden\n        30: unknown:1861           {1861}   internal, hidden\n        31: unknown:9001           {9001}   internal, hidden\n        32: unknown:9203           {9203}   internal, hidden\n        33: unknown:9205           {9205}   internal, hidden\n     Has 8 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Mouse Gesture Button      , default: Gesture Button Navigation   => Gesture Button Navigation\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         6: Smart Shift               , default: Smart Shift                 => Smart Shift\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         7: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty\n             reporting: default\n     Battery: 100%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/MX Master 3 Wireless Mouse B023.txt",
    "content": "Solaar version 1.1.4\n\n  1: MX Master 3 Wireless Mouse\n     Device path  : /dev/hidraw5\n     USB id       : 046d:B023\n     Codename     : MX Master 3\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number:\n     Model ID:      B02340820000\n     Unit ID:       198E3EB8\n        Bootloader: BOT 95.01.B0015\n          Firmware: MPM 19.01.B0015\n             Other:\n     Supports 30 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 95.01.B0015 00006A9CA89D\n            Firmware: Firmware MPM 19.01.B0015 B0236A9CA89D\n            Firmware: Other\n            Unit ID: 198E3EB8  Model ID: B02340820000  Transport IDs: {'btleid': 'B023', 'wpid': '4082'}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Mouse MX Master 3\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: CRYPTO ID              {0021}\n         7: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: MX Master 3\n         8: BATTERY STATUS         {1000}\n            Battery: 100%, discharging, next level 50%.\n         9: REPROG CONTROLS V4     {1B04}\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Mouse Gestures, Smart Shift:Sliding DPI}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular}\n        10: CHANGE HOST            {1814}\n            Change Host        : 2:idefix\n        11: XY STATS               {2250}\n        12: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 1600\n            Sensitivity (DPI)        : 1600\n        13: SMART SHIFT            {2110}\n            Scroll Wheel Rachet (saved): 32\n            Scroll Wheel Rachet        : 32\n        14: HIRES WHEEL            {2121}\n            Multiplier: 15\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            High resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): True\n            Scroll Wheel Resolution        : True\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        15: THUMB WHEEL            {2150}\n            Thumb Wheel Direction (saved): False\n            Thumb Wheel Direction        : False\n            Thumb Wheel Diversion (saved): False\n            Thumb Wheel Diversion        : False\n        16: WHEEL STATS            {2251}\n        17: DFUCONTROL SIGNED      {00C2}\n        18: DEVICE RESET           {1802}   internal, hidden\n        19: unknown:1803           {1803}   internal, hidden\n        20: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        21: unknown:1813           {1813}   internal, hidden\n        22: OOBSTATE               {1805}   internal, hidden\n        23: unknown:1830           {1830}   internal, hidden\n        24: unknown:18A1           {18A1}   internal, hidden\n        25: unknown:1E00           {1E00}   hidden\n        26: unknown:1EB0           {1EB0}   internal, hidden\n        27: unknown:1861           {1861}   internal, hidden\n        28: unknown:9300           {9300}   internal, hidden\n        29: unknown:9001           {9001}   internal, hidden\n     Has 8 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Mouse Gesture Button      , default: Gesture Button Navigation   => Gesture Button Navigation\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         6: Smart Shift               , default: Smart Shift                 => Smart Shift\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         7: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty\n             reporting: default\n     Battery: 100%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/MX Master 3 for Business B028.text",
    "content": "solaar version 1.1.8\n\n  1: MX Master 3 for Business\n     Device path  : None\n     WPID         : B028\n     Codename     : MX Master 3 B\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number: 18F3413B\n     Model ID:      B02800000000\n     Unit ID:       18F3413B\n        Bootloader: BL1 41.00.B0009\n          Firmware: RBM 14.00.B0009\n             Other:\n     The power switch is located on the (unknown).\n     Supports 35 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BL1 41.00.B0009 B0281D13EFC0\n            Firmware: Firmware RBM 14.00.B0009 B0281D13EFC0\n            Firmware: Other\n            Unit ID: 18F3413B  Model ID: B02800000000  Transport IDs: {'btleid': 'B028'}\n         3: DEVICE NAME            {0005} V0\n            Name: MX Master 3 for Business\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n         6: CRYPTO ID              {0021} V1\n         7: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: MX Master 3 B\n         8: UNIFIED BATTERY        {1004} V2\n            Battery: 95%, discharging.\n         9: REPROG CONTROLS V4     {1B04} V5\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular}\n        10: CHANGE HOST            {1814} V1\n            Change Host        : 1:bork\n        11: XY STATS               {2250} V1\n        12: ADJUSTABLE DPI         {2201} V2\n            Sensitivity (DPI) (saved): 1000\n            Sensitivity (DPI)        : 1000\n        13: SMART SHIFT            {2110} V0\n            Scroll Wheel Ratcheted (saved): Freespinning\n            Scroll Wheel Ratcheted        : Freespinning\n            Scroll Wheel Ratchet Speed (saved): 1\n            Scroll Wheel Ratchet Speed        : 1\n        14: HIRES WHEEL            {2121} V1\n            Multiplier: 15\n            Has invert: Normal wheel motion\n            Has ratchet switch: Free wheel mode\n            Low resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): False\n            Scroll Wheel Resolution        : False\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        15: THUMB WHEEL            {2150} V0\n            Thumb Wheel Direction (saved): False\n            Thumb Wheel Direction        : False\n            Thumb Wheel Diversion (saved): False\n            Thumb Wheel Diversion        : False\n        16: WHEEL STATS            {2251} V0\n        17: DFUCONTROL             {00C3} V0\n        18: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010\n        19: unknown:1803           {1803} V0    internal, hidden, unknown:000010\n        20: CONFIG DEVICE PROPS    {1806} V8    internal, hidden, unknown:000010\n        21: unknown:1816           {1816} V0    internal, hidden, unknown:000010\n        22: OOBSTATE               {1805} V0    internal, hidden\n        23: unknown:1830           {1830} V0    internal, hidden, unknown:000010\n        24: unknown:1891           {1891} V6    internal, hidden, unknown:000008\n        25: unknown:18A1           {18A1} V0    internal, hidden, unknown:000010\n        26: unknown:1E00           {1E00} V0    hidden\n        27: unknown:1E02           {1E02} V0    internal, hidden\n        28: unknown:1602           {1602} V0\n        29: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010\n        30: unknown:1861           {1861} V0    internal, hidden, unknown:000010\n        31: unknown:9300           {9300} V0    internal, hidden, unknown:000010\n        32: unknown:9001           {9001} V0    internal, hidden, unknown:000010\n        33: unknown:1E22           {1E22} V0    internal, hidden, unknown:000010\n        34: unknown:9205           {9205} V0    internal, hidden, unknown:000010\n     Has 8 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Mouse Gesture Button      , default: Gesture Button Navigation   => Gesture Button Navigation\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         6: Smart Shift               , default: Smart Shift                 => Smart Shift\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         7: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Battery: 95%, discharging.\n"
  },
  {
    "path": "docs/devices/MX Master 3S B034.txt",
    "content": "Solaar version 1.1.7\n\n  2: MX Master 3S\n     Device path  : None\n     WPID         : B034\n     Codename     : MX Master 3S\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number: CD2A6BB7\n     Model ID:      B03400000000\n     Unit ID:       CD2A6BB7\n        Bootloader: BL1 69.00.B0003\n          Firmware: RBM 22.00.B0003\n             Other:\n     The power switch is located on the (unknown).\n     Supports 36 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BL1 69.00.B0003 B03438FCA4E6\n            Firmware: Firmware RBM 22.00.B0003 B03438FCA4E6\n            Firmware: Other\n            Unit ID: CD2A6BB7  Model ID: B03400000000  Transport IDs: {'btleid': 'B034'}\n         3: DEVICE NAME            {0005} V0\n            Name: MX Master 3S\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: RESET                  {0020} V0\n         6: CRYPTO ID              {0021} V1\n         7: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: MX Master 3S\n         8: UNIFIED BATTERY        {1004} V3\n            Battery: 25%, discharging.\n         9: REPROG CONTROLS V4     {1B04} V5\n            Acciones de Tecla/Botón (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            Acciones de Tecla/Botón        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            Desvio de Tecla/Botón (saved): {Middle Button:Normal, Back Button:Normal, Forward Button:Normal, Mouse Gesture Button:Normal, Smart Shift:Normal}\n            Desvio de Tecla/Botón        : {Middle Button:Normal, Back Button:Normal, Forward Button:Normal, Mouse Gesture Button:Normal, Smart Shift:Normal}\n        10: CHANGE HOST            {1814} V1\n            Cambiar Host        : 1:romanescu\n        11: HOSTS INFO             {1815} V2\n            Host 0 (paired): romanescu\n            Host 1 (unpaired):\n            Host 2 (unpaired):\n        12: XY STATS               {2250} V1\n        13: ADJUSTABLE DPI         {2201} V2\n            Sensibilidad (PPP) (saved): 1000\n            Sensibilidad (PPP)        : 1000\n        14: SMART SHIFT            {2110} V0\n            Scroll Wheel Ratcheted (saved): Freespinning\n            Scroll Wheel Ratcheted        : Freespinning\n            Scroll Wheel Ratchet Speed (saved): 0\n            Scroll Wheel Ratchet Speed        : 1\n        15: HIRES WHEEL            {2121} V1\n            Multiplier: 15\n            Has invert: Normal wheel motion\n            Has ratchet switch: Free wheel mode\n            Low resolution mode\n            HID notification\n            Dirección Rueda Desplazamiento (saved): False\n            Dirección Rueda Desplazamiento        : False\n            Resolución Rueda Desplazamiento (saved): False\n            Resolución Rueda Desplazamiento        : False\n            Desvio Rueda Desplazamiento (saved): False\n            Desvio Rueda Desplazamiento        : False\n        16: THUMB WHEEL            {2150} V0\n            Dirección de la Rueda del Pulgar (saved): False\n            Dirección de la Rueda del Pulgar        : False\n            Desvío de la Rueda del Pulgar (saved): False\n            Desvío de la Rueda del Pulgar        : False\n        17: WHEEL STATS            {2251} V0\n        18: DFUCONTROL             {00C3} V0\n        19: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010\n        20: unknown:1803           {1803} V0    internal, hidden, unknown:000010\n        21: CONFIG DEVICE PROPS    {1806} V8    internal, hidden, unknown:000010\n        22: unknown:1816           {1816} V0    internal, hidden, unknown:000010\n        23: OOBSTATE               {1805} V0    internal, hidden\n        24: unknown:1830           {1830} V0    internal, hidden, unknown:000010\n        25: unknown:1891           {1891} V7    internal, hidden, unknown:000008\n        26: unknown:18A1           {18A1} V0    internal, hidden, unknown:000010\n        27: unknown:1E00           {1E00} V0    hidden\n        28: unknown:1E02           {1E02} V0    internal, hidden\n        29: unknown:1602           {1602} V0\n        30: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010\n        31: unknown:1861           {1861} V1    internal, hidden, unknown:000010\n        32: unknown:9300           {9300} V0    internal, hidden, unknown:000010\n        33: unknown:9001           {9001} V0    internal, hidden, unknown:000010\n        34: unknown:1E22           {1E22} V0    internal, hidden, unknown:000010\n        35: unknown:9205           {9205} V0    internal, hidden, unknown:000010\n     Has 8 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Mouse Gesture Button      , default: Gesture Button Navigation   => Gesture Button Navigation\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         6: Smart Shift               , default: Smart Shift                 => Smart Shift\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         7: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Battery: 25%, discharging.\n"
  },
  {
    "path": "docs/devices/MX Mechanical B366.txt",
    "content": "Solaar version 1.1.7\n\n  1: MX Mechanical\n     Device path  : None\n     WPID         : B366\n     Codename     : MX MCHNCL\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Serial number: 2DF63C09\n     Model ID:      B36600000000\n     Unit ID:       2DF63C09\n        Bootloader: BL1 45.00.B0016\n          Firmware: RBK 71.00.B0016\n             Other:\n     The power switch is located on the (unknown).\n     Supports 33 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BL1 45.00.B0016 B3662CB9B8E2\n            Firmware: Firmware RBK 71.00.B0016 B3662CB9B8E2\n            Firmware: Other\n            Unit ID: 2DF63C09  Model ID: B36600000000  Transport IDs: {'btleid': 'B366'}\n         3: DEVICE NAME            {0005} V0\n            Name: MX Mechanical\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: RESET                  {0020} V0\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: MX MCHNCL\n         7: UNIFIED BATTERY        {1004} V3\n            Battery: 50%, discharging.\n         8: REPROG CONTROLS V4     {1B04} V5\n            Desvio de Tecla/Botón (saved): {Calculator:Normal, Show Desktop:Normal, Lock PC:Normal, Brightness Down:Normal, Brightness Up:Normal, MultiPlatform Search:Normal, Backlight Down:Normal, Backlight Up:Normal, Previous Fn:Normal, Play/Pause Fn:Normal, Next Fn:Normal, Mute Fn:Normal, Volume Down Fn:Normal, Volume Up Fn:Normal, Voice Dictation:Normal, Open Emoji Panel:Normal, Snipping Tool:Normal, Grave Accent:Normal, Tab Key:Normal, Caps Lock:Normal, Left Shift:Normal, Left Control:Normal, Left Option/Start:Normal, Left Command/Alt:Normal, Right Command/Alt:Normal, Right Option/Start:Normal, Right Control:Normal, Right Shift:Normal, Insert:Normal, Delete:Normal, Home:Normal, End:Normal, Page Up:Normal, Page Down:Normal, Mute Microphone:Normal, Backslash:Normal}\n            Desvio de Tecla/Botón        : {Calculator:Normal, Show Desktop:Normal, Lock PC:Normal, Brightness Down:Normal, Brightness Up:Normal, MultiPlatform Search:Normal, Backlight Down:Normal, Backlight Up:Normal, Previous Fn:Normal, Play/Pause Fn:Normal, Next Fn:Normal, Mute Fn:Normal, Volume Down Fn:Normal, Volume Up Fn:Normal, Voice Dictation:Normal, Open Emoji Panel:Normal, Snipping Tool:Normal, Grave Accent:Normal, Tab Key:Normal, Caps Lock:Normal, Left Shift:Normal, Left Control:Normal, Left Option/Start:Normal, Left Command/Alt:Normal, Right Command/Alt:Normal, Right Option/Start:Normal, Right Control:Normal, Right Shift:Normal, Insert:Normal, Delete:Normal, Home:Normal, End:Normal, Page Up:Normal, Page Down:Normal, Mute Microphone:Normal, Backslash:Normal}\n         9: CHANGE HOST            {1814} V1\n            Cambiar Host        : 1:romanescu\n        10: HOSTS INFO             {1815} V2\n            Host 0 (paired): romanescu\n            Host 1 (unpaired):\n            Host 2 (unpaired):\n        11: BACKLIGHT2             {1982} V2\n            Retroiluminación (saved): True\n            Retroiluminación        : True\n        12: K375S FN INVERSION     {40A3} V0\n            Intercambiar función Fx (saved): True\n            Intercambiar función Fx        : True\n        13: LOCK KEY STATE         {4220} V0\n        14: KEYBOARD DISABLE KEYS  {4521} V0\n            Desactivar teclas (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Desactivar teclas        : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        15: MULTIPLATFORM          {4531} V1\n            Especificar SO (saved): Windows\n            Especificar SO        : Windows\n        16: KEYBOARD LAYOUT 2      {4540} V0\n        17: DFUCONTROL             {00C3} V0\n        18: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010\n        19: unknown:1803           {1803} V0    internal, hidden, unknown:000010\n        20: CONFIG DEVICE PROPS    {1806} V8    internal, hidden, unknown:000010\n        21: unknown:1816           {1816} V0    internal, hidden, unknown:000010\n        22: OOBSTATE               {1805} V0    internal, hidden\n        23: unknown:1830           {1830} V0    internal, hidden, unknown:000010\n        24: unknown:1891           {1891} V7    internal, hidden, unknown:000008\n        25: unknown:18A1           {18A1} V0    internal, hidden, unknown:000010\n        26: unknown:1E00           {1E00} V0    hidden\n        27: unknown:1E02           {1E02} V0    internal, hidden\n        28: unknown:1602           {1602} V0\n        29: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010\n        30: unknown:1861           {1861} V1    internal, hidden, unknown:000010\n        31: unknown:1A20           {1A20} V0    internal, hidden, unknown:000010\n        32: unknown:18B0           {18B0} V0    internal, hidden, unknown:000010\n     Has 41 reprogrammable keys:\n         0: Brightness Down           , default: Brightness Down             => Brightness Down\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Brightness Up             , default: Brightness Up               => Brightness Up\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:2, group:0, group mask:empty\n             reporting: default\n         2: Backlight Down            , default: Backlight Down              => Backlight Down\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:3, group:0, group mask:empty\n             reporting: default\n         3: Backlight Up              , default: Backlight Up                => Backlight Up\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:4, group:0, group mask:empty\n             reporting: default\n         4: Voice Dictation           , default: Voice Dictation             => Voice Dictation\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:5, group:0, group mask:empty\n             reporting: default\n         5: Open Emoji Panel          , default: Open Emoji Panel            => Open Emoji Panel\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:6, group:0, group mask:empty\n             reporting: default\n         6: Snipping Tool             , default: Snipping Tool               => Snipping Tool\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:7, group:0, group mask:empty\n             reporting: default\n         7: Mute Microphone           , default: Mute Microphone             => Mute Microphone\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:8, group:0, group mask:empty\n             reporting: default\n         8: Previous Fn               , default: Previous                    => Previous\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:9, group:0, group mask:empty\n             reporting: default\n         9: Play/Pause Fn             , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:10, group:0, group mask:empty\n             reporting: default\n        10: Next Fn                   , default: Next                        => Next\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:11, group:0, group mask:empty\n             reporting: default\n        11: Mute Fn                   , default: Mute                        => Mute\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:12, group:0, group mask:empty\n             reporting: default\n        12: Volume Down Fn            , default: Volume Down                 => Volume Down\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        13: Volume Up Fn              , default: Volume Up                   => Volume Up\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        14: Grave Accent              , default: Grave Accent                => Grave Accent\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        15: Tab Key                   , default: Standard Tab Key            => Standard Tab Key\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Caps Lock                 , default: Caps Lock                   => Caps Lock\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Left Shift                , default: Left Shift                  => Left Shift\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        18: Left Control              , default: Left Control                => Left Control\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        19: Left Option/Start         , default: Left Option/Start           => Left Option/Start\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        20: Left Command/Alt          , default: Left Command/Alt            => Left Command/Alt\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        21: Right Command/Alt         , default: Right Command/Alt           => Right Command/Alt\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        22: Right Option/Start        , default: Right Option/Start          => Right Option/Start\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        23: Right Control             , default: Right Control               => Right Control\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        24: Right Shift               , default: Right Shift                 => Right Shift\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        25: Backslash                 , default: Backslash                   => Backslash\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        26: Insert                    , default: Insert                      => Insert\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        27: Delete                    , default: Delete                      => Delete\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        28: Home                      , default: Home                        => Home\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        29: End                       , default: End                         => End\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        30: Page Up                   , default: Page Up                     => Page Up\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        31: Page Down                 , default: Page Down                   => Page Down\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        32: Calculator                , default: Calculator                  => Calculator\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        33: Show Desktop              , default: Show Desktop                => Show Desktop\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        34: MultiPlatform Search      , default: Multiplatform Search        => Multiplatform Search\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        35: Lock PC                   , default: WindowsLock                 => WindowsLock\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        36: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        37: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        38: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        39: F Lock                    , default: Do Nothing One              => Do Nothing One\n             is FN, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        40: FN Key                    , default: Do Nothing One              => Do Nothing One\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n     Battery: 50%, discharging.\n"
  },
  {
    "path": "docs/devices/MX Mechanical Mini B367.txt",
    "content": "Solaar version 1.1.4\n\n  1: MX Mechanical Mini\n     Device path  : None\n     WPID         : B367\n     Codename     : MX MCHNCL M\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Serial number: D4E94F5C\n     Model ID:      B36700000000\n     Unit ID:       D4E94F5C\n        Bootloader: BL1 50.00.B0010\n          Firmware: RBK 72.00.B0010\n             Other:\n     The power switch is located on the (unknown).\n     Supports 32 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BL1 50.00.B0010 B367A91B7FC8\n            Firmware: Firmware RBK 72.00.B0010 B367A91B7FC8\n            Firmware: Other\n            Unit ID: D4E94F5C  Model ID: B36700000000  Transport IDs: {'btleid': 'B367'}\n         3: DEVICE NAME            {0005} V0\n            Name: MX Mechanical Mini\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: RESET                  {0020} V0\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: MX MCHNCL M\n         7: UNIFIED BATTERY        {1004} V3\n            Battery: 90%, discharging.\n         8: REPROG CONTROLS V4     {1B04} V5\n            Key/Button Diversion (saved): {MultiPlatform Search:Regular, Backlight Down:Regular, Backlight Up:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Grave Accent:Regular, Tab Key:Regular, Caps Lock:Regular, Left Shift:Regular, Left Control:Regular, Left Option/Start:Regular, Left Command/Alt:Regular, Right Command/Alt:Regular, Right Shift:Regular, Delete:Regular, Home:Regular, End:Regular, Page Up:Regular, Page Down:Regular, Mute Microphone:Regular, Backslash:Regular, unknown:013C:Regular, unknown:0141:Regular}\n            Key/Button Diversion        : {MultiPlatform Search:Regular, Backlight Down:Regular, Backlight Up:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Grave Accent:Regular, Tab Key:Regular, Caps Lock:Regular, Left Shift:Regular, Left Control:Regular, Left Option/Start:Regular, Left Command/Alt:Regular, Right Command/Alt:Regular, Right Shift:Regular, Delete:Regular, Home:Regular, End:Regular, Page Up:Regular, Page Down:Regular, Mute Microphone:Regular, Backslash:Regular, unknown:013C:Regular, unknown:0141:Regular}\n         9: CHANGE HOST            {1814} V1\n            Change Host        : 1:chimera\n        10: HOSTS INFO             {1815} V2\n            Host 0 (paired): chimera\n            Host 1 (paired): Logitech Bolt receiver\n            Host 2 (unpaired):\n        11: BACKLIGHT2             {1982} V2\n            Backlight (saved): True\n            Backlight        : True\n        12: K375S FN INVERSION     {40A3} V0\n            Swap Fx function (saved): True\n            Swap Fx function        : True\n        13: LOCK KEY STATE         {4220} V0\n        14: KEYBOARD DISABLE KEYS  {4521} V0\n            Disable keys (saved): {Caps Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        15: MULTIPLATFORM          {4531} V1\n            Set OS (saved): Windows\n            Set OS        : Windows\n        16: KEYBOARD LAYOUT 2      {4540} V0\n        17: DFUCONTROL             {00C3} V0\n        18: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010\n        19: unknown:1803           {1803} V0    internal, hidden, unknown:000010\n        20: CONFIG DEVICE PROPS    {1806} V8    internal, hidden, unknown:000010\n        21: unknown:1816           {1816} V0    internal, hidden, unknown:000010\n        22: OOBSTATE               {1805} V0    internal, hidden\n        23: unknown:1830           {1830} V0    internal, hidden, unknown:000010\n        24: unknown:1891           {1891} V7    internal, hidden, unknown:000008\n        25: unknown:18A1           {18A1} V0    internal, hidden, unknown:000010\n        26: unknown:1E00           {1E00} V0    hidden\n        27: unknown:1E02           {1E02} V0    internal, hidden\n        28: unknown:1602           {1602} V0\n        29: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010\n        30: unknown:1861           {1861} V1    internal, hidden, unknown:000010\n        31: unknown:1A20           {1A20} V0    internal, hidden, unknown:000010\n     Has 32 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             is FN, FN sensitive, analytics key events, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             is FN, FN sensitive, analytics key events, pos:2, group:0, group mask:empty\n             reporting: default\n         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             is FN, FN sensitive, analytics key events, pos:3, group:0, group mask:empty\n             reporting: default\n         3: Backlight Down            , default: Backlight Down              => Backlight Down\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:4, group:0, group mask:empty\n             reporting: default\n         4: Backlight Up              , default: Backlight Up                => Backlight Up\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:5, group:0, group mask:empty\n             reporting: default\n         5: Voice Dictation           , default: Voice Dictation             => Voice Dictation\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:6, group:0, group mask:empty\n             reporting: default\n         6: Open Emoji Panel          , default: Open Emoji Panel            => Open Emoji Panel\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:7, group:0, group mask:empty\n             reporting: default\n         7: Snipping Tool             , default: Snipping Tool               => Snipping Tool\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:8, group:0, group mask:empty\n             reporting: default\n         8: Mute Microphone           , default: Mute Microphone             => Mute Microphone\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:9, group:0, group mask:empty\n             reporting: default\n         9: MultiPlatform Search      , default: Multiplatform Search        => Multiplatform Search\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:10, group:0, group mask:empty\n             reporting: default\n        10: unknown:0141              , default: unknown:00FD                => unknown:00FD\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:11, group:0, group mask:empty\n             reporting: default\n        11: Mute Fn                   , default: Mute                        => Mute\n             is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:12, group:0, group mask:empty\n             reporting: default\n        12: Volume Down Fn            , default: Volume Down                 => Volume Down\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        13: Volume Up Fn              , default: Volume Up                   => Volume Up\n             nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        14: Grave Accent              , default: Grave Accent                => Grave Accent\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        15: Tab Key                   , default: Standard Tab Key            => Standard Tab Key\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Caps Lock                 , default: Caps Lock                   => Caps Lock\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Left Shift                , default: Left Shift                  => Left Shift\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        18: Left Control              , default: Left Control                => Left Control\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        19: Left Option/Start         , default: Left Option/Start           => Left Option/Start\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        20: Left Command/Alt          , default: Left Command/Alt            => Left Command/Alt\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        21: Right Command/Alt         , default: Right Command/Alt           => Right Command/Alt\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        22: unknown:013C              , default: Right Option/Start/2        => Right Option/Start/2\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        23: Right Shift               , default: Right Shift                 => Right Shift\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        24: Backslash                 , default: Backslash                   => Backslash\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        25: Delete                    , default: Delete                      => Delete\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        26: Home                      , default: Home                        => Home\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        27: End                       , default: End                         => End\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        28: Page Up                   , default: Page Up                     => Page Up\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        29: Page Down                 , default: Page Down                   => Page Down\n             reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        30: F Lock                    , default: Do Nothing One              => Do Nothing One\n             is FN, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n        31: FN Key                    , default: Do Nothing One              => Do Nothing One\n             nonstandard, analytics key events, pos:0, group:0, group mask:empty\n             reporting: default\n     Battery: 90%, discharging.\n"
  },
  {
    "path": "docs/devices/MX Vertical Wireless Mouse 407B.txt",
    "content": "Solaar version 1.1.3\n\n  2: MX Vertical Wireless Mouse\n     Device path  : /dev/hidraw5\n     WPID         : 407B\n     Codename     : MX Vertical\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 87A544C3\n     Model ID:      B020407BC08A\n     Unit ID:       7818C6EE\n        Bootloader: BOT 78.00.B0009\n          Firmware: MPM 16.00.B0009\n             Other:\n     Supports 34 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 78.00.B0009 AAE28E5B17FF\n            Firmware: Firmware MPM 16.00.B0009 407B8E5B17FF\n            Firmware: Other\n            Unit ID: 7818C6EE  Model ID: B020407BC08A  Transport IDs: {'btleid': 'B020', 'wpid': '407B', 'usbid': 'C08A'}\n         3: DEVICE NAME            {0005}\n            Name: MX Vertical Advanced Ergonomic Mouse\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: CRYPTO ID              {0021}\n         7: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: MX Vertical\n         8: BATTERY STATUS         {1000}\n            Battery: 50%, discharging, next level 20%.\n         9: unknown:1002           {1002}\n        10: REPROG CONTROLS V4     {1B04}\n            DPI Sliding Adjustment (saved): Off\n            DPI Sliding Adjustment        : Off\n            Mouse Gestures (saved): Off\n            Mouse Gestures        : Off\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, DPI Switch:DPI Switch}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, DPI Switch:DPI Switch}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Diverted, Forward Button:Diverted, ?, DPI Switch:Diverted}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Diverted, Forward Button:Diverted, DPI Switch:Diverted}\n        11: PERSISTENT REMAPPABLE ACTION {1C00}\n        12: CHANGE HOST            {1814}\n            Change Host        : 1:pudim\n        13: HOSTS INFO             {1815}\n            Host 0 (unpaired): pudim\n            Host 1 (unpaired):\n            Host 2 (unpaired):\n        14: XY STATS               {2250}\n        15: unknown:18B1           {18B1}   internal, hidden\n        16: VERTICAL SCROLLING     {2100}\n            Roller type: standard\n            Ratchet per turn: 24\n            Scroll lines: 0\n        17: LOWRES WHEEL           {2130}\n            Wheel Reports: HID\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        18: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 2800\n            Sensitivity (DPI)        : 2800\n        19: DEVICE RESET           {1802}   internal, hidden\n        20: unknown:1803           {1803}   internal, hidden\n        21: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        22: unknown:1813           {1813}   internal, hidden\n        23: OOBSTATE               {1805}   internal, hidden\n        24: unknown:1830           {1830}   internal, hidden\n        25: unknown:1890           {1890}   internal, hidden\n        26: unknown:1891           {1891}   internal, hidden\n        27: unknown:18A1           {18A1}   internal, hidden\n        28: unknown:1DF3           {1DF3}   internal, hidden\n        29: unknown:1E00           {1E00}   hidden\n        30: unknown:1EB0           {1EB0}   internal, hidden\n        31: unknown:1E22           {1E22}   internal, hidden\n        32: unknown:1861           {1861}   internal, hidden\n        33: unknown:18C0           {18C0}   internal, hidden\n     Has 7 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: diverted\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: diverted\n         5: DPI Switch                , default: DPI Switch                  => DPI Switch\n             mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: diverted\n         6: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Has 6 persistent remappable keys:\n         0: Left Button                => Mouse Button: Mouse Button Left\n         1: Right Button               => Mouse Button: Mouse Button Right\n         2: Middle Button              => Mouse Button: Mouse Button Middle\n         3: Back Button                => Mouse Button: Mouse Button Back\n         4: Forward Button             => Mouse Button: Mouse Button Forward\n         5: unknown:0000               => None\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/MX Vertical Wireless Mouse B020.txt",
    "content": "Solaar version 1.1.3\n\n  1: MX Vertical Wireless Mouse\n     Device path  : /dev/hidraw0\n     USB id       : 046d:B020\n     Codename     : MX Vertical\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number:\n     Model ID:      B020407BC08A\n     Unit ID:       70926049\n        Bootloader: BOT 78.00.B0009\n          Firmware: MPM 16.00.B0009\n             Other:\n     Supports 30 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 78.00.B0009 AAE28E5B17FF\n            Firmware: Firmware MPM 16.00.B0009 B0208E5B17FF\n            Firmware: Other\n            Unit ID: 70926049  Model ID: B020407BC08A  Transport IDs: {'btleid': 'B020', 'wpid': '407B', 'usbid': 'C08A'}\n         3: DEVICE NAME            {0005}\n            Name: MX Vertical Advanced Ergonomic Mouse\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: CRYPTO ID              {0021}\n         7: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: MX Vertical\n         8: BATTERY STATUS         {1000}\n            Battery: 90%, discharging, next level 50%.\n         9: unknown:1002           {1002}\n        10: REPROG CONTROLS V4     {1B04}\n        11: PERSISTENT REMAPPABLE ACTION {1C00}\n        12: CHANGE HOST            {1814}\n        13: HOSTS INFO             {1815}\n            Host 0 (unpaired): minerva\n            Host 1 (unpaired): theseus\n            Host 2 (unpaired): athena\n        14: XY STATS               {2250}\n        15: unknown:18B1           {18B1}   internal, hidden\n        16: VERTICAL SCROLLING     {2100}\n            Roller type: standard\n            Ratchet per turn: 24\n            Scroll lines: 0\n        17: LOWRES WHEEL           {2130}\n            Wheel Reports: HID\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        18: ADJUSTABLE DPI         {2201}\n        19: unknown:1803           {1803}   internal, hidden\n        20: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        21: unknown:1813           {1813}   internal, hidden\n        22: OOBSTATE               {1805}   internal, hidden\n        23: unknown:1830           {1830}   internal, hidden\n        24: unknown:18A1           {18A1}   internal, hidden\n        25: unknown:1E00           {1E00}   hidden\n        26: unknown:1EB0           {1EB0}   internal, hidden\n        27: unknown:1E22           {1E22}   internal, hidden\n        28: unknown:1861           {1861}   internal, hidden\n        29: unknown:18C0           {18C0}   internal, hidden\n     Has 7 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: DPI Switch                , default: DPI Switch                  => DPI Switch\n             mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         6: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Has 6 persistent remappable keys:\n         0: Left Button                => Mouse Button: Mouse Button Left\n         1: Right Button               => Mouse Button: Mouse Button Right\n         2: Middle Button              => Mouse Button: Mouse Button Middle\n         3: Back Button                => Mouse Button: Mouse Button Back\n         4: Forward Button             => Mouse Button: Mouse Button Forward\n         5: unknown:0000               => None\n     Battery: 90%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/Marathon Mouse M705 101B.txt",
    "content": "Solaar version 1.1.5\n\n  1: Marathon Mouse M705 (M-R0009)\n     Device path  : /dev/hidraw1\n     WPID         : 101B\n     Codename     : M705 (M-R0009)\n     Kind         : mouse\n     Protocol     : HID++ 1.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: 23691D3D\n          Firmware: 17.01.B0017\n        Bootloader: 02.06\n             Other: 00.04\n     The power switch is located on the base.\n     Notifications: battery status (0x100000).\n     Features: special buttons, scroll accel (0x420000)\n     Battery: 65%, discharging.\n\nregisters:\n\n# writing 0x10 in this register will generate an event\n#   10 02 0Dxx yyzz00\n# where 0D happens to be the battery register number\n#       xx is the battery charge\n#       yy, zz ?\n<< (   0.001) [10 02 8100 000000] '\\x10\\x02\\x81\\x00\\x00\\x00\\x00'\n>> (   1.132) [10 02 8100 100000] '\\x10\\x02\\x81\\x00\\x10\\x00\\x00'\n\n# smooth scroll - possible values\n#    - 00 (off)\n#    - 02 ?, apparently off as well, default value at power-on\n#    - 0x40 (on)\n<< (   2.005) [10 02 8101 000000] '\\x10\\x02\\x81\\x01\\x00\\x00\\x00'\n>> (   2.052) [10 02 8101 020000] '\\x10\\x02\\x81\\x01\\x02\\x00\\x00'\n\n# battery status:  percentage full, ?, ?\n<< (  14.835) [10 02 810D 000000] '\\x10\\x02\\x81\\r\\x00\\x00\\x00'\n>> (  14.847) [10 02 810D 644734] '\\x10\\x02\\x81\\rdG4'\n\n# accepts mask 0xF1\n# setting 0x10 turns off the movement events (but buttons still work)\n<< ( 221.495) [10 02 81D0 000000] '\\x10\\x02\\x81\\xd0\\x00\\x00\\x00'\n>> ( 221.509) [10 02 81D0 000000] '\\x10\\x02\\x81\\xd0\\x00\\x00\\x00'\n\n# appears to be read-only?\n<< ( 223.527) [10 02 81D2 000000] '\\x10\\x02\\x81\\xd2\\x00\\x00\\x00'\n>> ( 223.540) [10 02 81D2 000003] '\\x10\\x02\\x81\\xd2\\x00\\x00\\x03'\n\n# appears to be read-only?\n<< ( 225.557) [10 02 81D4 000000] '\\x10\\x02\\x81\\xd4\\x00\\x00\\x00'\n>> ( 225.571) [10 02 81D4 000004] '\\x10\\x02\\x81\\xd4\\x00\\x00\\x04'\n\n# read-only, 01-04 firmware info\n<< ( 259.270) [10 02 81F1 000000] '\\x10\\x02\\x81\\xf1\\x00\\x00\\x00'\n>> ( 259.283) [10 02 8F81 F10300] '\\x10\\x02\\x8f\\x81\\xf1\\x03\\x00'\n\n# writing 01 here will trigger an avalanche of events, most likely\n# raw input from the mouse; disable by writing 00\n<< ( 261.300) [10 02 81F3 000000] '\\x10\\x02\\x81\\xf3\\x00\\x00\\x00'\n>> ( 261.315) [10 02 81F3 000000] '\\x10\\x02\\x81\\xf3\\x00\\x00\\x00'\n"
  },
  {
    "path": "docs/devices/Marathon Mouse M705 406D.txt",
    "content": "  3: Marathon Mouse M705 (M-R0073)\n     Device path  : /dev/hidraw3\n     WPID         : 406D\n     Codename     : M705 (M-R0073)\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: B14D65DA\n     Model ID:      406D00000000\n     Unit ID:       5E1A15B8\n        Bootloader: BOT 59.00.B0002\n          Firmware: RQM 67.01.B0005\n     The power switch is located on the base.\n     Supports 26 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 59.00.B0002 406D5F5048B901\n            Firmware: Firmware RQM 67.01.B0005 406D5F5048B901\n            Unit ID: 5E1A15B8  Model ID: 406D00000000  Transport IDs: {'wpid': '406D'}\n         3: DEVICE NAME            {0005}\n            Name: Marathon Mouse/Performance Plus M705\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: BATTERY STATUS         {1000}\n            Battery: 50%, discharging, next level 20%.\n         7: REPROG CONTROLS V4     {1B04}\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular}\n         8: POINTER SPEED          {2205}\n            Pointer Speed: 1.0\n            Sensitivity (Pointer Speed) (saved): 256\n            Sensitivity (Pointer Speed)        : 256\n         9: VERTICAL SCROLLING     {2100}\n            Roller type: 3G\n            Ratchet per turn: 24\n            Scroll lines: 0\n        10: DFUCONTROL SIGNED      {00C2}\n        11: DEVICE RESET           {1802}   internal, hidden\n        12: unknown:1803           {1803}   internal, hidden\n        13: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        14: unknown:1810           {1810}   internal, hidden\n        15: unknown:1830           {1830}   internal, hidden\n        16: unknown:1890           {1890}   internal, hidden\n        17: unknown:18A1           {18A1}   internal, hidden\n        18: unknown:1DF3           {1DF3}   internal, hidden\n        19: unknown:1E00           {1E00}   hidden\n        20: unknown:1EB0           {1EB0}   internal, hidden\n        21: unknown:1861           {1861}   internal, hidden\n        22: unknown:18B1           {18B1}   internal, hidden\n        23: unknown:1850           {1850}   internal, hidden\n        24: unknown:1F03           {1F03}   internal, hidden\n        25: unknown:18C0           {18C0}   internal, hidden\n     Has 7 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Left Tilt                 , default: Mouse Scroll Left Button    => Mouse Scroll Left Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         6: Right Tilt                , default: Mouse Scroll Right Button   => Mouse Scroll Right Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n     Battery: 50%, discharging, next level 20%.\n\n\n  3: Marathon Mouse M705 (M-R0073)\n     Device path  : /dev/hidraw3\n     WPID         : 406D\n     Codename     : M705 (M-R0073)\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: B14D65DA\n     Model ID:      406D00000000\n     Unit ID:       5E1A15B8\n        Bootloader: BOT 59.00.B0002\n          Firmware: RQM 67.01.B0005\n     The power switch is located on the base.\n     Supports 27 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 59.00.B0002 406D5F5048B901\n            Firmware: Firmware RQM 67.01.B0005 406D5F5048B901\n            Unit ID: 5E1A15B8  Model ID: 406D00000000  Transport IDs: {'wpid': '406D'}\n         3: DEVICE NAME            {0005}\n            Name: Marathon Mouse/Performance Plus M705\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: BATTERY STATUS         {1000}\n            Battery: 50%, discharging, next level 20%.\n         7: REPROG CONTROLS V4     {1B04}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular}\n         8: POINTER SPEED          {2205}\n            Pointer Speed: 1.0\n            Sensitivity (Pointer Speed)        : 256\n         9: VERTICAL SCROLLING     {2100}\n            Roller type: 3G\n            Ratchet per turn: 24\n            Scroll lines: 0\n        10: DFUCONTROL SIGNED      {00C2}\n        11: DEVICE RESET           {1802}   internal, hidden\n        12: unknown:1803           {1803}   internal, hidden\n        13: CONFIG DEVICE PROPS    {1806}   internal, hidden\n        14: unknown:1810           {1810}   internal, hidden\n        15: unknown:1830           {1830}   internal, hidden\n        16: unknown:1890           {1890}   internal, hidden\n        17: unknown:18A1           {18A1}   internal, hidden\n        18: unknown:1DF3           {1DF3}   internal, hidden\n        19: unknown:1E00           {1E00}   hidden\n        20: unknown:1EB0           {1EB0}   internal, hidden\n        21: unknown:1861           {1861}   internal, hidden\n        22: unknown:18B1           {18B1}   internal, hidden\n        23: unknown:1850           {1850}   internal, hidden\n        24: unknown:1F03           {1F03}   internal, hidden\n        25: unknown:18C0           {18C0}   internal, hidden\n        26: HIRES WHEEL            {2121}\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            Low resolution mode\n            HID notification\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution        : False\n     Has 7 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Left Tilt                 , default: Mouse Scroll Left Button    => Mouse Scroll Left Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         6: Right Tilt                , default: Mouse Scroll Right Button   => Mouse Scroll Right Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/Multi Device Silent Mouse M585-M590 406B.txt",
    "content": "Solaar version 1.1.7\n\n\n  2: Multi Device Silent Mouse M585/M590\n     Device path  : /dev/hidraw2\n     WPID         : 406B\n     Codename     : M585/M590\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 37216581\n     Model ID:      B01B406B0000\n     Unit ID:       F2D653C0\n        Bootloader: BOT 48.00.B0001\n          Firmware: MPM 05.02.B0007\n             Other:\n     The power switch is located on the base.\n     Supports 34 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Bootloader BOT 48.00.B0001 00005BEB5EE001\n            Firmware: Firmware MPM 05.02.B0007 406B5BEB5EE001\n            Firmware: Other\n            Unit ID: F2D653C0  Model ID: B01B406B0000  Transport IDs: {'btleid': 'B01B', 'wpid': '406B'}\n         3: DEVICE NAME            {0005} V0\n            Name: M585/M590 Multi-Device Mouse\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: RESET                  {0020} V0\n         6: CRYPTO ID              {0021} V0\n         7: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: M585/M590\n         8: BATTERY STATUS         {1000} V0\n            Battery: 50%, discharging, next level 20%.\n         9: CHANGE HOST            {1814} V1\n            Cambiar Host        : 1:romanescu\n        10: HOSTS INFO             {1815} V1\n            Host 0 (paired): romanescu\n            Host 1 (paired): espinaca\n        11: REPROG CONTROLS V4     {1B04} V3\n            Acciones de Tecla/Botón (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button}\n            Acciones de Tecla/Botón        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button}\n            Desvio de Tecla/Botón (saved): {Middle Button:Normal, Back Button:Normal, Forward Button:Normal, Left Tilt:Normal, Right Tilt:Normal}\n            Desvio de Tecla/Botón        : {Middle Button:Normal, Back Button:Normal, Forward Button:Normal, Left Tilt:Normal, Right Tilt:Normal}\n        12: PERSISTENT REMAPPABLE ACTION {1C00} V0\n            Persistent Key/Button Mapping        : {Left Button:Mouse Button Left, Right Button:Mouse Button Right, Middle Button:Mouse Button Middle, Back Button:Mouse Button Back, Forward Button:Mouse Button Forward, Left Tilt:Horizontal Scroll Left, Right Tilt:Horizontal Scroll Right}\n        13: POINTER SPEED          {2205} V0\n            Pointer Speed: 1.0\n            Sensibilidad (Velocidad del puntero) (saved): 256\n            Sensibilidad (Velocidad del puntero)        : 256\n        14: VERTICAL SCROLLING     {2100} V0\n            Roller type: standard\n            Ratchet per turn: 18\n            Scroll lines: 0\n        15: DFUCONTROL SIGNED      {00C2} V0\n        16: DEVICE RESET           {1802} V0    internal, hidden\n        17: unknown:1803           {1803} V0    internal, hidden\n        18: CONFIG DEVICE PROPS    {1806} V0    internal, hidden\n        19: OOBSTATE               {1805} V0    internal, hidden\n        20: unknown:1813           {1813} V0    internal, hidden\n        21: unknown:1830           {1830} V0    internal, hidden\n        22: unknown:1861           {1861} V0    internal, hidden\n        23: unknown:1890           {1890} V0    internal, hidden\n        24: unknown:1891           {1891} V0    internal, hidden\n        25: unknown:18A1           {18A1} V0    internal, hidden\n        26: unknown:1DF3           {1DF3} V0    internal, hidden\n        27: unknown:1E00           {1E00} V0    hidden\n        28: unknown:1EB0           {1EB0} V0    internal, hidden\n        29: unknown:18B1           {18B1} V0    internal, hidden\n        30: unknown:1850           {1850} V0    internal, hidden\n        31: unknown:1F03           {1F03} V0    internal, hidden\n        32: unknown:18C0           {18C0} V0    internal, hidden\n        33: LOWRES WHEEL           {2130} V0\n            Wheel Reports: HID\n            Desvio Rueda Desplazamiento (saved): False\n            Desvio Rueda Desplazamiento        : False\n     Has 8 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Left Tilt                 , default: Mouse Scroll Left Button    => Mouse Scroll Left Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         6: Right Tilt                , default: Mouse Scroll Right Button   => Mouse Scroll Right Button\n             mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         7: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Has 7 persistent remappable keys:\n         0: Left Button                => Mouse Button: Mouse Button Left\n         1: Right Button               => Mouse Button: Mouse Button Right\n         2: Middle Button              => Mouse Button: Mouse Button Middle\n         3: Back Button                => Mouse Button: Mouse Button Back\n         4: Forward Button             => Mouse Button: Mouse Button Forward\n         5: Left Tilt                  => Horizontal Scroll: Horizontal Scroll Left\n         6: Right Tilt                 => Horizontal Scroll: Horizontal Scroll Right\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/Nano Receiver C52F.txt",
    "content": "Nano Receiver\n  Device path  : /dev/hidraw3\n  USB id       : 046d:c52f\n  Serial       : 6D0342C5\n    Firmware   : 30.00.B0009\n  Has 1 paired device(s) out of a maximum of 1.\n  Notifications: (none)\n\nSeen with Marathon Mouse M705\n"
  },
  {
    "path": "docs/devices/Nano Receiver C534.txt",
    "content": "Solaar version 1.1.4rc2\n\nNano Receiver\n  Device path  : /dev/hidraw1\n  USB id       : 046d:C534\n  Serial       : None\n    Firmware   : 29.01.B0016\n  Has 2 paired device(s) out of a maximum of 2.\n  Has 18 successful pairing(s) remaining.\n  Notifications: wireless, software present (0x000900)\n\n\nSeen paired with Wireless Keyboard 4075 and Wireless Mouse M185 new 4054\n"
  },
  {
    "path": "docs/devices/Nano Receiver C535.txt",
    "content": "Solaar version 1.1.5\n\nNano Receiver\n  Device path  : /dev/hidraw5\n  USB id       : 046d:C535\n  Serial       : 1F3F94FC\n    Firmware   : 31.00.B0001\n  Has 1 paired device(s) out of a maximum of 1.\n  Has 39 successful pairing(s) remaining.\n  Notifications: wireless, software present (0x000900)\n"
  },
  {
    "path": "docs/devices/Number Pad N545 2006.txt",
    "content": "solaar version 1.1.8\n\n  3: Number Pad N545\n     Device path  : /dev/hidraw3\n     WPID         : 2006\n     Codename     : N545\n     Kind         : numpad\n     Protocol     : HID++ 1.0\n     Polling rate : 20 ms (50Hz)\n     Serial number: 900A4D98\n          Firmware: 13.00.B0037\n        Bootloader: 02.03\n             Other: 00.01\n     The power switch is located on the base.\n     Notifications: battery status (0x100000).\n     Features: (none)\n     Battery: full, discharging.\n"
  },
  {
    "path": "docs/devices/PRO X 2 40A9.text",
    "content": "solaar version 1.1.10\n\nReceiver\n  Device path  : /dev/hidraw3\n  USB id       : 046d:C54D\n  Serial       : 8FF3BF7B\n    Firmware   : 07.00.B0008\n    Bootloader : 00.08\n    Other      : C1.53\n  Has 1 paired device(s) out of a maximum of 2.\n  Notifications: (none)\n  Device activity counters: 1=51\n\n  1: PRO X 2\n     Device path  : None\n     WPID         : 40A9\n     Codename     : PRO X 2\n     Kind         : mouse\n     Protocol     : HID++ 4.2\n     Polling rate : 8 ms (125Hz)\n     Serial number: <nope>\n     Model ID:      40A9C09B0000\n     Unit ID:       <nope>\n        Bootloader: BL1 71.00.B0012\n          Firmware: MPM 32.00.B0012\n     Supports 32 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: Bootloader BL1 71.00.B0012 AB1CDBC0A7D9\n            Firmware: Firmware MPM 32.00.B0012 40A9DBC0A7D9\n            Unit ID: <nope>  Model ID: 40A9C09B0000  Transport IDs: {'wpid': '40A9', 'usbid': 'C09B'}\n         3: DEVICE NAME            {0005} V2\n            Name: PRO X 2\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n         6: UNIFIED BATTERY        {1004} V3\n            Battery: 96%, discharging.\n         7: XY STATS               {2250} V1\n         8: WHEEL STATS            {2251} V0\n         9: unknown:2202           {2202} V0\t\tEXTENDED_ADJUSTABLE_DPI\n        10: MODE STATUS            {8090} V2\n        11: unknown:8061           {8061} V0\t\tEXTENDED_ADJUSTABLE_REPORT_RATE\n        12: ONBOARD PROFILES       {8100} V0\n            Device Mode: On-Board\n            Onboard Profiles (saved): Enable\n            Onboard Profiles        : Enable\n        13: MOUSE BUTTON SPY       {8110} V0\n        14: unknown:1500           {1500} V0\t\tFORCE_PAIRING\n        15: unknown:1801           {1801} V0    internal, hidden, unknown:000010\n        16: DEVICE RESET           {1802} V0    internal, hidden, unknown:000010\n        17: unknown:1803           {1803} V0    internal, hidden, unknown:000010\n        18: CONFIG DEVICE PROPS    {1806} V8    internal, hidden, unknown:000010\n        19: unknown:1817           {1817} V0    internal, hidden, unknown:000010\n        20: OOBSTATE               {1805} V0    internal, hidden\n        21: unknown:1830           {1830} V0    internal, hidden, unknown:000010\n        22: unknown:1875           {1875} V0    internal, hidden, unknown:000010\n        23: unknown:1861           {1861} V1    internal, hidden, unknown:000010\n        24: unknown:1890           {1890} V9    internal, hidden, unknown:000008\n        25: unknown:18A1           {18A1} V0    internal, hidden, unknown:000010\n        26: unknown:1E00           {1E00} V0    hidden\n        27: unknown:1E02           {1E02} V0    internal, hidden\n        28: unknown:1E22           {1E22} V1    internal, hidden, unknown:000010\n        29: unknown:1602           {1602} V0\n        30: unknown:1EB0           {1EB0} V0    internal, hidden, unknown:000010\n        31: unknown:18B1           {18B1} V0    internal, hidden, unknown:000010\n     Battery: 96%, discharging.\n"
  },
  {
    "path": "docs/devices/PRO X Wireless 4093.txt",
    "content": "Solaar version 1.1.14\n\n  2: PRO X Wireless\n     Device path  : None\n     WPID         : 4093\n     Codename     : PRO X\n     Kind         : mouse\n     Protocol     : HID++ 4.2\n     Report Rate : 1ms\n     Serial number: 8B24D1D1\n     Model ID:      4093C0940000\n     Unit ID:       8B24D1D1\n                 1: BL1 25.01.B0018\n                 3:\n                 0: MPM 25.01.B0018\n     Supports 28 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V3\n            Firmware: 1 BL1 25.01.B0018 AB00FE92436C\n            Firmware: 3\n            Firmware: 0 MPM 25.01.B0018 4093FE92436C\n            Unit ID: 8B24D1D1  Model ID: 4093C0940000  Transport IDs: {'wpid': '4093', 'usbid': 'C094'}\n         3: DEVICE NAME            {0005} V0\n            Name: PRO X Wireless\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n            Configuration: 11000000000000000000000000000000\n         6: UNIFIED BATTERY        {1004} V1\n            Battery: 71%, 0.\n         7: COLOR LED EFFECTS      {8070} V4    internal, hidden\n            LED Control        : HID++ error {'number': 2, 'request': 1908, 'error': 5, 'params': b''}\n         8: ONBOARD PROFILES       {8100} V0\n            Device Mode: On-Board\n            Onboard Profiles (saved): Profile 1\n            Onboard Profiles        : Profile 1\n         9: MOUSE BUTTON SPY       {8110} V0\n        10: REPORT RATE            {8060} V0\n            Report Rate: 1ms\n            Report Rate (saved): 1ms\n            Report Rate        : 1ms\n        11: ADJUSTABLE DPI         {2201} V2\n            Sensitivity (DPI) (saved): 800\n            Sensitivity (DPI)        : 800\n        12: FORCE PAIRING          {1500} V0\n        13: DEVICE RESET           {1802} V0    internal, hidden\n        14: unknown:1803           {1803} V0    internal, hidden\n        15: CONFIG DEVICE PROPS    {1806} V4    internal, hidden\n        16: unknown:1811           {1811} V0    internal, hidden\n        17: OOBSTATE               {1805} V0    internal, hidden\n        18: unknown:1830           {1830} V0    internal, hidden\n        19: unknown:1890           {1890} V5    internal, hidden\n        20: unknown:1891           {1891} V5    internal, hidden\n        21: unknown:18A1           {18A1} V0    internal, hidden\n        22: unknown:1801           {1801} V0    internal, hidden\n        23: unknown:18B1           {18B1} V0    internal, hidden\n        24: unknown:1E00           {1E00} V0    hidden\n        25: unknown:1EB0           {1EB0} V0    internal, hidden\n        26: unknown:1863           {1863} V0    internal, hidden\n        27: unknown:1E22           {1E22} V0    internal, hidden\n     Battery: 71%, 0.\n"
  },
  {
    "path": "docs/devices/Rechargeable Trackpad T651 B00C.txt",
    "content": "Solaar version 1.1.7\n\n  1: Rechargeable Trackpad T651\n     Device path  : /dev/hidraw9\n     USB id       : 046d:B00C\n     Codename     : Rechargeable\n     Kind         : touchpad\n     Protocol     : HID++ 2.0\n     Serial number:\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: RBM 05.00.B0026\n             Other:\n     Supports 9 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: FEATURE INFO           {0002} V0\n         3: DEVICE FW VERSION      {0003} V0\n            Firmware: Firmware RBM 05.00.B0026 B00C\n            Firmware: Other\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         4: DEVICE NAME            {0005} V0\n            Name: Rechargeable Trackpad T651\n            Kind: touchpad\n         5: unknown:1E00           {1E00} V0    hidden\n         6: GENERIC TEST           {1800} V0    internal, hidden\n         7: BATTERY STATUS         {1000} V0\n            Battery: 90%, discharging, next level 70%.\n         8: TOUCHPAD RAW XY        {6100} V0\n     Battery: 90%, discharging, next level 70%.\n"
  },
  {
    "path": "docs/devices/Signature M550.text",
    "content": "solaar version 1.1.19\n\n  1: Signature M550\n     Device path  : None\n     WPID         : B02B\n     Codename     : Logi M550\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number: D074434E\n     Model ID:      B02B00000000\n     Unit ID:       D074434E\n                 1: BL1 39.01.B0013\n                 0: RBM 17.01.B0013\n                 3:\n     The power switch is located on the (unknown).\n     Supports 30 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V4\n            Firmware: 1 BL1 39.01.B0013 B02BB0706FCD\n            Firmware: 0 RBM 17.01.B0013 B02BB0706FCD\n            Firmware: 3\n            Unit ID: D074434E  Model ID: B02B00000000  Transport IDs: {'btleid': 'B02B'}\n         3: DEVICE NAME            {0005} V0\n            Name: Signature M550\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n            Configuration: 11000000000000000000000000000000\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: Logi M550\n         7: UNIFIED BATTERY        {1004} V3\n            Battery: 35%, BatteryStatus.DISCHARGING.\n         8: REPROG CONTROLS V4     {1B04} V5\n            Key/Button Actions (saved): {Middle Button:Mouse Middle Button}\n            Key/Button Actions        : {Middle Button:Mouse Middle Button}\n            Key/Button Diversion (saved): {Middle Button:Regular}\n            Key/Button Diversion        : {Middle Button:Regular}\n         9: HOSTS INFO             {1815} V2\n            Host 0 (paired): mst\n        10: XY STATS               {2250} V1\n        11: LOWRES WHEEL           {2130} V0\n            Wheel Reports: HID\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        12: ADJUSTABLE DPI         {2201} V2\n            Sensitivity (DPI) (saved): 1000\n            Sensitivity (DPI)        : 1000\n        13: DFUCONTROL             {00C3} V0\n        14: DEVICE RESET           {1802} V0\n        15: unknown:1803           {0318} V0    internal, hidden, unknown:000010\n        16: CONFIG DEVICE PROPS    {1806} V8\n        17: unknown:1816           {1618} V0    internal, hidden, unknown:000010\n        18: OOBSTATE               {1805} V0\n        19: unknown:1830           {3018} V0    internal, hidden, unknown:000010\n        20: unknown:1891           {9118} V0    internal, hidden, unknown:000008\n        21: unknown:18A1           {A118} V0    internal, hidden, unknown:000010\n        22: unknown:1E00           {001E} V0    hidden\n        23: unknown:1E02           {021E} V0    internal, hidden\n        24: unknown:1E22           {221E} V0    internal, hidden, unknown:000010\n        25: unknown:1602           {0216} V0\n        26: unknown:1EB0           {B01E} V0    internal, hidden, unknown:000010\n        27: unknown:1861           {6118} V0    internal, hidden, unknown:000010\n        28: unknown:18B1           {B118} V0    internal, hidden, unknown:000010\n        29: unknown:920A           {0A92} V0    internal, hidden, unknown:000010\n     Has 4 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             analytics_key_events, mse, pos:0, group:1, group mask:empty\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             analytics_key_events, mse, pos:0, group:1, group mask:empty\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             analytics_key_events, raw_xy, divertable, reprogrammable, mse, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             force_raw_xy, raw_xy, virtual, divertable, pos:0, group:3, group mask:empty\n             reporting: default\n     Battery: 35%, BatteryStatus.DISCHARGING.\n"
  },
  {
    "path": "docs/devices/Signature M650 L Mouse B02A.txt",
    "content": "Solaar version 1.1.3\n\n  2: Signature M650 L Mouse\n     Device path  : None\n     WPID         : B02A\n     Codename     : Logi M650 L\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number: 46756ABD\n     Model ID:      B02A00000000\n     Unit ID:       46756ABD\n        Bootloader: BL1 38.01.B0011\n          Firmware: RBM 16.02.B0013\n             Other:\n     The power switch is located on the (unknown).\n     Supports 29 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BL1 38.01.B0011 B02ADFC9033D\n            Firmware: Firmware RBM 16.02.B0013 B02AB0706FCD\n            Firmware: Other\n            Unit ID: 46756ABD  Model ID: B02A00000000  Transport IDs: {'btleid': 'B02A'}\n         3: DEVICE NAME            {0005}\n            Name: Signature M650 L Mouse\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: DEVICE FRIENDLY NAME   {0007}\n            Friendly Name: Logi M650 L\n         7: UNIFIED BATTERY        {1004}\n         8: REPROG CONTROLS V4     {1B04}\n            DPI Sliding Adjustment (saved): Off\n            DPI Sliding Adjustment        : Off\n            Mouse Gestures (saved): Off\n            Mouse Gestures        : Off\n            Key/Button Actions (saved): {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button}\n            Key/Button Actions        : {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular}\n         9: HOSTS INFO             {1815}\n            Host 0 (paired): legion15\n        10: XY STATS                       11: LOWRES WHEEL           {2130}\n            Wheel Reports: HID\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        12: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 1200\n            Sensitivity (DPI)        : 1200\n        13: DFUCONTROL             {00C3}\n        14: DEVICE RESET           {1802}   internal, hidden, unknown:000010\n        15: unknown:1803           {1803}   internal, hidden, unknown:000010\n        16: CONFIG DEVICE PROPS    {1806}   internal, hidden, unknown:000010\n        17: unknown:1816           {1816}   internal, hidden, unknown:000010\n        18: OOBSTATE               {1805}   internal, hidden\n        19: unknown:1830           {1830}   internal, hidden, unknown:000010\n        20: unknown:1891           {1891}   internal, hidden, unknown:000008\n        21: unknown:18A1           {18A1}   internal, hidden, unknown:000010\n        22: unknown:1E00           {1E00}   hidden\n        23: unknown:1E02           {1E02}   internal, hidden\n        24: unknown:1E22           {1E22}   internal, hidden, unknown:000010\n        25: unknown:1602           {1602}\n        26: unknown:1EB0           {1EB0}   internal, hidden, unknown:000010\n        27: unknown:1861           {1861}   internal, hidden, unknown:000010\n        28: unknown:18B1           {18B1}   internal, hidden, unknown:000010\n     Has 6 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, analytics key events, pos:0, group:1, group mask:empty\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, analytics key events, pos:0, group:1, group mask:empty\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty\n             reporting: default\n     Battery: 95%, discharging.\n"
  },
  {
    "path": "docs/devices/Unifying Receiver C52B.txt",
    "content": "Solaar version 1.1.4\n\nUnifying Receiver\n  Device path  : /dev/hidraw0\n  USB id       : 046d:C52B\n  Serial       : E0662192\n    Firmware   : 24.11.B0036\n    Bootloader : 02.09\n    Other      : AA.AC\n  Has 2 paired device(s) out of a maximum of 6.\n  Notifications: wireless, software present (0x000900)\n  Device activity counters: 1=225, 2=132\n"
  },
  {
    "path": "docs/devices/Wireless All-in-One Keyboard TK820 4102.txt",
    "content": "Solaar version 1.1.1\n\n  1: Wireless All-in-One Keyboard TK820\n     Device path  : /dev/hidraw5\n     WPID         : 4102\n     Codename     : TK820\n     Kind         : keyboard\n     Protocol     : HID++ 2.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: 7D7699C9\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: RQK 52.00.B0025\n        Bootloader: BL  02.00.B0001\n          Hardware: 72\n             Other:\n     The power switch is located on the top right corner.\n     Supports 28 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: FEATURE INFO           {0002}\n         3: DEVICE FW VERSION      {0003}\n            Firmware: Firmware RQK 52.00.B0025 4102\n            Firmware: Bootloader BL  02.00.B0001 4102\n            Firmware: Hardware  72\n            Firmware: Other\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         4: DEVICE NAME            {0005}\n            Name: Wireless All-in-One Keyboard TK820\n            Kind: keyboard\n         5: BATTERY STATUS         {1000}\n            Battery: 20%, discharging, next level 5%.\n         6: WIRELESS DEVICE STATUS {1D4B}\n         7: unknown:1DF3           {1DF3}   internal, hidden\n         8: REPROG CONTROLS        {1B00}\n         9: unknown:1F03           {1F03}   internal, hidden\n        10: FN INVERSION           {40A0}\n            Swap Fx function (saved): True\n            Swap Fx function        : True\n        11: NEW FN INVERSION       {40A2}\n            Fn-swap: enabled\n            Fn-swap default: enabled\n        12: MOUSE POINTER          {2200}\n            DPI: 1000\n            Acceleration: low\n            Override OS ballistics\n            No vertical tuning, standard mice\n        13: DFUCONTROL LEGACY      {00C0}\n        14: unknown:1E80           {1E80}   internal, hidden\n        15: TOUCHPAD RAW XY        {6100}\n        16: unknown:1860           {1860}   internal, hidden\n        17: unknown:1E00           {1E00}   hidden\n        18: REPROG CONTROLS V3     {1B03}\n        19: unknown:1890           {1890}   internal, hidden\n        20: unknown:18E6           {18E6}   internal, hidden\n        21: unknown:18A0           {18A0}   internal, hidden\n        22: unknown:1830           {1830}   internal, hidden\n        23: unknown:1F04           {1F04}   internal, hidden\n        24: unknown:1EA1           {1EA1}   internal, hidden\n        25: unknown:18B0           {18B0}   internal, hidden\n        26: ENCRYPTION             {4100}\n        27: KEYBOARD LAYOUT        {4520}\n     Has 15 reprogrammable keys:\n         0: Fn Left Click              => ShowUI                        divertable\n         1: Metro Appswitch            => MetroAppSwitch                is FN, reprogrammable\n         2: Metro Search               => MetroSearch                   is FN, reprogrammable\n         3: unknown:00B2               => MetroShare2                   is FN, reprogrammable\n         4: unknown:00B3               => MetroDevices2                 is FN, reprogrammable\n         5: unknown:00B4               => MetroSettings2                is FN, reprogrammable\n         6: Previous                   => Previous                      is FN\n         7: Play/Pause                 => Play/Pause                    is FN\n         8: Next                       => Next                          is FN\n         9: Mute                       => Mute                          is FN\n        10: Volume Down                => Volume Down                   is FN\n        11: Volume Up                  => Volume Up                     is FN\n        12: Sleep                      => Sleep                         is FN, reprogrammable\n        13: Left Button                => Left Click                    mse\n        14: Right Button               => Right Click\n         mse\n     Battery: 20%, discharging, next level 5\n"
  },
  {
    "path": "docs/devices/Wireless Illuminated Keyboard K800 2010.txt",
    "content": "  2: Wireless Illuminated Keyboard K800\n     Codename     : K800\n     Kind         : keyboard\n     Wireless PID : 2010\n     Protocol     : HID++ 1.0\n     Polling rate : 20 ms (50Hz)\n     Serial number: FFC65665\n          Firmware: 22.01.B0019\n        Bootloader: 02.01\n             Other: 00.07\n     The power switch is located on the top right corner.\n     Notifications: battery status (0x100000).\n     Battery: full, discharging.\n\n\n# 0x00 - Enabled Notifications. rw (see HID++ 1.0 spec)\n<< (   0.055) [10 02 8100 000000] '\\x10\\x02\\x81\\x00\\x00\\x00\\x00'\n>> (   0.084) [10 02 8100 000000] '\\x10\\x02\\x81\\x00\\x00\\x00\\x00'\n\n# 0x01 -  Keyboard hand detection. rw, last param is 00 when hand detection is\n# enabled, 30 when disabled. (when enabled, keyboard will light up if not\n# already when hovering over the front)\n<< (   1.085) [10 02 8101 000000] '\\x10\\x02\\x81\\x01\\x00\\x00\\x00'\n>> (   1.114) [10 02 8101 000000] '\\x10\\x02\\x81\\x01\\x00\\x00\\x00'\n\n# 0x07 - Battery status (3 = one bar; 1 = red/critical; 5=two bars; 7=three\n# bars/full. Second returned param is 25 when keyboard is charging )\n<< (   7.327) [10 02 8107 000000] '\\x10\\x02\\x81\\x07\\x00\\x00\\x00'\n>> (   7.368) [10 02 8107 030000] '\\x10\\x02\\x81\\x07\\x03\\x00\\x00'\n\n# 0x09 - F key function. rw (read: status, set/get: 00 01 00 means swap\n# functions, 00 00 00 means do not swap functions)\n<< (   9.411) [10 02 8109 000000] '\\x10\\x02\\x81\\t\\x00\\x00\\x00'\n>> (   9.440) [10 02 8109 000000] '\\x10\\x02\\x81\\t\\x00\\x00\\x00'\n\n# 0x17 - Illumination info r/w. Last param: 02 to disable backlight, 01 to\n# enable backlight\n<< (  24.965) [10 02 8117 000000] '\\x10\\x02\\x81\\x17\\x00\\x00\\x00'\n>> (  24.988) [10 02 8117 3C0001] '\\x10\\x02\\x81\\x17<\\x00\\x01'\n\n# 0x51 - ?\n<< (  99.294) [10 02 8151 000000] '\\x10\\x02\\x81Q\\x00\\x00\\x00'\n>> (  99.543) [10 02 8151 000000] '\\x10\\x02\\x81Q\\x00\\x00\\x00'\n\n# 0x54 - ?\n<< ( 103.046) [10 02 8154 000000] '\\x10\\x02\\x81T\\x00\\x00\\x00'\n>> ( 103.295) [10 02 8154 FF0000] '\\x10\\x02\\x81T\\xff\\x00\\x00'\n\n# 0xD0 - ?\n<< ( 253.860) [10 02 81D0 000000] '\\x10\\x02\\x81\\xd0\\x00\\x00\\x00'\n>> ( 253.883) [10 02 81D0 000000] '\\x10\\x02\\x81\\xd0\\x00\\x00\\x00'\n\n# 0xF1 - Version info (params 0n 00 00 where n is 1..4)\n<< ( 289.991) [10 02 81F1 000000] '\\x10\\x02\\x81\\xf1\\x00\\x00\\x00'\n>> ( 290.032) [10 02 8F81 F10300] '\\x10\\x02\\x8f\\x81\\xf1\\x03\\x00'\n\n# 0xF3 - ?\n<< ( 292.075) [10 02 81F3 000000] '\\x10\\x02\\x81\\xf3\\x00\\x00\\x00'\n>> ( 292.116) [10 02 81F3 000000] '\\x10\\x02\\x81\\xf3\\x00\\x00\\x00'\n\n# 0x0F - This changes, the last commented line was observed in an earlier run\n<< (  17.728) [10 02 830F 000000] '\\x10\\x02\\x83\\x0f\\x00\\x00\\x00'\n>> (  17.976) [11 02 830F FFFB00000240025C000000000FF90080] '\\x11\\x02\\x83\\x0f\\xff\\xfb\\x00\\x00\\x02@\\x02\\\\\\x00\\x00\\x00\\x00\\x0f\\xf9\\x00\\x80'\n#>> ( 17.999) [11 02 830F FFFC007F0243025D000000000FF60080] '\\x11\\x02\\x83\\x0f\\xff\\xfc\\x00\\x7f\\x02C\\x02]\\x00\\x00\\x00\\x00\\x0f\\xf6\\x00\\x80'\n\n# See also https://git.lekensteyn.nl/ltunify/tree/registers.txt for a verbose\n# meaning of registers and params.\n"
  },
  {
    "path": "docs/devices/Wireless Illuminated Keyboard K800 new 406E.txt",
    "content": "  2: Wireless Illuminated Keyboard K800 new\n     Codename     : new\n     Kind         : keyboard\n     Wireless PID : 406E\n     Protocol     : HID++ 4.5\n     Polling rate : 20 ms (50Hz)\n     Serial number: 636E1413\n        Bootloader: BOT 60.00.B0002\n          Firmware: RQK 68.01.B0009\n     The power switch is located on the top right corner.\n     Supports 25 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n         3: DEVICE NAME            {0005}\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: BATTERY STATUS         {1000}\n         7: unknown:1983           {1983}\n         8: REPROG CONTROLS V4     {1B04}\n         9: FN INVERSION           {40A0}\n        10: ENCRYPTION             {4100}\n        11: KEYBOARD DISABLE       {4521}\n        12: unknown:00C2           {00C2}\n        13: unknown:1803           {1803}   internal, hidden\n        14: unknown:1806           {1806}   internal, hidden\n        15: unknown:1811           {1811}   internal, hidden\n        17: unknown:1890           {1890}   internal, hidden\n        18: unknown:18A1           {18A1}   internal, hidden\n        19: unknown:1DF3           {1DF3}   internal, hidden\n        20: unknown:1E00           {1E00}   hidden\n        21: unknown:1EB0           {1EB0}   internal, hidden\n        22: unknown:1861           {1861}   internal, hidden\n        23: unknown:1A20           {1A20}   internal, hidden\n        24: unknown:18B0           {18B0}   internal, hidden\n     Has 15 reprogrammable keys:\n         0: MY HOME                   , default: HomePage                    => MY HOME\n             is FN, FN sensitive, reprogrammable, divertable, pos:1, group:0, gmask:0\n         1: Mail                      , default: Email                       => Mail\n             is FN, FN sensitive, reprogrammable, divertable, pos:2, group:0, gmask:0\n         2: SEARCH                    , default: SearchForFiles              => SEARCH\n             is FN, FN sensitive, reprogrammable, divertable, pos:3, group:0, gmask:0\n         3: Application Switcher      , default: Application Switcher        => Application Switcher\n             is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, gmask:0\n         4: unknown:00E2              , default: unknown:00C1                => unknown:00E2\n             is FN, FN sensitive, divertable, pos:5, group:0, gmask:0\n         5: unknown:00E3              , default: unknown:00C2                => unknown:00E3\n             is FN, FN sensitive, divertable, pos:6, group:0, gmask:0\n         6: SLEEP                     , default: Sleep                       => SLEEP\n             is FN, FN sensitive, reprogrammable, divertable, pos:8, group:0, gmask:0\n         7: MEDIA PLAYER              , default: Music                       => MEDIA PLAYER\n             is FN, FN sensitive, reprogrammable, divertable, pos:9, group:0, gmask:0\n         8: Previous                  , default: Previous                    => Previous\n             is FN, FN sensitive, divertable, pos:10, group:0, gmask:0\n         9: Play/Pause                , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, divertable, pos:11, group:0, gmask:0\n        10: Next                      , default: Next                        => Next\n             is FN, FN sensitive, divertable, pos:12, group:0, gmask:0\n        11: Volume Up                 , default: Volume Up                   => Volume Up\n             nonstandard, divertable, pos:0, group:0, gmask:0\n        12: Volume Down               , default: Volume Down                 => Volume Down\n             nonstandard, divertable, pos:0, group:0, gmask:0\n        13: Mute                      , default: Mute                        => Mute\n             nonstandard, divertable, pos:0, group:0, gmask:0\n        14: Calculator                , default: Calculator                  => Calculator\n             nonstandard, reprogrammable, divertable, pos:0, group:0, gmask:0\n     Battery: 50%, discharging.\n"
  },
  {
    "path": "docs/devices/Wireless Keyboard 4075.txt",
    "content": "Solaar version 1.1.4rc2\n\n 1: Wireless Keyboard\n     Device path  : /dev/hidraw2\n     WPID         : 4075\n     Codename     :\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Polling rate : 20 ms (50Hz)\n     Serial number: 00000000\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: RQK 71.00.B0002\n     Supports 19 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Firmware RQK 71.00.B0002 4075\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Keyboard\n            Kind: keyboard\n         4: RESET                  {0020}\n         5: BATTERY STATUS         {1000}\n            Battery: 30%, discharging, next level 5%.\n         6: REPROG CONTROLS V4     {1B04}\n            Key/Button Diversion (saved): {Calculator:Regular, Mail:Regular, My Home:Regular, Search:Regular}\n            Key/Button Diversion        : {Calculator:Regular, Mail:Regular, My Home:Regular, Search:Regular}\n         7: WIRELESS DEVICE STATUS {1D4B}\n         8: NEW FN INVERSION       {40A2}\n            Fn-swap: disabled\n            Fn-swap default: disabled\n            Swap Fx function (saved): False\n            Swap Fx function        : False\n         9: ENCRYPTION             {4100}\n        10: LOCK KEY STATE         {4220}\n        11: KEYBOARD DISABLE KEYS  {4521}\n            Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        12: unknown:1810           {1810}   internal, hidden\n        13: unknown:1830           {1830}   internal, hidden\n        14: unknown:1890           {1890}   internal, hidden\n        15: unknown:18A0           {18A0}   internal, hidden\n        16: unknown:18B0           {18B0}   internal, hidden\n        17: unknown:1DF3           {1DF3}   internal, hidden\n        18: unknown:1E00           {1E00}   hidden\n     Has 4 reprogrammable keys:\n         0: My Home                   , default: HomePage                    => HomePage\n             is FN, FN sensitive, reprogrammable, divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Mail                      , default: Email                       => Email\n             is FN, FN sensitive, reprogrammable, divertable, pos:2, group:0, group mask:empty\n             reporting: default\n         2: Search                    , default: Search Files                => Search Files\n             is FN, FN sensitive, reprogrammable, divertable, pos:3, group:0, group mask:empty\n             reporting: default\n         3: Calculator                , default: Calculator                  => Calculator\n             is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, group mask:empty\n             reporting: default\n     Battery: 30%, discharging, next level 5%.\n"
  },
  {
    "path": "docs/devices/Wireless Keyboard Dell KB714 4015.txt",
    "content": "Solaar version 1.1.6rc4\n\n  4: Wireless Keyboard Dell KB714\n     Device path  : /dev/hidraw6\n     WPID         : 4015\n     Codename     : Dell KB714\n     Kind         : keyboard\n     Protocol     : HID++ 3.0\n     Polling rate : 20 ms (50Hz)\n     Serial number: C0A37A58\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: RQK 51.00.B0005\n     Supports 19 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V0\n            Firmware: Firmware RQK 51.00.B0005 4015\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         3: DEVICE NAME            {0005} V0\n            Name: Wireless Keyboard Dell KB714\n            Kind: keyboard\n         4: BATTERY STATUS         {1000} V0\n            Battery: 90%, discharging, next level 5%.\n         5: WIRELESS DEVICE STATUS {1D4B} V0\n         6: ENCRYPTION             {4100} V0\n         7: KEYBOARD LAYOUT        {4520} V0\n         8: unknown:1810           {1810} V0    internal, hidden\n         9: unknown:1830           {1830} V0    internal, hidden\n        10: unknown:1860           {1860} V0    internal, hidden\n        11: unknown:1890           {1890} V0    internal, hidden\n        12: unknown:18A0           {18A0} V0    internal, hidden\n        13: unknown:18B0           {18B0} V0    internal, hidden\n        14: REMAINING PAIRING      {1DF0} V0    hidden\n            Remaining Pairings: 54\n        15: unknown:1DF3           {1DF3} V0    internal, hidden\n        16: unknown:1E00           {1E00} V0    hidden\n        17: unknown:1E90           {1E90} V0    internal, hidden\n        18: DEVICE GROUPS          {0006} V0\n     Battery: 90%, discharging, next level 5%.\n"
  },
  {
    "path": "docs/devices/Wireless Keyboard K220 4005.txt",
    "content": "  2: Wireless Keyboard K220\n     Codename     : K220\n     Kind         : keyboard\n     Wireless PID : 4005\n     Protocol     : HID++ 2.0\n     Polling rate : 20 ms (50Hz)\n     Serial number: 5BB1D72E\n          Firmware: RQK 37.00.B0011\n     Supports 14 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: FEATURE INFO           {0002}\n         3: DEVICE FW VERSION      {0003}\n         4: DEVICE NAME            {0005}\n         5: BATTERY STATUS         {1000}\n         6: unknown:1820           {1820}   hidden\n         7: REPROG CONTROLS        {1B00}\n         8: REPROG CONTROLS V2     {1B01}\n         9: WIRELESS DEVICE STATUS {1D4B}\n        10: unknown:1DF0           {1DF0}   hidden\n        11: unknown:1DF3           {1DF3}   hidden\n        12: ENCRYPTION             {4100}\n        13: KEYBOARD LAYOUT        {4520}\n     Has 12 reprogrammable keys:\n         0: FN F1                      => Do Nothing One                is FN, reprogrammable\n         1: FN F2                      => Do Nothing One                is FN, reprogrammable\n         2: FN F3                      => Do Nothing One                is FN, reprogrammable\n         3: FN F4                      => Do Nothing One                is FN, reprogrammable\n         4: FN F5                      => Do Nothing One                is FN, reprogrammable\n         5: FN F6                      => Do Nothing One                is FN, reprogrammable\n         6: FN F7                      => Do Nothing One                is FN, reprogrammable\n         7: FN F8                      => Do Nothing One                is FN, reprogrammable\n         8: FN F9                      => Do Nothing One                is FN, reprogrammable\n         9: Mute                       => Mute                          is FN\n        10: Volume Down                => Volume Down                   is FN\n        11: Volume Up                  => Volume Up                     is FN\n     Battery: 90%, discharging.\n"
  },
  {
    "path": "docs/devices/Wireless Keyboard K230 400D.txt",
    "content": "  1: Wireless Keyboard K230\n     Device path  : /dev/hidraw5\n     WPID         : 400D\n     Codename     : K230\n     Kind         : keyboard\n     Protocol     : HID++ 2.0\n     Polling rate : 20 ms (50Hz)\n     Serial number: 9BB42D7D\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: RQK 40.00.B0011\n     The power switch is located on the bottom left corner.\n     Supports 14 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: FEATURE INFO           {0002}\n         3: DEVICE FW VERSION      {0003}\n            Firmware: Firmware RQK 40.00.B0011 400D\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         4: DEVICE NAME            {0005}\n            Name: Wireless Keyboard K230\n            Kind: keyboard\n         5: BATTERY STATUS         {1000}\n            Battery: 70%, discharging, next level 20%.\n         6: unknown:1820           {1820}   hidden\n         7: REPROG CONTROLS        {1B00}\n         8: REPROG CONTROLS V2     {1B01}\n         9: WIRELESS DEVICE STATUS {1D4B}\n        10: REMAINING PAIRING      {1DF0}   hidden\n            Remaining Pairings: 54\n        11: unknown:1DF3           {1DF3}   hidden\n        12: ENCRYPTION             {4100}\n        13: KEYBOARD LAYOUT        {4520}\n     Has 12 reprogrammable keys:\n         0: Fn F1                      => Do Nothing One                is FN, reprogrammable\n         1: Fn F2                      => Do Nothing One                is FN, reprogrammable\n         2: Fn F3                      => Do Nothing One                is FN, reprogrammable\n         3: Fn F4                      => Do Nothing One                is FN, reprogrammable\n         4: Fn F5                      => Do Nothing One                is FN, reprogrammable\n         5: Fn F6                      => Do Nothing One                is FN, reprogrammable\n         6: Fn F7                      => Do Nothing One                is FN, reprogrammable\n         7: Fn F8                      => Do Nothing One                is FN, reprogrammable\n         8: Fn F9                      => Do Nothing One                is FN, reprogrammable\n         9: Mute                       => Mute                          is FN\n        10: Volume Down                => Volume Down                   is FN\n        11: Volume Up                  => Volume Up                     is FN\n     Battery: 70%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/Wireless Keyboard K270(unifying) 4003.txt",
    "content": "  2: Wireless Keyboard K270(unifying)\n     Codename     : K270(unifying)\n     Kind         : keyboard\n     Wireless PID : 4003\n     Protocol     : HID++ 2.0\n     Polling rate : 20 ms (50Hz)\n     Serial number: FE8C8542\n          Firmware: RQK 35.00.B0017\n     The power switch is located on the top case.\n     Supports 12 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n         3: DEVICE NAME            {0005}\n         4: BATTERY STATUS         {1000}\n         5: unknown:1820           {1820}   hidden\n         6: REPROG CONTROLS        {1B00}\n         7: WIRELESS DEVICE STATUS {1D4B}\n         8: unknown:1DF0           {1DF0}   hidden\n         9: unknown:1DF3           {1DF3}   hidden\n        10: ENCRYPTION             {4100}\n        11: KEYBOARD LAYOUT        {4520}\n     Has 8 reprogrammable keys:\n         0: Play/Pause                 => Play/Pause                    nonstandard\n         1: Mute                       => Mute                          nonstandard\n         2: Volume Down                => Volume Down                   nonstandard\n         3: Volume Up                  => Volume Up                     nonstandard\n         4: MY HOME                    => HomePage                      nonstandard, reprogrammable\n         5: Mail                       => Email                         nonstandard, reprogrammable\n         6: SLEEP                      => Sleep                         nonstandard, reprogrammable\n         7: Calculator                 => Calculator                    nonstandard, reprogrammable\n     Battery: 90%, discharging.\n"
  },
  {
    "path": "docs/devices/Wireless Keyboard K360 4004.txt",
    "content": "Solaar version 1.1.4\n\n  2: Wireless Keyboard K360\n     Device path  : /dev/hidraw2\n     WPID         : 4004\n     Codename     : K360\n     Kind         : keyboard\n     Protocol     : HID++ 2.0\n     Polling rate : 20 ms (50Hz)\n     Serial number: 334AC01A\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: RQK 36.00.B0007\n     The power switch is located on the top case.\n     Supports 12 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Firmware RQK 36.00.B0007 4004\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Keyboard K360\n            Kind: keyboard\n         4: BATTERY STATUS         {1000}\n            Battery: 70%, discharging, next level 20%.\n         5: unknown:1820           {1820}   hidden\n         6: REPROG CONTROLS        {1B00}\n         7: WIRELESS DEVICE STATUS {1D4B}\n         8: REMAINING PAIRING      {1DF0}   hidden\n            Remaining Pairings: 55\n         9: unknown:1DF3           {1DF3}   hidden\n        10: FN INVERSION           {40A0}\n            Swap Fx function (saved): False\n            Swap Fx function        : False\n        11: ENCRYPTION             {4100}\n     Battery: 70%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/Wireless Keyboard K470 4075.txt",
    "content": "Solaar version 1.1.7\n\n  1: Wireless Keyboard\n     Device path  : /dev/hidraw6\n     WPID         : 4075\n     Codename     :\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Polling rate : 20 ms (50Hz)\n     Serial number: 00000000\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: RQK 71.00.B0002\n     Supports 20 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V0\n            Firmware: Firmware RQK 71.00.B0002 4075\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         3: DEVICE NAME            {0005} V0\n            Name: Wireless Keyboard\n            Kind: keyboard\n         4: RESET                  {0020} V0\n         5: BATTERY STATUS         {1000} V0\n            Battery: 30%, discharging, next level 5%.\n         6: REPROG CONTROLS V4     {1B04} V2\n            Key/Button Diversion (saved): {Calculator:Regular, Mail:Regular, My Home:Regular, Search:Regular}\n            Key/Button Diversion        : {Calculator:Regular, Mail:Regular, My Home:Regular, Search:Regular}\n         7: WIRELESS DEVICE STATUS {1D4B} V0\n         8: NEW FN INVERSION       {40A2} V0\n            Fn-swap: disabled\n            Fn-swap default: disabled\n            Swap Fx function (saved): False\n            Swap Fx function        : False\n         9: ENCRYPTION             {4100} V0\n        10: LOCK KEY STATE         {4220} V0\n        11: KEYBOARD DISABLE KEYS  {4521} V0\n            Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        12: unknown:1810           {1810} V0    internal, hidden\n        13: unknown:1830           {1830} V0    internal, hidden\n        14: unknown:1890           {1890} V0    internal, hidden\n        15: unknown:18A0           {18A0} V0    internal, hidden\n        16: unknown:18B0           {18B0} V0    internal, hidden\n        17: unknown:1DF3           {1DF3} V0    internal, hidden\n        18: unknown:1E00           {1E00} V0    hidden\n        19: unknown:1868           {1868} V0    internal, hidden\n     Has 4 reprogrammable keys:\n         0: My Home                   , default: HomePage                    => HomePage\n             is FN, FN sensitive, reprogrammable, divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Mail                      , default: Email                       => Email\n             is FN, FN sensitive, reprogrammable, divertable, pos:2, group:0, group mask:empty\n             reporting: default\n         2: Search                    , default: Search Files                => Search Files\n             is FN, FN sensitive, reprogrammable, divertable, pos:3, group:0, group mask:empty\n             reporting: default\n         3: Calculator                , default: Calculator                  => Calculator\n             is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, group mask:empty\n             reporting: default\n     Battery: 30%, discharging, next level 5%.\n"
  },
  {
    "path": "docs/devices/Wireless Keyboard K520 2011.txt",
    "content": "  2: Wireless Keyboard K520\n     Device path  : /dev/hidraw5\n     WPID         : 2011\n     Codename     : K520\n     Kind         : keyboard\n     Protocol     : HID++ 1.0\n     Polling rate : 20 ms (50Hz)\n     Serial number: C17F6771\n          Firmware: 26.00.B0012\n             Other: 00.07\n     The power switch is located on the top case.\n     Notifications: battery status (0x100000).\n     Battery: full, discharging.\n\nHas Swap Fn register\n"
  },
  {
    "path": "docs/devices/Wireless Keyboard MK270 4023.txt",
    "content": "Solaar version 1.1.7\n\n  1: Wireless Keyboard MK270\n     Device path  : /dev/hidraw6\n     WPID         : 4023\n     Codename     : MK270\n     Kind         : keyboard\n     Protocol     : HID++ 2.0\n     Polling rate : 20 ms (50Hz)\n     Serial number: 90A794A3\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: RQK 49.00.B0029\n     Supports 18 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V0\n            Firmware: Firmware RQK 49.00.B0029 4023\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         3: DEVICE NAME            {0005} V0\n            Name: Wireless Keyboard\n            Kind: keyboard\n         4: BATTERY STATUS         {1000} V0\n            Battery: 30%, discharging, next level 5%.\n         5: REPROG CONTROLS        {1B00} V0\n         6: WIRELESS DEVICE STATUS {1D4B} V0\n         7: FN INVERSION           {40A0} V0\n            Swap Fx function (saved): False\n            Swap Fx function        : False\n         8: ENCRYPTION             {4100} V0\n         9: KEYBOARD LAYOUT        {4520} V0\n        10: unknown:1810           {1810} V0    internal, hidden\n        11: unknown:1830           {1830} V0    internal, hidden\n        12: unknown:1890           {1890} V0    internal, hidden\n        13: unknown:18A0           {18A0} V0    internal, hidden\n        14: unknown:18B0           {18B0} V0    internal, hidden\n        15: unknown:1DF3           {1DF3} V0    internal, hidden\n        16: unknown:1E00           {1E00} V0    hidden\n        17: unknown:1868           {1868} V0    internal, hidden\n     Battery: 30%, discharging, next level 5%.\n"
  },
  {
    "path": "docs/devices/Wireless Mobile Mouse MX Anywhere 2 4072.txt",
    "content": "  2: Wireless Mobile Mouse MX Anywhere 2\n     Codename     : MX Anywhere 2\n     Kind         : mouse\n     Wireless PID : 4072\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: DDAE1933\n        Bootloader: BOT 57.10.B0003\n          Firmware: MPM 13.10.B0003\n          Firmware: MPM 13.10.B0003\n             Other:\n     The power switch is located on the base.\n     Supports 28 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n         3: DEVICE NAME            {0005}\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: CRYPTO ID              {0021}\n         7: BATTERY STATUS         {1000}\n         8: CONFIG DEVICE PROPS    {1806}   internal, hidden\n         9: CHANGE HOST            {1814}\n        10: REPROG CONTROLS V4     {1B04}\n        11: ADJUSTABLE DPI         {2201}\n        12: VERTICAL SCROLLING     {2100}\n            Roller type: 3G\n            Ratchet per turn: 24\n            Scroll lines: 0\n        13: HIRES WHEEL            {2121}\n            Multiplier: 8\n            Has invert\n              Normal wheel motion\n            Has ratchet switch\n              Normal wheel mode\n            Low resolution mode\n            HID notification\n            High Resolution Wheel Invert: False\n            Wheel Resolution: False\n        14: DFUCONTROL SIGNED      {00C2}\n        15: unknown:1813           {1813}   internal, hidden\n        16: unknown:1830           {1830}   internal, hidden\n        17: unknown:1890           {1890}   internal, hidden\n        18: unknown:1891           {1891}   internal, hidden\n        19: unknown:18A1           {18A1}   internal, hidden\n        20: unknown:18C0           {18C0}   internal, hidden\n        21: unknown:1DF3           {1DF3}   internal, hidden\n        22: unknown:1E00           {1E00}   hidden\n        23: unknown:1EB0           {1EB0}   internal, hidden\n        24: unknown:1803           {1803}   internal, hidden\n        25: unknown:1861           {1861}   internal, hidden\n        26: unknown:9001           {9001}   internal, hidden\n        27: OOBSTATE               {1805}   internal, hidden\n     Has 8 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Button\n             mse, pos:0, group:1, gmask:1\n         1: Right Button              , default: Right Click                 => Right Button\n             mse, pos:0, group:1, gmask:1\n         2: Middle Button             , default: Gesture Button Navigation   => Middle Button\n             mse, reprogrammable, divertable, pos:0, group:2, gmask:11\n         3: Back Button               , default: Mouse Back Button           => Back Button\n             mse, reprogrammable, divertable, pos:0, group:3, gmask:15\n         4: Forward Button            , default: Mouse Forward Button        => Forward Button\n             mse, reprogrammable, divertable, pos:0, group:3, gmask:15\n         5: Left Tilt                 , default: Mouse Scroll Left Button    => Left Tilt\n             mse, reprogrammable, divertable, pos:0, group:3, gmask:15\n         6: Right Tilt                , default: Mouse Scroll Right Button   => Right Tilt\n             mse, reprogrammable, divertable, pos:0, group:3, gmask:15\n         7: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, pos:0, group:4, gmask:0\n     Battery: 90%, discharging, next level 50%.\n15:29:59,190     INFO [MainThread] logitech_receiver.receiver: <UnifyingReceiver(/dev/hidraw0,3)>: found new device 3 (4024)\n"
  },
  {
    "path": "docs/devices/Wireless Mobile Mouse MX Anywhere 2S 406A.txt",
    "content": "Solaar version 1.1.3\n\n  2: Wireless Mobile Mouse MX Anywhere 2S\n     Device path  : None\n     WPID         : 406A\n     Codename     : MX Anywhere 2S\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: C53F2F0B\n     Model ID:      B01A406A0000\n     Unit ID:       3F714CA3\n        Bootloader: BOT 57.00.B0003\n          Firmware: MPM 13.00.B0003\n          Firmware: MPM 13.00.B0003\n             Other:\n     The power switch is located on the base.\n     Supports 28 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 57.00.B0003 406AD22DCF4D01\n            Firmware: Firmware MPM 13.00.B0003 B01AD22DCF4D01\n            Firmware: Firmware MPM 13.00.B0003 406AD22DCF4D01\n            Firmware: Other\n            Unit ID: 3F714CA3  Model ID: B01A406A0000  Transport IDs: {'btleid': 'B01A', 'wpid': '406A'}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Mobile Mouse MX Anywhere 2S\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: BATTERY STATUS         {1000}\n            Battery: 90%, discharging, next level 50%.\n         7: CONFIG DEVICE PROPS    {1806}   internal, hidden\n         8: CHANGE HOST            {1814}\n         9: REPROG CONTROLS V4     {1B04}\n        10: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 4000\n            Sensitivity (DPI)        : 4000\n        11: VERTICAL SCROLLING     {2100}\n            Roller type: 3G\n            Ratchet per turn: 24\n            Scroll lines: 0\n        12: HIRES WHEEL            {2121}\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Free wheel mode\n            Low resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): False\n            Scroll Wheel Resolution        : False\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        13: DFUCONTROL UNSIGNED    {00C1}\n        14: DFUCONTROL SIGNED      {00C2}\n        15: unknown:1813           {1813}   internal, hidden\n        16: unknown:1830           {1830}   internal, hidden\n        17: unknown:1890           {1890}   internal, hidden\n        18: unknown:1891           {1891}   internal, hidden\n        19: unknown:18A1           {18A1}   internal, hidden\n        20: unknown:18C0           {18C0}   internal, hidden\n        21: unknown:1DF3           {1DF3}   internal, hidden\n        22: unknown:1E00           {1E00}   hidden\n        23: unknown:1EB0           {1EB0}   internal, hidden\n        24: unknown:1803           {1803}   internal, hidden\n        25: unknown:1861           {1861}   internal, hidden\n        26: unknown:9001           {9001}   internal, hidden\n        27: OOBSTATE               {1805}   internal, hidden\n     Has 8 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Gesture Button Navigation   => Gesture Button Navigation\n             mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2,g4\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4\n             reporting: default\n         5: Left Tilt                 , default: Mouse Scroll Left Button    => Mouse Scroll Left Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4\n             reporting: default\n         6: Right Tilt                , default: Mouse Scroll Right Button   => Mouse Scroll Right Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4\n             reporting: default\n         7: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty\n             reporting: default\n     Battery: 90%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/Wireless Mobile Mouse MX Anywhere 2S B01A.txt",
    "content": "solaar version 1.1.9\n\n  1: Wireless Mobile Mouse MX Anywhere 2S\n     Device path  : /dev/hidraw1\n     USB id       : 046d:B01A\n     Codename     : Wireless\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number:\n     Model ID:      B01A406A0000\n     Unit ID:       3F714CA3\n        Bootloader: BOT 57.00.B0003\n          Firmware: MPM 13.00.B0003\n          Firmware: MPM 13.00.B0003\n             Other:\n     Supports 24 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Bootloader BOT 57.00.B0003 406AD22DCF4D01\n            Firmware: Firmware MPM 13.00.B0003 B01AD22DCF4D01\n            Firmware: Firmware MPM 13.00.B0003 406AD22DCF4D01\n            Firmware: Other\n            Unit ID: 3F714CA3  Model ID: B01A406A0000  Transport IDs: {'btleid': 'B01A', 'wpid': '406A'}\n         3: DEVICE NAME            {0005} V0\n            Name: Wireless Mobile Mouse MX Anywhere 2S\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: CONFIG CHANGE          {0020} V0\n         6: BATTERY STATUS         {1000} V0\n            Battery: 90%, discharging, next level 50%.\n         7: CONFIG DEVICE PROPS    {1806} V0    internal, hidden\n         8: CHANGE HOST            {1814} V1\n            Change Host        : 2:mburcheri2\n         9: REPROG CONTROLS V4     {1B04} V3\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Gesture Button Navigation, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Gesture Button Navigation, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Sliding DPI, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Diverted, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular}\n        10: ADJUSTABLE DPI         {2201} V1\n            Sensitivity (DPI) (saved): 3400\n            Sensitivity (DPI)        : 3400\n        11: VERTICAL SCROLLING     {2100} V0\n            Roller type: 3G\n            Ratchet per turn: 24\n            Scroll lines: 0\n        12: HIRES WHEEL            {2121} V0\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Free wheel mode\n            Low resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): False\n            Scroll Wheel Resolution        : False\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        13: unknown:1813           {1813} V0    internal, hidden\n        14: unknown:1830           {1830} V0    internal, hidden\n        15: unknown:18A1           {18A1} V0    internal, hidden\n        16: unknown:18C0           {18C0} V0    internal, hidden\n        17: unknown:1DF3           {1DF3} V0    internal, hidden\n        18: unknown:1E00           {1E00} V0    hidden\n        19: unknown:1EB0           {1EB0} V0    internal, hidden\n        20: unknown:1803           {1803} V0    internal, hidden\n        21: unknown:1861           {1861} V0    internal, hidden\n        22: unknown:9001           {9001} V0    internal, hidden\n        23: OOBSTATE               {1805} V0    internal, hidden\n     Has 8 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Gesture Button Navigation   => Gesture Button Navigation\n             mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2,g4\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4\n             reporting: diverted, raw XY diverted\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4\n             reporting: default\n         5: Left Tilt                 , default: Mouse Scroll Left Button    => Mouse Scroll Left Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4\n             reporting: default\n         6: Right Tilt                , default: Mouse Scroll Right Button   => Mouse Scroll Right Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4\n             reporting: default\n         7: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty\n             reporting: default\n     Battery: 90%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse 4022.txt",
    "content": "  2: Wireless Mouse\n     Codename     :\n     Kind         : mouse\n     Wireless PID : 4022\n     Protocol     : HID++ 2.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: 00000000\n          Firmware: RQM 38.00.B0044\n     Supports 18 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n         3: DEVICE NAME            {0005}\n         4: BATTERY STATUS         {1000}\n         5: REPROG CONTROLS        {1B00}\n         6: WIRELESS DEVICE STATUS {1D4B}\n         7: VERTICAL SCROLLING     {2100}\n         8: MOUSE POINTER          {2200}\n         9: unknown:1810           {1810}   internal, hidden\n        10: unknown:1830           {1830}   internal, hidden\n        11: unknown:1850           {1850}   internal, hidden\n        12: unknown:1890           {1890}   internal, hidden\n        13: unknown:18B0           {18B0}   internal, hidden\n        14: unknown:1DF3           {1DF3}   internal, hidden\n        15: unknown:1868           {1868}   internal, hidden\n        16: unknown:1869           {1869}   internal, hidden\n        17: unknown:1E00           {1E00}   hidden\n     Has 3 reprogrammable keys:\n         0: LEFT CLICK                 => LeftClick                     mse, reprogrammable\n         1: RIGHT CLICK                => RightClick                    mse, reprogrammable\n         2: MIDDLE BUTTON              => MiddleMouseButton             mse, reprogrammable\n     Battery: 30%, discharging.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse Dell WM514 4029.txt",
    "content": "Solaar version 1.1.6rc4\n\n  3: Wireless Mouse Dell WM514\n     Device path  : /dev/hidraw5\n     WPID         : 4029\n     Codename     : Dell WM514\n     Kind         : mouse\n     Protocol     : HID++ 3.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: 17F2CD56\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: RQM 44.00.B0013\n     The power switch is located on the base.\n     Supports 23 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V0\n            Firmware: Firmware RQM 44.00.B0013 4029\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         3: DEVICE NAME            {0005} V0\n            Name: Wireless Mouse Dell WM514\n            Kind: mouse\n         4: BATTERY STATUS         {1000} V0\n            Battery: 70%, discharging, next level 5%.\n         5: unknown:1830           {1830} V0    internal, hidden\n         6: unknown:1860           {1860} V0    internal, hidden\n         7: unknown:1890           {1890} V0    internal, hidden\n         8: unknown:18A0           {18A0} V0    internal, hidden\n         9: unknown:18B0           {18B0} V0    internal, hidden\n        10: unknown:18C0           {18C0} V0    internal, hidden\n        11: WIRELESS DEVICE STATUS {1D4B} V0\n        12: unknown:1DF3           {1DF3} V0    internal, hidden\n        13: REPROG CONTROLS        {1B00} V0\n        14: REMAINING PAIRING      {1DF0} V0    hidden\n            Remaining Pairings: 124\n        15: unknown:1E00           {1E00} V0    hidden\n        16: unknown:1850           {1850} V0    internal, hidden\n        17: unknown:1E90           {1E90} V0    internal, hidden\n        18: unknown:1F03           {1F03} V0    internal, hidden\n        19: VERTICAL SCROLLING     {2100} V0\n            Roller type: standard\n            Ratchet per turn: 24\n            Scroll lines: 0\n        20: MOUSE POINTER          {2200} V0\n            DPI: 1000\n            Acceleration: low\n            Override OS ballistics\n            No vertical tuning, standard mice\n        21: DEVICE GROUPS          {0006} V0\n        22: unknown:1BB0           {1BB0} V0\n     Battery: 70%, discharging, next level 5%.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse M185 new 4054.txt",
    "content": "Solaar version 1.1.4rc2\n\n 2: Wireless Mouse M185 new\n     Device path  : /dev/hidraw3\n     WPID         : 4054\n     Codename     : M185n\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 00000000\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: RQM 64.00.B0008\n     The power switch is located on the base.\n     Supports 19 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Firmware RQM 64.00.B0008 4054\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Mouse\n            Kind: mouse\n         4: RESET                  {0020}\n         5: REPROG CONTROLS V4     {1B04}\n            Mouse Gestures (saved): Off\n            Mouse Gestures        : Off\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button}\n            Key/Button Diversion (saved): {Middle Button:Regular}\n            Key/Button Diversion        : {Middle Button:Regular}\n         6: WIRELESS DEVICE STATUS {1D4B}\n         7: LOWRES WHEEL           {2130}\n            Wheel Reports: HID\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n         8: POINTER SPEED          {2205}\n            Pointer Speed: 1.0\n            Sensitivity (Pointer Speed) (saved): 256\n            Sensitivity (Pointer Speed)        : 256\n         9: DEVICE RESET           {1802}   internal, hidden\n        10: unknown:1810           {1810}   internal, hidden\n        11: unknown:1830           {1830}   internal, hidden\n        12: unknown:1850           {1850}   internal, hidden\n        13: unknown:1869           {1869}   internal, hidden\n        14: unknown:1890           {1890}   internal, hidden\n        15: unknown:18B1           {18B1}   internal, hidden\n        16: unknown:1DF3           {1DF3}   internal, hidden\n        17: unknown:1E00           {1E00}   hidden\n        18: unknown:1F03           {1F03}   internal, hidden\n     Has 3 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n     Battery status unavailable.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse M185,M235,M310 4055.txt",
    "content": "Solaar version 1.1.4\n\n  1: Wireless Mouse M185/M235/M310\n     Device path  : /dev/hidraw2\n     WPID         : 4055\n     Codename     : M185/M235/M310\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 82C9A01F\n     Model ID:      405500000000\n     Unit ID:       82C9A01F\n          Firmware: RQM 65.00.B0003\n     The power switch is located on the base.\n     Supports 21 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Firmware RQM 65.00.B0003 4055\n            Unit ID: 82C9A01F  Model ID: 405500000000  Transport IDs: {'wpid': '4055'}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Mouse\n            Kind: mouse\n         4: RESET                  {0020}\n         5: BATTERY STATUS         {1000}\n            Battery: 70%, discharging, next level 5%.\n         6: unknown:1810           {1810}   internal, hidden\n         7: unknown:1830           {1830}   internal, hidden\n         8: DEVICE RESET           {1802}   internal, hidden\n         9: unknown:1862           {1862}   internal, hidden\n        10: unknown:1890           {1890}   internal, hidden\n        11: unknown:18A0           {18A0}   internal, hidden\n        12: unknown:18B1           {18B1}   internal, hidden\n        13: REPROG CONTROLS V4     {1B04}\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button}\n            Key/Button Diversion (saved): {Left Button:Regular, Right Button:Regular, Middle Button:Regular}\n            Key/Button Diversion        : {Left Button:Regular, Right Button:Regular, Middle Button:Regular}\n        14: WIRELESS DEVICE STATUS {1D4B}\n        15: REMAINING PAIRING      {1DF0}   hidden\n            Remaining Pairings: 116\n        16: unknown:1DF3           {1DF3}   internal, hidden\n        17: unknown:1E00           {1E00}   hidden\n        18: unknown:1EB0           {1EB0}   internal, hidden\n        19: unknown:1F03           {1F03}   internal, hidden\n        20: LOWRES WHEEL           {2130}\n            Wheel Reports: HID\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n     Has 3 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, divertable, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, divertable, pos:0, group:1, group mask:g1\n             reporting: analytics key events reporting\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: unknown:000200\n     Battery: 70%, discharging, next level 5%.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse M185.text",
    "content": "solaar show\nrules cannot access modifier keys in Wayland, accessing process only works on GNOME with Solaar Gnome extension installed\nsolaar version 1.1.14-2\n\nUnifying Receiver\n  Device path  : /dev/hidraw1\n  USB id       : 046d:C52B\n  Serial       : EC219AC2\n  C Pending    : ff\n    0          : 12.11.B0032\n    1          : 04.16\n    3          : AA.AA\n  Has 2 paired device(s) out of a maximum of 6.\n  Notifications: wireless (0x000100)\n  Device activity counters: 1=195, 2=74\n\n  1: Wireless Mouse M175\n     Device path  : /dev/hidraw2\n     WPID         : 4008\n     Codename     : M175\n     Kind         : mouse\n     Protocol     : HID++ 2.0\n     Report Rate : 8ms\n     Serial number: 16E46E8C\n     Model ID:      000000000000\n     Unit ID:       00000000\n                 0: RQM 40.00.B0016\n     The power switch is located on the base.\n     Supports 21 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V0\n            Firmware: 0 RQM 40.00.B0016 4008\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         3: DEVICE NAME            {0005} V0\n            Name: Wireless Mouse M185\n            Kind: mouse\n         4: BATTERY STATUS         {1000} V0\n            Battery: 70%, 0, next level 5%.\n         5: unknown:1830           {1830} V0    internal, hidden\n         6: unknown:1850           {1850} V0    internal, hidden\n         7: unknown:1860           {1860} V0    internal, hidden\n         8: unknown:1890           {1890} V0    internal, hidden\n         9: unknown:18A0           {18A0} V0    internal, hidden\n        10: unknown:18C0           {18C0} V0    internal, hidden\n        11: WIRELESS DEVICE STATUS {1D4B} V0\n        12: unknown:1DF3           {1DF3} V0    internal, hidden\n        13: REPROG CONTROLS        {1B00} V0\n        14: REMAINING PAIRING      {1DF0} V0    hidden\n            Remaining Pairings: 117\n        15: unknown:1E00           {1E00} V0    hidden\n        16: unknown:1E80           {1E80} V0    internal, hidden\n        17: unknown:1E90           {1E90} V0    internal, hidden\n        18: unknown:1F03           {1F03} V0    internal, hidden\n        19: VERTICAL SCROLLING     {2100} V0\n            Roller type: standard\n            Ratchet per turn: 24\n            Scroll lines: 0\n        20: MOUSE POINTER          {2200} V0\n            DPI: 1000\n            Acceleration: low\n            Override OS ballistics\n            No vertical tuning, standard mice\n     Battery: 70%, 0, next level 5%.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse M215 2nd Gen 401B.txt",
    "content": "Solaar version 1.1.5\n\n  1: Wireless Mouse M215 2nd Gen\n     Device path  : None\n     WPID         : 401B\n     Codename     : Wireless\n     Kind         : mouse\n     Protocol     : HID++ 2.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: D225825E\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: RQM 27.12.B0029\n     The power switch is located on the base.\n     Supports 13 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V0\n            Firmware: Firmware RQM 27.12.B0029 401B\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         3: DEVICE NAME            {0005} V0\n            Name: Wireless Mouse M215 2nd Gen\n            Kind: mouse\n         4: BATTERY STATUS         {1000} V0\n            Battery: 90%, discharging, next level 5%.\n         5: WIRELESS DEVICE STATUS {1D4B} V0\n         6: unknown:1DF3           {1DF3} V0    hidden\n         7: REPROG CONTROLS        {1B00} V0\n         8: REMAINING PAIRING      {1DF0} V0    hidden\n            Remaining Pairings: 126\n         9: unknown:1F03           {1F03} V0    hidden\n        10: VERTICAL SCROLLING     {2100} V0\n            Roller type: standard\n            Ratchet per turn: 24\n            Scroll lines: 0\n        11: HI RES SCROLLING       {2120} V0\n            Hi-res scrolling disabled\n            Hi-res scrolling multiplier: 8\n            Scroll Wheel High Resolution (saved): False\n            Scroll Wheel High Resolution        : False\n        12: MOUSE POINTER          {2200} V0\n            DPI: 800\n            Acceleration: low\n            Override OS ballistics\n            No vertical tuning, standard mice\n     Battery: 90%, discharging, next level 5%.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse M310 M310t 4031.txt",
    "content": "  1: Wireless Mouse M310/M310t\n     Codename     : M310/M310t\n     Kind         : mouse\n     Wireless PID : 4031\n     Protocol     : HID++ 2.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: 03E8C0B4\n          Firmware: RQM 40.01.B0017\n     The power switch is located on the base.\n     Supports 21 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n         3: DEVICE NAME            {0005}\n         4: BATTERY STATUS         {1000}\n         5: unknown:1830           {1830}   internal, hidden\n         6: unknown:1850           {1850}   internal, hidden\n         7: unknown:1860           {1860}   internal, hidden\n         8: unknown:1890           {1890}   internal, hidden\n         9: unknown:18A0           {18A0}   internal, hidden\n        10: unknown:18C0           {18C0}   internal, hidden\n        11: WIRELESS DEVICE STATUS {1D4B}\n        12: unknown:1DF3           {1DF3}   internal, hidden\n        13: REPROG CONTROLS        {1B00}\n        14: unknown:1DF0           {1DF0}   hidden\n        15: unknown:1E00           {1E00}   hidden\n        16: unknown:1E80           {1E80}   internal, hidden\n        17: unknown:1E90           {1E90}   internal, hidden\n        18: unknown:1F03           {1F03}   internal, hidden\n        19: VERTICAL SCROLLING     {2100}\n        20: MOUSE POINTER          {2200}\n     Has 3 reprogrammable keys:\n         0: LEFT CLICK                 => LeftClick                     mse, reprogrammable\n         1: RIGHT CLICK                => RightClick                    mse, reprogrammable\n         2: MIDDLE BUTTON              => MiddleMouseButton             mse, reprogrammable\n     Battery: 70%, discharging.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse M325 400A.txt",
    "content": "\n 1: Wireless Mouse M325\n     Device path  : /dev/hidraw4\n     WPID         : 400A\n     Codename     : M325\n     Kind         : mouse\n     Protocol     : HID++ 2.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: D72D97E9\n     Model ID:      000000000000\n     Unit ID:       00000000\n          Firmware: RQM 40.01.B0018\n     The power switch is located on the base.\n     Supports 22 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V0\n            Firmware: Firmware RQM 40.01.B0018 400A\n            Unit ID: 00000000  Model ID: 000000000000  Transport IDs: {}\n         3: DEVICE NAME            {0005} V0\n            Name: Wireless Mouse M325\n            Kind: mouse\n         4: BATTERY STATUS         {1000} V0\n            Battery: 70%, discharging, next level 5%.\n         5: unknown:1830           {1830} V0    internal, hidden\n         6: unknown:1850           {1850} V0    internal, hidden\n         7: unknown:1860           {1860} V0    internal, hidden\n         8: unknown:1890           {1890} V0    internal, hidden\n         9: unknown:18A0           {18A0} V0    internal, hidden\n        10: unknown:18C0           {18C0} V0    internal, hidden\n        11: WIRELESS DEVICE STATUS {1D4B} V0\n        12: unknown:1DF3           {1DF3} V0    internal, hidden\n        13: REPROG CONTROLS        {1B00} V0\n        14: REMAINING PAIRING      {1DF0} V0    hidden\n            Remaining Pairings: 117\n        15: unknown:1E00           {1E00} V0    hidden\n        16: unknown:1E80           {1E80} V0    internal, hidden\n        17: unknown:1E90           {1E90} V0    internal, hidden\n        18: unknown:1F03           {1F03} V0    internal, hidden\n        19: VERTICAL SCROLLING     {2100} V0\n            Roller type: micro\n            Ratchet per turn: 36\n            Scroll lines: 0\n        20: MOUSE POINTER          {2200} V0\n            DPI: 800\n            Acceleration: low\n            Override OS ballistics\n            No vertical tuning, standard mice\n        21: unknown:18B0           {18B0} V0    internal, hidden\n     Battery: 70%, discharging, next level 5%.\n\n\nWireless Mouse M325\nCodename     : M325\nKind         : mouse\nWireless PID : 400A\nProtocol     : HID++ 2.0\nPolling rate : 8 ms (125Hz)\nSerial number: ABB05E01\n     Firmware: RQM 27.02.B0028\nThe power switch is located on the base.\nSupports 13 HID++ 2.0 features:\n    0: ROOT                   {0000}\n    1: FEATURE SET            {0001}\n    2: DEVICE FW VERSION      {0003}\n    3: DEVICE NAME            {0005}\n    4: BATTERY STATUS         {1000}\n    5: WIRELESS DEVICE STATUS {1D4B}\n    6: unknown:1DF3           {1DF3}   hidden\n    7: REPROG CONTROLS        {1B00}\n    8: unknown:1DF0           {1DF0}   hidden\n    9: unknown:1F03           {1F03}   hidden\n   10: VERTICAL SCROLLING     {2100}\n   11: HI RES SCROLLING       {2120}\n   12: MOUSE POINTER          {2200}\nHas 5 reprogrammable keys:\n    0: LEFT CLICK                 => LeftClick                     mse, reprogrammable\n    1: RIGHT CLICK                => RightClick                    mse, reprogrammable\n    2: MIDDLE BUTTON              => MiddleMouseButton             mse, reprogrammable\n    3: BACK AS BUTTON 4           => Back                          mse, reprogrammable\n    4: FORWARD AS BUTTON 5        => BrowserForward                mse, reprogrammable\n"
  },
  {
    "path": "docs/devices/Wireless Mouse M345 4017.txt",
    "content": "1: Wireless Mouse M345\n   Codename     : M345\n   Kind         : mouse\n   Wireless PID : 4017\n   Protocol     : HID++ 2.0\n   Polling rate : 8 ms\n   Serial number: 920DC223\n        Firmware: RQM 27.02.B0028\n   The power switch is located on the base.\n   Supports 13 HID++ 2.0 features:\n       0: ROOT                   {0000}\n       1: FEATURE SET            {0001}\n       2: DEVICE FW VERSION      {0003}\n       3: DEVICE NAME            {0005}\n       4: BATTERY STATUS         {1000}\n       5: WIRELESS DEVICE STATUS {1D4B}\n       6: unknown:1DF3           {1DF3}   hidden\n       7: REPROG CONTROLS        {1B00}\n       8: unknown:1DF0           {1DF0}   hidden\n       9: unknown:1F03           {1F03}   hidden\n      10: VERTICAL SCROLLING     {2100}\n      11: HI RES SCROLLING       {2120}\n      12: MOUSE POINTER          {2200}\n   Battery: 90%, discharging,\n"
  },
  {
    "path": "docs/devices/Wireless Mouse M510 1025.txt",
    "content": "Solaar version 1.1.4\n\n  1: Wireless Mouse M510\n     Device path  : /dev/hidraw2\n     WPID         : 1025\n     Codename     : M510\n     Kind         : mouse\n     Protocol     : HID++ 1.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: 93E8527F\n          Firmware: 23.01.B0016\n     The power switch is located on the base.\n     Notifications: battery status (0x100000).\n     Features: special buttons, buttons control resolution (0x820000)\n     Battery: good, discharging.\n\nHas Side Scrolling register\n"
  },
  {
    "path": "docs/devices/Wireless Mouse M510 4051.txt",
    "content": "  1: Wireless Mouse M510\n     Codename     : M510v2\n     Kind         : mouse\n     Wireless PID : 4051\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 8989B04C\n          Firmware: RQM 62.00.B0013\n     The power switch is located on the base.\n     Supports 22 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n         3: DEVICE NAME            {0005}\n         4: RESET                  {0020}\n         5: BATTERY STATUS         {1000}\n         6: unknown:1802           {1802}   internal, hidden\n         7: unknown:1810           {1810}   internal, hidden\n         8: unknown:1830           {1830}   internal, hidden\n         9: unknown:1862           {1862}   internal, hidden\n        10: unknown:1890           {1890}   internal, hidden\n        11: unknown:18A0           {18A0}   internal, hidden\n        12: unknown:18B1           {18B1}   internal, hidden\n        13: REPROG CONTROLS V4     {1B04}\n        14: WIRELESS DEVICE STATUS {1D4B}\n        15: unknown:1DF0           {1DF0}   hidden\n        16: unknown:1DF3           {1DF3}   internal, hidden\n        17: unknown:1E00           {1E00}   hidden\n        18: unknown:1EB0           {1EB0}   internal, hidden\n        19: unknown:1F03           {1F03}   internal, hidden\n        20: LOWRES WHEEL           {2130}\n        21: POINTER SPEED          {2205}\n     Has 7 reprogrammable keys:\n         0: LEFT CLICK                , default: LeftClick                   => LEFT CLICK\n             divertable, mse, pos:0, group:1, gmask:1\n         1: RIGHT CLICK               , default: RightClick                  => RIGHT CLICK\n             divertable, mse, pos:0, group:1, gmask:1\n         2: MIDDLE BUTTON             , default: MiddleMouseButton           => MIDDLE BUTTON\n             divertable, mse, reprogrammable, pos:0, group:2, gmask:3\n         3: LEFT SCROLL AS AC PAN     , default: HorzScrollLeftSet           => LEFT SCROLL AS AC PAN\n             divertable, mse, reprogrammable, pos:0, group:2, gmask:3\n         4: RIGHT SCROLL AS AC PAN    , default: HorzScrollRightSet          => RIGHT SCROLL AS AC PAN\n             divertable, mse, reprogrammable, pos:0, group:2, gmask:3\n         5: BACK AS BUTTON 4          , default: BackEx                      => BACK AS BUTTON 4\n             divertable, mse, reprogrammable, pos:0, group:2, gmask:3\n         6: FORWARD AS BUTTON 5       , default: BrowserForwardEx            => FORWARD AS BUTTON 5\n             divertable, mse, reprogrammable, pos:0, group:2, gmask:3\n     Battery: 70%, discharging.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse M525 4013.txt",
    "content": "  1: Wireless Mouse M525\n     Codename     : M525\n     Kind         : mouse\n     Wireless PID : 4013\n     Protocol     : HID++ 2.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: DAFA335E\n          Firmware: RQM 27.02.B0028\n     The power switch is located on the base.\n     Supports 13 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n         3: DEVICE NAME            {0005}\n         4: BATTERY STATUS         {1000}\n         5: WIRELESS DEVICE STATUS {1D4B}\n         6: unknown:1DF3           {1DF3}   hidden\n         7: REPROG CONTROLS        {1B00}\n         8: unknown:1DF0           {1DF0}   hidden\n         9: unknown:1F03           {1F03}   hidden\n        10: VERTICAL SCROLLING     {2100}\n        11: HI RES SCROLLING       {2120}\n        12: MOUSE POINTER          {2200}\n     Has 5 reprogrammable keys:\n         0: LEFT CLICK                 => LeftClick                     mse, reprogrammable\n         1: RIGHT CLICK                => RightClick                    mse, reprogrammable\n         2: MIDDLE BUTTON              => MiddleMouseButton             mse, reprogrammable\n         3: BACK AS BUTTON 4           => Back                          mse, reprogrammable\n         4: FORWARD AS BUTTON 5        => BrowserForward                mse, reprogrammable\n     Battery: 90%, discharging.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse M560 402D.txt",
    "content": "  1: Wireless Mouse M560\n     Codename     : M560\n     Kind         : mouse\n     Wireless PID : 402D\n     Protocol     : HID++ 2.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: 16E6E42A\n          Firmware: RQM 48.00.B0015\n     The power switch is located on the base.\n     Supports 22 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n         3: DEVICE NAME            {0005}\n         4: BATTERY STATUS         {1000}\n         5: unknown:1830           {1830}   internal, hidden\n         6: unknown:1850           {1850}   internal, hidden\n         7: unknown:1860           {1860}   internal, hidden\n         8: unknown:1890           {1890}   internal, hidden\n         9: unknown:18A0           {18A0}   internal, hidden\n        10: REPROG CONTROLS V3     {1B03}\n        11: WIRELESS DEVICE STATUS {1D4B}\n        12: unknown:1DF3           {1DF3}   internal, hidden\n        13: REPROG CONTROLS        {1B00}\n        14: unknown:1DF0           {1DF0}   hidden\n        15: unknown:1E00           {1E00}   hidden\n        16: unknown:18B0           {18B0}   internal, hidden\n        17: unknown:1E90           {1E90}   internal, hidden\n        18: unknown:1F03           {1F03}   internal, hidden\n        19: VERTICAL SCROLLING     {2100}\n        20: HI RES SCROLLING       {2120}\n        21: MOUSE POINTER          {2200}\n     Has 7 reprogrammable keys:\n         0: LEFT CLICK                 => LeftClick                     mse, reprogrammable\n         1: RIGHT CLICK                => RightClick                    mse, reprogrammable\n         2: BACK AS BUTTON 4           => Win8BackHorzLeft              mse, reprogrammable\n         3: FORWARD AS BUTTON 5        => Win8ForwardHorzRight          mse, reprogrammable\n         4: unknown:00B0               => Win8MetroWin7Forward          mse, reprogrammable\n         5: SHOW DESKTOP HPP           => Win8ShowDesktopWin7Back       mse, reprogrammable\n         6: unknown:00AF               => Win8Charm Appswitch GifAnimation   mse, reprogrammable, unknown:000020\n     Battery: 70%, discharging.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse MX Anywhere 2 404A.txt",
    "content": "  1: Wireless Mouse MX Anywhere 2\n     Codename     : MX Anywhere 2\n     Kind         : mouse\n     Wireless PID : 404A\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: F3B81C5B\n        Bootloader: BOT 23.00.B0007\n          Firmware: MPM 02.00.B0007\n          Firmware: MPM 02.00.B0007\n             Other:\n     The power switch is located on the base.\n     Supports 26 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n         3: DEVICE NAME            {0005}\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: BATTERY STATUS         {1000}\n         7: CHANGE HOST            {1814}\n         8: REPROG CONTROLS V4     {1B04}\n         9: ADJUSTABLE DPI         {2201}\n        10: VERTICAL SCROLLING     {2100}\n        11: HIRES WHEEL            {2121}\n        12: DFUCONTROL 2           {00C1}\n        13: unknown:1813           {1813}   internal, hidden\n        14: unknown:1830           {1830}   internal, hidden\n        15: unknown:1890           {1890}   internal, hidden\n        16: unknown:1891           {1891}   internal, hidden\n        17: unknown:18A1           {18A1}   internal, hidden\n        18: unknown:18C0           {18C0}   internal, hidden\n        19: unknown:1DF3           {1DF3}   internal, hidden\n        20: unknown:1E00           {1E00}   hidden\n        21: unknown:1EB0           {1EB0}   internal, hidden\n        22: unknown:1803           {1803}   internal, hidden\n        23: unknown:1861           {1861}   internal, hidden\n        24: unknown:9000           {9000}   internal, hidden\n        25: unknown:1805           {1805}   internal, hidden\n     Battery: 0%, recharging.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse MX Master 2S 4069.txt",
    "content": "Solaar version 1.1.4\n\n  1: Wireless Mouse MX Master 2S\n     Device path  : /dev/hidraw1\n     WPID         : 4069\n     Codename     : MX Master 2S\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 9429B808\n     Model ID:      B01940690000\n     Unit ID:       65D747F7\n        Bootloader: BOT 56.01.B0006\n          Firmware: MPM 12.01.B0006\n          Firmware: MPM 12.01.B0006\n             Other:\n     The power switch is located on the base.\n     Supports 31 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 56.01.B0006 406916A9FC5401\n            Firmware: Firmware MPM 12.01.B0006 B01916A9FC5401\n            Firmware: Firmware MPM 12.01.B0006 406916A9FC5401\n            Firmware: Other\n            Unit ID: 65D747F7  Model ID: B01940690000  Transport IDs: {'btleid': 'B019', 'wpid': '4069'}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Mouse MX Master 2S\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: CRYPTO ID              {0021}\n         7: BATTERY STATUS         {1000}\n            Battery: 50%, discharging, next level 20%.\n         8: CONFIG DEVICE PROPS    {1806}   internal, hidden\n         9: CHANGE HOST            {1814}\n            Cambiar Host        : 2:lapega\n        10: REPROG CONTROLS V4     {1B04}\n            Ajustar DPI deslizando (saved): Off\n            Ajustar DPI deslizando        : Off\n            Gestos de Ratón (saved): Off\n            Gestos de Ratón        : Off\n            Acciones de Tecla/Botón (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            Acciones de Tecla/Botón        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            Desvio de Tecla/Botón (saved): {Middle Button:Normal, Back Button:Normal, Forward Button:Normal, Mouse Gesture Button:Normal, Smart Shift:Normal}\n            Desvio de Tecla/Botón        : {Middle Button:Normal, Back Button:Normal, Forward Button:Normal, Mouse Gesture Button:Normal, Smart Shift:Normal}\n        11: ADJUSTABLE DPI         {2201}\n            Sensibilidad (PPP) (saved): 4000\n            Sensibilidad (PPP)        : 4000\n        12: VERTICAL SCROLLING     {2100}\n            Roller type: 3G\n            Ratchet per turn: 24\n            Scroll lines: 0\n        13: SMART SHIFT            {2110}\n            Trinquete Rueda Desplazamiento (saved): 50\n            Trinquete Rueda Desplazamiento        : 50\n        14: HIRES WHEEL            {2121}\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            High resolution mode\n            HID notification\n            Dirección Rueda Desplazamiento (saved): False\n            Dirección Rueda Desplazamiento        : False\n            Resolución Rueda Desplazamiento (saved): True\n            Resolución Rueda Desplazamiento        : True\n            Desvio Rueda Desplazamiento (saved): False\n            Desvio Rueda Desplazamiento        : False\n        15: GESTURE 2              {6501}\n            Gestos (saved): {45: True, 46: True}\n            Gestos        : {46: True, 45: True}\n            Gestures Diversion (saved): {46: False}\n            Gestures Diversion        : {46: False}\n        16: DFUCONTROL SIGNED      {00C2}\n        17: unknown:1813           {1813}   internal, hidden\n        18: unknown:1830           {1830}   internal, hidden\n        19: unknown:1890           {1890}   internal, hidden\n        20: unknown:1891           {1891}   internal, hidden\n        21: unknown:18A1           {18A1}   internal, hidden\n        22: unknown:18C0           {18C0}   internal, hidden\n        23: unknown:1DF3           {1DF3}   internal, hidden\n        24: unknown:1E00           {1E00}   hidden\n        25: unknown:1EB0           {1EB0}   internal, hidden\n        26: unknown:1803           {1803}   internal, hidden\n        27: unknown:1861           {1861}   internal, hidden\n        28: unknown:9001           {9001}   internal, hidden\n        29: unknown:9200           {9200}   internal, hidden\n        30: unknown:9202           {9202}   internal, hidden\n     Has 8 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Mouse Gesture Button      , default: Gesture Button Navigation   => Gesture Button Navigation\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         6: Smart Shift               , default: Smart Shift                 => Smart Shift\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         7: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty\n             reporting: default\n     Has 2 gesture(s), 0 param(s) and 4 spec(s):\n        Thumbwheel                 Enabled(   0): True   Diverted:(   0) False\n        NaturalScrolling           Enabled(   1): True   Diverted:(None) None\n        period unit                Spec   (   3): 800\n        DVI field width            Spec   (   1): 8\n        field widths               Spec   (   2): 8\n        resolution                 Spec   (   4): 2048\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse MX Master 2S B019.txt",
    "content": "Solaar version 1.1.3\n\n  1: Wireless Mouse MX Master 2S\n     Device path  : /dev/hidraw3\n     USB id       : 046d:B019\n     Codename     : MX Master 2S\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number:\n     Model ID:      B01940690000\n     Unit ID:       D34FD133\n        Bootloader: BOT 56.01.B0006\n          Firmware: MPM 12.01.B0006\n          Firmware: MPM 12.01.B0006\n             Other:\n     Supports 29 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 56.01.B0006 406916A9FC5401\n            Firmware: Firmware MPM 12.01.B0006 B01916A9FC5401\n            Firmware: Firmware MPM 12.01.B0006 406916A9FC5401\n            Firmware: Other\n            Unit ID: D34FD133  Model ID: B01940690000  Transport IDs: {'btleid': 'B019', 'wpid': '4069'}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Mouse MX Master 2S\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: CRYPTO ID              {0021}\n         7: BATTERY STATUS         {1000}\n            Battery: 50%, discharging, next level 20%.\n         8: CONFIG DEVICE PROPS    {1806}   internal, hidden\n         9: CHANGE HOST            {1814}\n            改变主机        : 1:yan-desktop\n        10: REPROG CONTROLS V4     {1B04}\n            DPI 滑动调节 (saved): 关\n            DPI 滑动调节        : 关\n            鼠标手势 (saved): Mouse Gesture Button\n            鼠标手势        : 关\n            按键/按钮操作 (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            按键/按钮操作        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            按键/按钮改道 (saved): {Middle Button:常规, Back Button:改道, Forward Button:改道, Mouse Gesture Button:改道, Smart Shift:常规}\n            按键/按钮改道        : {Middle Button:常规, Back Button:改道, Forward Button:改道, Mouse Gesture Button:改道, Smart Shift:常规}\n        11: ADJUSTABLE DPI         {2201}\n            灵敏度 (DPI) (saved): 1000\n            灵敏度 (DPI)        : 1000\n        12: VERTICAL SCROLLING     {2100}\n            Roller type: 3G\n            Ratchet per turn: 24\n            Scroll lines: 0\n        13: SMART SHIFT            {2110}\n            滚轮分段模式 (saved): 16\n            滚轮分段模式        : 16\n        14: HIRES WHEEL            {2121}\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            Low resolution mode\n            HID notification\n            滚轮方向 (saved): False\n            滚轮方向        : False\n            滚轮分辨率 (saved): False\n            滚轮分辨率        : False\n            滚轮改道 (saved): False\n            滚轮改道        : False\n        15: GESTURE 2              {6501}\n            手势 (saved): {45: True, 46: True}\n            手势        : {46: True, 45: True}\n            手势改道 (saved): {46: False}\n            手势改道        : {46: False}\n        16: unknown:1813           {1813}   internal, hidden\n        17: unknown:1830           {1830}   internal, hidden\n        18: unknown:18A1           {18A1}   internal, hidden\n        19: unknown:18C0           {18C0}   internal, hidden\n        20: unknown:1DF3           {1DF3}   internal, hidden\n        21: unknown:1E00           {1E00}   hidden\n        22: unknown:1EB0           {1EB0}   internal, hidden\n        23: unknown:1803           {1803}   internal, hidden\n        24: unknown:1861           {1861}   internal, hidden\n        25: unknown:9001           {9001}   internal, hidden\n        26: unknown:9200           {9200}   internal, hidden\n        27: unknown:9202           {9202}   internal, hidden\n        28: OOBSTATE               {1805}   internal, hidden\n     Has 8 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: diverted\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: diverted\n         5: Mouse Gesture Button      , default: Gesture Button Navigation   => Gesture Button Navigation\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3\n             reporting: diverted, raw XY diverted\n         6: Smart Shift               , default: Smart Shift                 => Smart Shift\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         7: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty\n             reporting: default\n     Has 2 gesture(s), 0 param(s) and 4 spec(s):\n        Thumbwheel                 Enabled(   0): True   Diverted:(   0) False\n        NaturalScrolling           Enabled(   1): True   Diverted:(None) None\n        period unit                Spec   (   3): 800\n        DVI field width            Spec   (   1): 8\n        field widths               Spec   (   2): 8\n        resolution                 Spec   (   4): 2048\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse MX Master 4041.txt",
    "content": "  4: Wireless Mouse MX Master\n     Device path  : /dev/hidraw4\n     WPID         : 4041\n     Codename     : MX Master\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: ----------\n     Model ID:      B01240410000\n     Unit ID:       ----------\n        Bootloader: BOT 18.01.B0014\n          Firmware: MPM 11.02.B0014\n          Firmware: MPM 11.02.B0014\n             Other:\n     The power switch is located on the base.\n     Supports 28 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 18.01.B0014 40410862AB80\n            Firmware: Firmware MPM 11.02.B0014 B0120862AB80\n            Firmware: Firmware MPM 11.02.B0014 40410862AB80\n            Firmware: Other\n            Unit ID: ------------  Model ID: B01240410000  Transport IDs: {'btleid': 'B012', 'wpid': '4041'}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Mouse MX Master\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: BATTERY STATUS         {1000}\n            Battery: 50%, discharging, next level 20%.\n         7: CHANGE HOST            {1814}\n            Change Host        : 1:jaaxx-elite\n         8: REPROG CONTROLS V4     {1B04}\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button, Smart Shift:Smart Shift}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button, Smart Shift:Smart Shift}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular}\n         9: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 1200\n            Sensitivity (DPI)        : 1200\n        10: VERTICAL SCROLLING     {2100}\n            Roller type: 3G\n            Ratchet per turn: 24\n            Scroll lines: 0\n        11: SMART SHIFT            {2110}\n            Scroll Wheel Rachet (saved): 8\n            Scroll Wheel Rachet        : 8\n        12: HIRES WHEEL            {2121}\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            High resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): True\n            Scroll Wheel Resolution        : True\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        13: GESTURE 2              {6501}\n            Gestures (saved): {45: True, 46: True}\n            Gestures        : {46: True, 45: True}\n            Gestures Diversion (saved): {46: False, 98: False, 211: False, 212: False}\n            Gestures Diversion        : {46: False, 98: False, 211: False, 212: False}\n        14: DFUCONTROL UNSIGNED    {00C1}\n        15: unknown:1813           {1813}   internal, hidden\n        16: unknown:1830           {1830}   internal, hidden\n        17: unknown:1890           {1890}   internal, hidden\n        18: unknown:18A1           {18A1}   internal, hidden\n        19: unknown:18C0           {18C0}   internal, hidden\n        20: unknown:1DF3           {1DF3}   internal, hidden\n        21: unknown:1E00           {1E00}   hidden\n        22: unknown:1EB0           {1EB0}   internal, hidden\n        23: unknown:1803           {1803}   internal, hidden\n        24: unknown:1861           {1861}   internal, hidden\n        25: unknown:9000           {9000}   internal, hidden\n        26: unknown:9200           {9200}   internal, hidden\n        27: unknown:9240           {9240}   internal, hidden\n     Has 7 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2,g3\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Mouse Gesture Button      , default: Gesture Button              => Gesture Button\n             mse, reprogrammable, divertable, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         6: Smart Shift               , default: Smart Shift                 => Smart Shift\n             mse, reprogrammable, divertable, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n     Has 5 gesture(s), 0 param(s) and 4 spec(s):\n        Thumbwheel                 Enabled(   0): True   Diverted:(   0) False\n        NaturalScrolling           Enabled(   1): True   Diverted:(None) None\n        Finger9                    Enabled(None): None   Diverted:(   1) False\n        unknown:00D3               Enabled(None): None   Diverted:(   2) False\n        unknown:00D4               Enabled(None): None   Diverted:(   3) False\n        period unit                Spec   (   3): 800\n        DVI field width            Spec   (   1): 8\n        field widths               Spec   (   2): 8\n        resolution                 Spec   (   4): 2048\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse MX Master 4071.txt",
    "content": "Solaar version 1.1.4\n\n  3: Wireless Mouse MX Master\n     Device path  : /dev/hidraw3\n     WPID         : 4071\n     Codename     : MX Master\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: D3596818\n     Model ID:      B01E40710000\n     Unit ID:       9803B76B\n        Bootloader: BOT 56.10.B0005\n          Firmware: MPM 12.10.B0005\n          Firmware: MPM 12.10.B0005\n             Other:\n     The power switch is located on the base.\n     Supports 31 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 56.10.B0005 40717622661101\n            Firmware: Firmware MPM 12.10.B0005 B01E7622661101\n            Firmware: Firmware MPM 12.10.B0005 40717622661101\n            Firmware: Other\n            Unit ID: 9803B76B  Model ID: B01E40710000  Transport IDs: {'btleid': 'B01E', 'wpid': '4071'}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Mouse MX Master\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: CRYPTO ID              {0021}\n         7: BATTERY STATUS         {1000}\n            Battery: N/A, recharging, next level 0%.\n         8: CONFIG DEVICE PROPS    {1806}   internal, hidden\n         9: CHANGE HOST            {1814}\n            Change Host        : 2:rachel\n        10: REPROG CONTROLS V4     {1B04}\n            DPI Sliding Adjustment (saved): Off\n            DPI Sliding Adjustment        : Off\n            Mouse Gestures (saved): Off\n            Mouse Gestures        : Off\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular}\n        11: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 1000\n            Sensitivity (DPI)        : 1000\n        12: VERTICAL SCROLLING     {2100}\n            Roller type: 3G\n            Ratchet per turn: 24\n            Scroll lines: 0\n        13: SMART SHIFT            {2110}\n            Scroll Wheel Rachet (saved): 10\n            Scroll Wheel Rachet        : 10\n        14: HIRES WHEEL            {2121}\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            High resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False            Scroll Wheel Resolution (saved): True\n            Scroll Wheel Resolution        : True\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        15: GESTURE 2              {6501}\n            Gestures (saved): {45: True, 46: True}\n            Gestures        : {46: True, 45: True}\n            Gestures Diversion (saved): {46: False}\n            Gestures Diversion        : {46: False}\n        16: DFUCONTROL SIGNED      {00C2}\n        17: unknown:1813           {1813}   internal, hidden\n        18: unknown:1830           {1830}   internal, hidden\n        19: unknown:1890           {1890}   internal, hidden\n        20: unknown:1891           {1891}   internal, hidden\n        21: unknown:18A1           {18A1}   internal, hidden\n        22: unknown:18C0           {18C0}   internal, hidden\n        23: unknown:1DF3           {1DF3}   internal, hidden\n        24: unknown:1E00           {1E00}   hidden\n        25: unknown:1EB0           {1EB0}   internal, hidden\n        26: unknown:1803           {1803}   internal, hidden\n        27: unknown:1861           {1861}   internal, hidden\n        28: unknown:9001           {9001}   internal, hidden\n        29: unknown:9200           {9200}   internal, hidden\n        30: unknown:9202           {9202}   internal, hidden\n     Has 8 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Mouse Gesture Button      , default: Gesture Button Navigation   => Gesture Button Navigation\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         6: Smart Shift               , default: Smart Shift                 => Smart Shift\n             mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3\n             reporting: default\n         7: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty\n             reporting: default\n     Has 2 gesture(s), 0 param(s) and 4 spec(s):\n        Thumbwheel                 Enabled(   0): True   Diverted:(   0) False\n        NaturalScrolling           Enabled(   1): True   Diverted:(None) None\n        period unit                Spec   (   3): 800\n        DVI field width            Spec   (   1): 8\n        field widths               Spec   (   2): 8\n        resolution                 Spec   (   4): 2048\n     Battery: N/A, recharging, next level 0%.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse MX Master B012.txt",
    "content": "Solaar version 1.1.3\n\n  1: Wireless Mouse MX Master\n     Device path  : /dev/hidraw4\n     USB id       : 046d:B012\n     Codename     : MX Master\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Serial number:\n     Model ID:      B01240410000\n     Unit ID:       3E9C68EF\n        Bootloader: BOT 18.01.B0014\n          Firmware: MPM 11.02.B0014\n          Firmware: MPM 11.02.B0014\n             Other:\n     Supports 28 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 18.01.B0014 40410862AB80\n            Firmware: Firmware MPM 11.02.B0014 B0120862AB80\n            Firmware: Firmware MPM 11.02.B0014 40410862AB80\n            Firmware: Other\n            Unit ID: 3E9C68EF  Model ID: B01240410000  Transport IDs: {'btleid': 'B012', 'wpid': '4041'}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Mouse MX Master\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: BATTERY STATUS         {1000}\n            Battery: 50%, discharging, next level 20%.\n         7: CHANGE HOST            {1814}\n            Change Host        : 1:heimdall\n         8: REPROG CONTROLS V4     {1B04}\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button, Smart Shift:Smart Shift}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button, Smart Shift:Smart Shift}\n            Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Diverted, Smart Shift:Diverted}\n            Key/Button Diversion        : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Diverted, Smart Shift:Diverted}\n         9: ADJUSTABLE DPI         {2201}\n            Sensitivity (DPI) (saved): 1000\n            Sensitivity (DPI)        : 1000\n        10: VERTICAL SCROLLING     {2100}\n            Roller type: 3G\n            Ratchet per turn: 24\n            Scroll lines: 0\n        11: SMART SHIFT            {2110}\n            Scroll Wheel Rachet (saved): 35\n            Scroll Wheel Rachet        : 35\n        12: HIRES WHEEL            {2121}\n            Multiplier: 8\n            Has invert: Normal wheel motion\n            Has ratchet switch: Normal wheel mode\n            High resolution mode\n            HID notification\n            Scroll Wheel Direction (saved): False\n            Scroll Wheel Direction        : False\n            Scroll Wheel Resolution (saved): True\n            Scroll Wheel Resolution        : True\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        13: GESTURE 2              {6501}\n            Gestures (saved): {45: True, 46: True}\n            Gestures        : {46: True, 45: True}\n            Gestures Diversion (saved): {46: False, 98: False, 211: False, 212: False}\n            Gestures Diversion        : {46: False, 98: False, 211: False, 212: False}\n        14: unknown:1813           {1813}   internal, hidden\n        15: unknown:1830           {1830}   internal, hidden\n        16: unknown:1890           {1890}   internal, hidden\n        17: unknown:18A1           {18A1}   internal, hidden\n        18: unknown:18C0           {18C0}   internal, hidden\n        19: unknown:1DF3           {1DF3}   internal, hidden\n        20: unknown:1E00           {1E00}   hidden\n        21: unknown:1EB0           {1EB0}   internal, hidden\n        22: unknown:1803           {1803}   internal, hidden\n        23: unknown:1861           {1861}   internal, hidden\n        24: unknown:9000           {9000}   internal, hidden\n        25: unknown:9200           {9200}   internal, hidden\n        26: unknown:9240           {9240}   internal, hidden\n        27: OOBSTATE               {1805}   internal, hidden\n     Has 7 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2,g3\n             reporting: default\n         3: Back Button               , default: Mouse Back Button           => Mouse Back Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         4: Forward Button            , default: Mouse Forward Button        => Mouse Forward Button\n             mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         5: Mouse Gesture Button      , default: Gesture Button              => Gesture Button\n             mse, reprogrammable, divertable, pos:0, group:3, group mask:g1,g2,g3\n             reporting: diverted\n         6: Smart Shift               , default: Smart Shift                 => Smart Shift\n             mse, reprogrammable, divertable, pos:0, group:3, group mask:g1,g2,g3\n             reporting: diverted\n     Has 5 gesture(s), 0 param(s) and 4 spec(s):\n        Thumbwheel                 Enabled(   0): True   Diverted:(   0) False\n        NaturalScrolling           Enabled(   1): True   Diverted:(None) None\n        Finger9                    Enabled(None): None   Diverted:(   1) False\n        unknown:00D3               Enabled(None): None   Diverted:(   2) False\n        unknown:00D4               Enabled(None): None   Diverted:(   3) False\n        period unit                Spec   (   3): 800\n        DVI field width            Spec   (   1): 8\n        field widths               Spec   (   2): 8\n        resolution                 Spec   (   4): 2048\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/Wireless Mouse Pebble M350 4080.txt",
    "content": "Solaar version 1.1.4\n\n  2: Wireless Mouse Pebble M350\n     Device path  : /dev/hidraw2\n     WPID         : 4080\n     Codename     : Pebble\n     Kind         : mouse\n     Protocol     : HID++ 4.5\n     Polling rate : 8 ms (125Hz)\n     Serial number: 2B442F40\n     Model ID:      B02140800000\n     Unit ID:       DE12CCD9\n          Firmware: MPM 18.00.B0007\n             Other:\n     The power switch is located on the base.\n     Supports 26 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Firmware MPM 18.00.B0007 4080BEA0D686\n            Firmware: Other\n            Unit ID: DE12CCD9  Model ID: B02140800000  Transport IDs: {'btleid': 'B021', 'wpid': '4080'}\n         3: DEVICE NAME            {0005} V0\n            Name: M350 Wireless Mouse\n            Kind: mouse\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: RESET                  {0020} V0\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: Logitech Pebble\n         7: BATTERY STATUS         {1000} V1\n            Battery: 50%, discharging, next level 20%.\n         8: REPROG CONTROLS V4     {1B04} V4\n            Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button}\n            Key/Button Actions        : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button}\n            Key/Button Diversion (saved): {Middle Button:Regular, ?}\n            Key/Button Diversion        : {Middle Button:Regular}\n         9: CHANGE HOST            {1814} V1\n            Change Host        : 1:brandy\n        10: ADJUSTABLE DPI         {2201} V1\n            Sensitivity (DPI) (saved): 1000\n            Sensitivity (DPI)        : 1000\n        11: LOWRES WHEEL           {2130} V0\n            Wheel Reports: HID\n            Scroll Wheel Diversion (saved): False\n            Scroll Wheel Diversion        : False\n        12: DEVICE RESET           {1802} V0    internal, hidden\n        13: unknown:1803           {1803} V0    internal, hidden\n        14: CONFIG DEVICE PROPS    {1806} V5    internal, hidden\n        15: unknown:1812           {1812} V0    internal, hidden\n        16: OOBSTATE               {1805} V0    internal, hidden\n        17: unknown:1830           {1830} V0    internal, hidden\n        18: unknown:1890           {1890} V4    internal, hidden\n        19: unknown:1891           {1891} V4    internal, hidden\n        20: unknown:18A1           {18A1} V0    internal, hidden\n        21: unknown:1DF3           {1DF3} V0    internal, hidden\n        22: unknown:1E00           {1E00} V0    hidden\n        23: unknown:1EB0           {1EB0} V0    internal, hidden\n        24: unknown:1861           {1861} V0    internal, hidden\n        25: unknown:18B1           {18B1} V0    internal, hidden\n     Has 4 reprogrammable keys:\n         0: Left Button               , default: Left Click                  => Left Click\n             mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         1: Right Button              , default: Right Click                 => Right Click\n             mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1\n             reporting: default\n         2: Middle Button             , default: Mouse Middle Button         => Mouse Middle Button\n             mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2\n             reporting: default\n         3: Virtual Gesture Button    , default: Virtual Gesture Button      => Virtual Gesture Button\n             divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty\n             reporting: default\n     Battery: 50%, discharging, next level 20%.\n"
  },
  {
    "path": "docs/devices/Wireless Multi-Device Keyboard K780 405B.txt",
    "content": "Solaar version 1.1.7\n\n  1: Wireless Multi-Device Keyboard K780\n     Device path  : /dev/hidraw4\n     WPID         : 405B\n     Codename     : K780\n     Kind         : keyboard\n     Protocol     : HID++ 4.5\n     Polling rate : 20 ms (50Hz)\n     Serial number: 3C60AFA4\n     Model ID:      B33B405B0000\n     Unit ID:       6CAF50FF\n        Bootloader: BOT 25.01.B0006\n          Firmware: MPK 01.04.B0028\n             Other:\n     The power switch is located on the edge of top right corner.\n     Supports 31 HID++ 2.0 features:\n         0: ROOT                   {0000} V0\n         1: FEATURE SET            {0001} V0\n         2: DEVICE FW VERSION      {0003} V2\n            Firmware: Bootloader BOT 25.01.B0006 0000C9839F9301\n            Firmware: Firmware MPK 01.04.B0028 405BC9839F9301\n            Firmware: Other\n            Unit ID: 6CAF50FF  Model ID: B33B405B0000  Transport IDs: {'btleid': 'B33B', 'wpid': '405B'}\n         3: DEVICE NAME            {0005} V0\n            Name: K780 Multi-Device Wireless Keyboard\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B} V0\n         5: RESET                  {0020} V0\n         6: DEVICE FRIENDLY NAME   {0007} V0\n            Friendly Name: Keyboard K780\n         7: BATTERY STATUS         {1000} V0\n            Battery: 90%, discharging, next level 50%.\n         8: CHANGE HOST            {1814} V1\n            Cambiar Host        : 1:romanescu\n         9: HOSTS INFO             {1815} V1\n            Host 0 (paired): romanescu\n            Host 1 (paired): espinaca\n            Host 2 (unpaired):\n        10: REPROG CONTROLS V4     {1B04} V3\n            Desvio de Tecla/Botón (saved): {Volume Up:Normal, Volume Down:Normal, Mute:Normal, Play/Pause:Normal, Next:Normal, Previous:Normal, Multiplatform Back:Normal, Multiplatform Insert:Normal, Screen Capture/Print Screen:Normal, Fn Down:Normal, Fn Up:Normal, Multiplatform Lock:Normal, Host Switch Channel 1:Normal, Host Switch Channel 2:Normal, Host Switch Channel 3:Normal, MultiPlatform Search:Normal, MultiPlatform Home/Mission Control:Normal, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Normal}\n            Desvio de Tecla/Botón        : {Volume Up:Normal, Volume Down:Normal, Mute:Normal, Play/Pause:Normal, Next:Normal, Previous:Normal, Multiplatform Back:Normal, Multiplatform Insert:Normal, Screen Capture/Print Screen:Normal, Fn Down:Normal, Fn Up:Normal, Multiplatform Lock:Normal, Host Switch Channel 1:Normal, Host Switch Channel 2:Normal, Host Switch Channel 3:Normal, MultiPlatform Search:Normal, MultiPlatform Home/Mission Control:Normal, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Normal}\n        11: PERSISTENT REMAPPABLE ACTION {1C00} V0\n            Persistent Key/Button Mapping        : {Volume Up:Volume Up, Volume Down:Volume Down, Mute:Mute, Play/Pause:Play/Pause, Next:Scan Next Track, Previous:Scan Previous Track, Multiplatform Back:AC Back, MultiPlatform Search:AC Search, MultiPlatform Home/Mission Control:AC Home, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:COMPOSE}\n        12: NEW FN INVERSION       {40A2} V0\n            Fn-swap: enabled\n            Fn-swap default: enabled\n            Intercambiar función Fx (saved): True\n            Intercambiar función Fx        : True\n        13: ENCRYPTION             {4100} V0\n        14: KEYBOARD DISABLE KEYS  {4521} V0\n            Desactivar teclas (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Desactivar teclas        : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        15: MULTIPLATFORM          {4531} V0\n            Especificar SO (saved): Windows\n            Especificar SO        : Windows\n        16: LOCK KEY STATE         {4220} V0\n        17: DFUCONTROL SIGNED      {00C2} V0\n        18: unknown:1803           {1803} V0    internal, hidden\n        19: CONFIG DEVICE PROPS    {1806} V0    internal, hidden\n        20: OOBSTATE               {1805} V0    internal, hidden\n        21: unknown:1813           {1813} V0    internal, hidden\n        22: unknown:1830           {1830} V0    internal, hidden\n        23: unknown:1861           {1861} V0    internal, hidden\n        24: unknown:1890           {1890} V0    internal, hidden\n        25: unknown:1891           {1891} V0    internal, hidden\n        26: unknown:18A1           {18A1} V0    internal, hidden\n        27: unknown:1DF3           {1DF3} V0    internal, hidden\n        28: unknown:1E00           {1E00} V0    hidden\n        29: unknown:1EB0           {1EB0} V0    internal, hidden\n        30: unknown:18B0           {18B0} V0    internal, hidden\n     Has 19 reprogrammable keys:\n         0: Host Switch Channel 1     , default: HostSwitch Channel 1        => HostSwitch Channel 1\n             is FN, FN sensitive, divertable, persistently divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         1: Host Switch Channel 2     , default: HostSwitch Channel 2        => HostSwitch Channel 2\n             is FN, FN sensitive, divertable, persistently divertable, pos:2, group:0, group mask:empty\n             reporting: default\n         2: Host Switch Channel 3     , default: HostSwitch Channel 3        => HostSwitch Channel 3\n             is FN, FN sensitive, divertable, persistently divertable, pos:3, group:0, group mask:empty\n             reporting: default\n         3: MultiPlatform Home/Mission Control, default: Multiplatform Home/Mission Control => Multiplatform Home/Mission Control\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty\n             reporting: default\n         4: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad, default: Multiplatform Menu/Launchpad => Multiplatform Menu/Launchpad\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:5, group:0, group mask:empty\n             reporting: default\n         5: Multiplatform Back        , default: MultiPlatform Back          => MultiPlatform Back\n             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:6, group:0, group mask:empty\n             reporting: default\n         6: Previous                  , default: Previous                    => Previous\n             is FN, FN sensitive, divertable, persistently divertable, pos:7, group:0, group mask:empty\n             reporting: default\n         7: Play/Pause                , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, divertable, persistently divertable, pos:8, group:0, group mask:empty\n             reporting: default\n         8: Next                      , default: Next                        => Next\n             is FN, FN sensitive, divertable, persistently divertable, pos:9, group:0, group mask:empty\n             reporting: default\n         9: Mute                      , default: Mute                        => Mute\n             is FN, FN sensitive, divertable, persistently divertable, pos:10, group:0, group mask:empty\n             reporting: default\n        10: Volume Down               , default: Volume Down                 => Volume Down\n             is FN, FN sensitive, divertable, persistently divertable, pos:11, group:0, group mask:empty\n             reporting: default\n        11: Volume Up                 , default: Volume Up                   => Volume Up\n             is FN, FN sensitive, divertable, persistently divertable, pos:12, group:0, group mask:empty\n             reporting: default\n        12: MultiPlatform Search      , default: Multiplatform Search        => Multiplatform Search\n             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        13: Multiplatform Insert      , default: Switch Language             => Switch Language\n             is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        14: Screen Capture/Print Screen, default: Screen Capture              => Screen Capture\n             is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        15: Multiplatform Lock        , default: WindowsLock                 => WindowsLock\n             is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Fn Up                     , default: unknown:0070                => unknown:0070\n             is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Fn Down                   , default: unknown:006F                => unknown:006F\n             is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        18: FN Key                    , default: Do Nothing One              => Do Nothing One\n             nonstandard, pos:0, group:0, group mask:empty\n             reporting: default\n     Has 10 persistent remappable keys:\n         0: MultiPlatform Home/Mission Control => Consumer: AC Home\n         1: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad => Key: COMPOSE\n         2: Multiplatform Back         => Consumer: AC Back\n         3: Previous                   => Consumer: Scan Previous Track\n         4: Play/Pause                 => Consumer: Play/Pause\n         5: Next                       => Consumer: Scan Next Track\n         6: Mute                       => Consumer: Mute\n         7: Volume Down                => Consumer: Volume Down\n         8: Volume Up                  => Consumer: Volume Up\n         9: MultiPlatform Search       => Consumer: AC Search\n     Battery: 90%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/Wireless Rechargeable Touchpad T650 4101.txt",
    "content": "  1: Wireless Rechargeable Touchpad T650\n     Codename     : T650\n     Kind         : touchpad\n     Wireless PID : 4101\n     Protocol     : HID++ 2.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: 22205A4D\n          Firmware: RQM 41.01.B0037\n        Bootloader: BL  03.00\n          Hardware: 72\n             Other:\n     The power switch is located on the base.\n     Supports 23 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: FEATURE INFO           {0002}\n         3: DEVICE FW VERSION      {0003}\n         4: DEVICE NAME            {0005}\n         5: BATTERY STATUS         {1000}\n         6: WIRELESS DEVICE STATUS {1D4B}\n         7: unknown:1DF3           {1DF3}   internal, hidden\n         8: REPROG CONTROLS        {1B00}\n         9: unknown:1F03           {1F03}   internal, hidden\n        10: VERTICAL SCROLLING     {2100}\n        11: HI RES SCROLLING       {2120}\n        12: MOUSE POINTER          {2200}\n        13: DFUCONTROL             {00C0}\n        14: unknown:1E80           {1E80}   internal, hidden\n        15: TOUCHPAD RAW XY        {6100}\n        16: unknown:1860           {1860}   internal, hidden\n        17: unknown:1E00           {1E00}   hidden\n        18: REPROG CONTROLS V2     {1B01}\n        19: unknown:1890           {1890}   internal, hidden\n        20: unknown:18E5           {18E5}   internal, hidden\n        21: unknown:18A0           {18A0}   internal, hidden\n        22: unknown:1830           {1830}   internal, hidden\n     Has 2 reprogrammable keys:\n         0: LEFT CLICK                 => LeftClick                     mse, reprogrammable\n         1: RIGHT CLICK                => RightClick                    mse, reprogrammable\n     Battery: 50%, discharging.\n"
  },
  {
    "path": "docs/devices/Wireless Solar Keyboard K750 4002.txt",
    "content": "  2: Wireless Solar Keyboard K750\n     Codename     : K750\n     Kind         : keyboard\n     Wireless PID : 4002\n     Protocol     : HID++ 2.0\n     Polling rate : 20 ms (50Hz)\n     Serial number: 5692B2EC\n          Firmware: RQK 33.00.B0015\n        Bootloader: DFU 00.02.B0003\n     The power switch is located on the edge of top right corner.\n     Supports 11 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n         3: DEVICE NAME            {0005}\n         4: REPROG CONTROLS        {1B00}\n         5: WIRELESS DEVICE STATUS {1D4B}\n         6: unknown:1DF3           {1DF3}   hidden\n         7: FN INVERSION           {40A0}\n         8: ENCRYPTION             {4100}\n         9: SOLAR DASHBOARD        {4301}\n        10: KEYBOARD LAYOUT        {4520}\n     Has 12 reprogrammable keys:\n         0: MY HOME                    => HomePage                      FN sensitive, is FN, reprogrammable\n         1: Mail                       => Email                         FN sensitive, is FN, reprogrammable\n         2: SEARCH                     => Search                        FN sensitive, is FN, reprogrammable\n         3: Calculator                 => Calculator                    FN sensitive, is FN, reprogrammable\n         4: MEDIA PLAYER               => Music                         FN sensitive, is FN, reprogrammable\n         5: Previous                   => Previous                      FN sensitive, is FN\n         6: Play/Pause                 => Play/Pause                    FN sensitive, is FN\n         7: Next                       => Next                          FN sensitive, is FN\n         8: Mute                       => Mute                          FN sensitive, is FN\n         9: Volume Down                => Volume Down                   FN sensitive, is FN\n        10: Volume Up                  => Volume Up                     FN sensitive, is FN\n        11: SLEEP                      => Sleep                         FN sensitive, is FN, reprogrammable\n     Battery status unavailable.\n"
  },
  {
    "path": "docs/devices/Wireless Touch Keyboard K400 4024.txt",
    "content": "\n  1: Wireless Touch Keyboard K400\n     Codename     : K400\n     Kind         : keyboard\n     Wireless PID : 4024\n     Protocol     : HID++ 2.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: AC5F5069\n          Firmware: RQK 50.01.B0013\n     The power switch is located on the edge of top right corner.\n     Supports 22 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: FEATURE INFO           {0002}\n         3: DEVICE FW VERSION      {0003}\n         4: DEVICE NAME            {0005}\n         5: BATTERY STATUS         {1000}\n         6: REPROG CONTROLS        {1B00}\n         7: REPROG CONTROLS V3     {1B03}\n         8: WIRELESS DEVICE STATUS {1D4B}\n         9: unknown:1DF0           {1DF0}   hidden\n        10: unknown:1DF3           {1DF3}   internal, hidden\n        11: unknown:1E00           {1E00}   hidden\n        12: VERTICAL SCROLLING     {2100}\n        13: HI RES SCROLLING       {2120}\n        14: MOUSE POINTER          {2200}\n        15: FN INVERSION           {40A0}\n        16: NEW FN INVERSION       {40A2}\n        17: ENCRYPTION             {4100}\n        18: KEYBOARD LAYOUT        {4520}\n        19: TOUCHPAD FW ITEMS      {6010}\n        20: TOUCHPAD SW ITEMS      {6011}\n        21: TOUCHPAD WIN8 FW ITEMS {6012}\n     Has 18 reprogrammable keys:\n         0: SHOW DESKTOP               => ShowDesktop                   is FN, reprogrammable\n         1: METRO APPSWITCH            => MetroAppSwitch                is FN, reprogrammable\n         2: METRO SEARCH               => MetroSearch                   is FN, reprogrammable\n         3: METRO SHARE                => MetroShare                    is FN, reprogrammable\n         4: METRO DEVICES              => MetroDevices                  is FN, reprogrammable\n         5: METRO SETTINGS             => MetroSettings                 is FN, reprogrammable\n         6: Previous                   => Previous                      is FN\n         7: Play/Pause                 => Play/Pause                    is FN\n         8: Next                       => Next                          is FN\n         9: Mute                       => Mute                          is FN\n        10: Volume Down                => Volume Down                   is FN\n        11: Volume Up                  => Volume Up                     is FN\n        12: MEDIA PLAYER               => Music                         nonstandard, reprogrammable\n        13: Lock PC                    => WindowsLock                   nonstandard, reprogrammable\n        14: SLEEP                      => Sleep                         nonstandard, reprogrammable\n        15: LEFT CLICK                 => LeftClick                     mse\n        16: LEFT CLICK                 => LeftClick                     mse\n        17: RIGHT CLICK                => RightClick                    mse\n     Battery: 90%, discharging.\n"
  },
  {
    "path": "docs/devices/Wireless Touch Keyboard K400 Plus 404D.txt",
    "content": "Solaar version 1.1.4\n\n  1: Wireless Touch Keyboard K400 Plus\n     Device path  : /dev/hidraw2\n     WPID         : 404D\n     Codename     : K400 Plus\n     Kind         : keyboard\n     Protocol     : HID++ 4.1\n     Polling rate : 8 ms (125Hz)\n     Serial number: 6DC5C81C\n     Model ID:      404D00000000\n     Unit ID:       641487CF\n        Bootloader: BOT 22.02.B0002\n          Firmware: RQK 63.02.B0016\n             Other:\n     The power switch is located on the top edge.\n     Supports 23 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: DEVICE FW VERSION      {0003}\n            Firmware: Bootloader BOT 22.02.B0002 404D6217AD40\n            Firmware: Firmware RQK 63.02.B0016 404D6217AD40\n            Firmware: Other\n            Unit ID: 641487CF  Model ID: 404D00000000  Transport IDs: {'wpid': '404D'}\n         3: DEVICE NAME            {0005}\n            Name: Wireless Touch Keyboard K400 Plus\n            Kind: keyboard\n         4: WIRELESS DEVICE STATUS {1D4B}\n         5: RESET                  {0020}\n         6: BATTERY STATUS         {1000}\n            Battery: 90%, discharging, next level 50%.\n         7: REPROG CONTROLS V4     {1B04}\n            Key/Button Diversion (saved): {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Application Switcher:Regular, My Home:Regular, Media Player:Regular, Search:Regular, Sleep:Regular, Contextual Menu:Regular, Back:Regular, Show Desktop:Regular, Maximize Window:Regular, Switch Screen:Regular, Fn Left Click:Regular, Second Left Click:Regular}\n            Key/Button Diversion        : {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Application Switcher:Regular, My Home:Regular, Media Player:Regular, Search:Regular, Sleep:Regular, Contextual Menu:Regular, Back:Regular, Show Desktop:Regular, Maximize Window:Regular, Switch Screen:Regular, Fn Left Click:Regular, Second Left Click:Regular}\n         8: SWAP BUTTON CANCEL     {2005}\n         9: NEW FN INVERSION       {40A2}\n            Fn-swap: enabled\n            Fn-swap default: enabled\n            Swap Fx function (saved): True\n            Swap Fx function        : True\n        10: ENCRYPTION             {4100}\n        11: KEYBOARD DISABLE KEYS  {4521}\n            Disable keys (saved): {Caps Lock:False, Scroll Lock:False, Insert:False, Win:False}\n            Disable keys        : {Caps Lock:False, Scroll Lock:False, Insert:False, Win:False}\n        12: TOUCHPAD RAW XY        {6100}\n        13: GESTURE 2              {6501}\n            Gestures (saved): {1: True, 2: True, 10: True, 30: True, 34: False, 42: True, 43: True, 45: False, 64: False, 65: False, 67: False, 84: True}\n            Gestures        : {1: True, 2: True, 30: True, 10: True, 45: False, 42: True, 43: True, 64: False, 65: False, 67: False, 84: True, 34: False}\n            Gestures Diversion (saved): {1: False, 2: False, 10: False, 44: False, 64: False, 65: False, 67: False, 84: False, 85: False, 100: False}\n            Gestures Diversion        : {1: False, 2: False, 10: False, 44: False, 64: False, 65: False, 67: False, 84: False, 85: False, 100: False}\n            Gesture params (saved): {4: {'scale': 256}}\n            Gesture params        : {4: {'scale': 256}}\n        14: DFUCONTROL UNSIGNED    {00C1}\n        15: unknown:1811           {1811}   internal, hidden\n        16: unknown:1830           {1830}   internal, hidden\n        17: unknown:1890           {1890}   internal, hidden\n        18: unknown:1DF3           {1DF3}   internal, hidden\n        19: unknown:1E00           {1E00}   hidden\n        20: unknown:1EB0           {1EB0}   internal, hidden\n        21: unknown:1861           {1861}   internal, hidden\n        22: unknown:18B0           {18B0}   internal, hidden\n     Has 20 reprogrammable keys:\n         0: Second Left Click         , default: Left Click                  => Left Click\n             mse, divertable, pos:0, group:0, group mask:empty\n             reporting: default\n         1: Back                      , default: Mouse Back Button           => Mouse Back Button\n             is FN, FN sensitive, reprogrammable, divertable, pos:1, group:0, group mask:empty\n             reporting: default\n         2: My Home                   , default: HomePage                    => HomePage\n             is FN, FN sensitive, reprogrammable, divertable, pos:2, group:0, group mask:empty\n             reporting: default\n         3: Application Switcher      , default: Application Switcher        => Application Switcher\n             is FN, FN sensitive, reprogrammable, divertable, pos:3, group:0, group mask:empty\n             reporting: default\n         4: Contextual Menu           , default: Right Click                 => Right Click\n             is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, group mask:empty\n             reporting: default\n         5: Search                    , default: Search Files                => Search Files\n             is FN, FN sensitive, reprogrammable, divertable, pos:5, group:0, group mask:empty\n             reporting: default\n         6: Show Desktop              , default: Show Desktop                => Show Desktop\n             is FN, FN sensitive, reprogrammable, divertable, pos:6, group:0, group mask:empty\n             reporting: default\n         7: Maximize Window           , default: Maximize Window             => Maximize Window\n             is FN, FN sensitive, reprogrammable, divertable, pos:7, group:0, group mask:empty\n             reporting: default\n         8: Switch Screen             , default: Switch Presentation/Switch Screen => Switch Presentation/Switch Screen\n             is FN, FN sensitive, reprogrammable, divertable, pos:8, group:0, group mask:empty\n             reporting: default\n         9: Media Player              , default: Music                       => Music\n             is FN, FN sensitive, reprogrammable, divertable, pos:9, group:0, group mask:empty\n             reporting: default\n        10: Previous                  , default: Previous                    => Previous\n             is FN, FN sensitive, divertable, pos:10, group:0, group mask:empty\n             reporting: default\n        11: Play/Pause                , default: Play/Pause                  => Play/Pause\n             is FN, FN sensitive, divertable, pos:11, group:0, group mask:empty\n             reporting: default\n        12: Next                      , default: Next                        => Next\n             is FN, FN sensitive, divertable, pos:12, group:0, group mask:empty\n             reporting: default\n        13: Fn Left Click             , default: ShowUI                      => ShowUI\n             divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        14: Left Button               , default: Left Click                  => Left Click\n             mse, pos:0, group:0, group mask:empty\n             reporting: default\n        15: Right Button              , default: Right Click                 => Right Click\n             mse, pos:0, group:0, group mask:empty\n             reporting: default\n        16: Mute                      , default: Mute                        => Mute\n             nonstandard, divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        17: Volume Up                 , default: Volume Up                   => Volume Up\n             nonstandard, divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        18: Volume Down               , default: Volume Down                 => Volume Down\n             nonstandard, divertable, pos:0, group:0, group mask:empty\n             reporting: default\n        19: Sleep                     , default: Sleep                       => Sleep\n             reprogrammable, divertable, pos:0, group:0, group mask:empty\n             reporting: default\n     Has 17 gesture(s), 1 param(s) and 5 spec(s):\n        Track1Finger               Enabled(None): None   Diverted:(None) None\n        TapGestures                Enabled(None): None   Diverted:(None) None\n        Tap1Finger                 Enabled(   0): True   Diverted:(   0) False\n        Tap2Finger                 Enabled(   1): True   Diverted:(   1) False\n        TapDrag1Finger             Enabled(   2): True   Diverted:(None) None\n        DoubleTap1Finger           Enabled(   3): True   Diverted:(   2) False\n        Scroll2FingerStateless     Enabled(None): None   Diverted:(   3) False\n        NaturalScrolling           Enabled(   4): False  Diverted:(None) None\n        Scroll2FingerHoriz         Enabled(   5): True   Diverted:(None) None\n        Scroll2FingerVert          Enabled(   6): True   Diverted:(None) None\n        LeftEdgeSwipe1Finger2      Enabled(   7): False  Diverted:(   4) False\n        RightEdgeSwipe1Finger2     Enabled(   8): False  Diverted:(   5) False\n        TopEdgeSwipe1Finger2       Enabled(   9): False  Diverted:(   6) False\n        Zoom2FingerStateless       Enabled(  10): True   Diverted:(   7) False\n        FnClickGestureSuppression  Enabled(  11): False  Diverted:(None) None\n        TwoFingersPresent          Enabled(None): None   Diverted:(   8) False\n        DeviceSpecificRawData      Enabled(None): None   Diverted:(   9) False\n        ScaleFactor                Value  (   0): 256 [Default: 256]\n        period unit                Spec   (   3): 2048\n        DVI field width            Spec   (   1): 8\n        field widths               Spec   (   2): 8\n        multiplier                 Spec   (   5): None\n        resolution                 Spec   (   4): 4\n     Battery: 90%, discharging, next level 50%.\n"
  },
  {
    "path": "docs/devices/Wireless Trackball M570 1028.txt",
    "content": "  1: Wireless Trackball M570\n     Codename     : M570\n     Kind         : mouse\n     Wireless PID : 1028\n     Protocol     : HID++ 1.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: 891DC05A\n          Firmware: 26.00.B0003\n        Bootloader: 02.06\n             Other: 00.01\n     The power switch is located on the base.\n     Notifications: battery status (0x100000).\n     Battery: 100%, discharging.\n"
  },
  {
    "path": "docs/devices/Zone Touch Mouse T400 4026.txt",
    "content": "  1: Zone Touch Mouse T400\n     Codename     : T400\n     Kind         : mouse\n     Wireless PID : 4026\n     Protocol     : HID++ 2.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: 131A3093\n          Firmware: RQM 39.00.B0029\n        Bootloader: BL  03.00\n          Hardware: 72\n             Other:\n     The power switch is located on the base.\n     Supports 28 HID++ 2.0 features:\n         0: ROOT                   {0000}\n         1: FEATURE SET            {0001}\n         2: FEATURE INFO           {0002}\n         3: DEVICE FW VERSION      {0003}\n         4: DEVICE NAME            {0005}\n         5: DFUCONTROL             {00C0}\n         6: BATTERY STATUS         {1000}\n         7: unknown:1802           {1802}   internal, hidden\n         8: unknown:1810           {1810}   internal, hidden\n         9: unknown:1830           {1830}   internal, hidden\n        10: unknown:1850           {1850}   internal, hidden\n        11: unknown:1860           {1860}   internal, hidden\n        12: unknown:1890           {1890}   internal, hidden\n        13: unknown:18A0           {18A0}   internal, hidden\n        14: unknown:18E3           {18E3}   internal, hidden\n        15: REPROG CONTROLS        {1B00}\n        16: WIRELESS DEVICE STATUS {1D4B}\n        17: unknown:1DF3           {1DF3}   internal, hidden\n        18: unknown:1E00           {1E00}   hidden\n        19: unknown:1E80           {1E80}   internal, hidden\n        20: unknown:1F03           {1F03}   internal, hidden\n        21: unknown:1F04           {1F04}   internal, hidden\n        22: VERTICAL SCROLLING     {2100}\n        23: unknown:2101           {2101}   hidden\n        24: HI RES SCROLLING       {2120}\n        25: MOUSE POINTER          {2200}\n        26: TOUCHMOUSE RAW POINTS  {6110}   hidden\n        27: REPROG CONTROLS V3     {1B03}\n     Has 7 reprogrammable keys:\n         0: LEFT CLICK                 => LeftClick                     mse, reprogrammable\n         1: RIGHT CLICK                => RightClick                    mse, reprogrammable\n         2: MIDDLE BUTTON              => MiddleMouseButton             mse, reprogrammable\n         3: METRO START SCREEN         => MetroStartScreen              mse, reprogrammable\n         4: ZOOMIN                     => Do Nothing                    mse, reprogrammable\n         5: ZOOMOUT                    => Do Nothing                    mse, reprogrammable\n         6: BACK HSCROLL               => TouchBackForwardHorzScroll\n     Battery: 100%, discharging.\n"
  },
  {
    "path": "docs/devices/anywhere-mx.txt",
    "content": "Receiver\nLZ301AR-DJ\nM/N:C-U0007\n(ltunify)\nSerial number: D1759614\nFirmware version: 012.001.00019\nBootloader version: BL.002.014\n\nSupported notification flags: 00 09 00\n- 01: Wireless Notifications\n- 08: Software Present\n\nMouse\n(ltunify)\nHID++ version: 1.0\nDevice index 1\nMouse\nName: Anywhere MX\nWireless Product ID: 1017\nSerial number: 13865F99\nFirmware version: 016.001.00040\nBootloader version: BL.002.010\n(solaar)\nUnifying Receiver\n  Device path  : /dev/hidraw2\n  USB id       : 046d:c52b\n  Serial       : D1759614\n    Firmware   : 12.01.B0019\n    Bootloader : 02.14\n  Has 1 paired device(s) out of a maximum of 6.\n  Notifications: (none)\n  Device activity counters: 1=19\n\n  1: Anywhere Mouse MX\n     Codename     : Anywhere MX\n     Kind         : mouse\n     Wireless PID : 1017\n     Protocol     : HID++ 1.0\n     Polling rate : 8 ms (125Hz)\n     Serial number: 13865F99\n          Firmware: 16.01.B0040\n        Bootloader: 02.10\n             Other: 00.06\n     The power switch is located on the base.\n     Notifications: (none).\n     Battery: 100%, discharging.\n\n(scan-registers)\n# Old notification flags: 000000\n# 00 - Enabled Notifications, supported flags: Battery Status (10)\n>> (   0.792) [10 01 8100 100000] b'\\x10\\x01\\x81\\x00\\x10\\x00\\x00'\n\n# 01 - scrolling settings?\n# Flags:\n# 0x40 - Enable Smooth Scrolling\n# 0x02 - \"confuse KDE\", see https://github.com/pwr/Solaar/issues/115\n<< (   0.011) [10 01 8101 000000] b'\\x10\\x01\\x81\\x01\\x00\\x00\\x00'\n>> (   1.710) [10 01 8101 020000] b'\\x10\\x01\\x81\\x01\\x02\\x00\\x00'\n\n# 0D - battery level. first byte is remaining charge in percent; second is\n# (guessed) maximum?; third is charge status (30=discharging)\n# \"10 ix 0D  64 64 30  00\" is a battery notification (when enabled)\n<< (   9.789) [10 01 810D 000000] b'\\x10\\x01\\x81\\r\\x00\\x00\\x00'\n>> (   9.816) [10 01 810D 646430] b'\\x10\\x01\\x81\\rdd0'\n\n# 63 - DPI (range 0x80-0x8e (inclusive))\n<< (  75.521) [10 01 8163 000000] b'\\x10\\x01\\x81c\\x00\\x00\\x00'\n>> (  75.550) [10 01 8163 890000] b'\\x10\\x01\\x81c\\x89\\x00\\x00'\n\n# D0 - ?\n<< ( 163.118) [10 01 81D0 000000] b'\\x10\\x01\\x81\\xd0\\x00\\x00\\x00'\n>> ( 163.148) [10 01 81D0 000000] b'\\x10\\x01\\x81\\xd0\\x00\\x00\\x00'\n\n# D4 - ?\n<< ( 166.034) [10 01 81D4 000000] b'\\x10\\x01\\x81\\xd4\\x00\\x00\\x00'\n>> ( 166.063) [10 01 81D4 000008] b'\\x10\\x01\\x81\\xd4\\x00\\x00\\x08'\n\n# F1 - firmware/bootloader version\n<< ( 187.172) [10 01 81F1 000000] b'\\x10\\x01\\x81\\xf1\\x00\\x00\\x00'\n>> ( 187.199) [10 01 8F81 F10300] b'\\x10\\x01\\x8f\\x81\\xf1\\x03\\x00'\n\n# F3 - ?\n<< ( 188.629) [10 01 81F3 000000] b'\\x10\\x01\\x81\\xf3\\x00\\x00\\x00'\n>> ( 188.661) [10 01 81F3 000000] b'\\x10\\x01\\x81\\xf3\\x00\\x00\\x00'\n\n# FD - ?\n<< ( 195.715) [10 01 83FD 000000] b'\\x10\\x01\\x83\\xfd\\x00\\x00\\x00'\n>> ( 195.746) [11 01 83FD 00000000000000000000000000000000] b'\\x11\\x01\\x83\\xfd\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n"
  },
  {
    "path": "docs/devices/mk700.txt",
    "content": "# Enabled Notifications\n# 10 - battery status\n# 02 + 01 - remap FN keys (multimedia + power buttons)\n>> (   1.412) [10 02 8100 130000] '\\x10\\x02\\x81\\x00\\x13\\x00\\x00'\n<< (   0.011) [10 02 8101 000000] '\\x10\\x02\\x81\\x01\\x00\\x00\\x00'\n>> (   0.276) [10 02 8101 000000] '\\x10\\x02\\x81\\x01\\x00\\x00\\x00'\n\n# Battery status\n<< (   6.033) [10 02 8107 000000] '\\x10\\x02\\x81\\x07\\x00\\x00\\x00'\n>> (   6.344) [10 02 8107 070000] '\\x10\\x02\\x81\\x07\\x07\\x00\\x00'\n\n# FN status\n<< (   8.055) [10 02 8109 000000] '\\x10\\x02\\x81\\t\\x00\\x00\\x00'\n>> (   8.144) [10 02 8109 000000] '\\x10\\x02\\x81\\t\\x00\\x00\\x00'\n\n# ?\n<< ( 208.316) [10 02 81D0 000000] '\\x10\\x02\\x81\\xd0\\x00\\x00\\x00'\n>> ( 208.353) [10 02 81D0 000000] '\\x10\\x02\\x81\\xd0\\x00\\x00\\x00'\n\n# version info\n<< ( 237.436) [10 02 81F1 000000] '\\x10\\x02\\x81\\xf1\\x00\\x00\\x00'\n>> ( 237.744) [10 02 8F81 F10300] '\\x10\\x02\\x8f\\x81\\xf1\\x03\\x00'\n\n# ?\n<< ( 239.459) [10 02 81F3 000000] '\\x10\\x02\\x81\\xf3\\x00\\x00\\x00'\n>> ( 239.766) [10 02 81F3 000000] '\\x10\\x02\\x81\\xf3\\x00\\x00\\x00'\n"
  },
  {
    "path": "docs/devices/performance-mx.txt",
    "content": "# Notifications (r1_bit0 = battery status?)\n<< (   0.113) [10 01 8100 000000] '\\x10\\x01\\x81\\x00\\x00\\x00\\x00'\n>> (   0.157) [10 01 8100 100000] '\\x10\\x01\\x81\\x00\\x10\\x00\\x00'\n\n# ?\n<< (   1.050) [10 01 8101 000000] '\\x10\\x01\\x81\\x01\\x00\\x00\\x00'\n>> (   1.097) [10 01 8101 020000] '\\x10\\x01\\x81\\x01\\x02\\x00\\x00'\n\n# battery (07 means full)\n<< (   7.335) [10 01 8107 000000] '\\x10\\x01\\x81\\x07\\x00\\x00\\x00'\n>> (   7.382) [10 01 8107 070000] '\\x10\\x01\\x81\\x07\\x07\\x00\\x00'\n\n# Set LEDS - ab cd 00, where a/b/c/d values are 1=off, 2=on, 3=flash\n#   a = lower led\n#   b = red led\n#   c = upper led\n#   d = middle led\n# below: all leds are off\n<< (  86.592) [10 01 8151 000000] '\\x10\\x01\\x81Q\\x00\\x00\\x00'\n>> (  86.639) [10 01 8151 111100] '\\x10\\x01\\x81Q\\x11\\x11\\x00'\n\n# DPI (values in range 0x81..0x8F; logical value: 100..1500)\n<< ( 108.430) [10 01 8163 000000] '\\x10\\x01\\x81c\\x00\\x00\\x00'\n>> ( 108.477) [10 01 8163 890000] '\\x10\\x01\\x81c\\x89\\x00\\x00'\n\n# ?\n<< ( 240.505) [10 01 81D0 000000] '\\x10\\x01\\x81\\xd0\\x00\\x00\\x00'\n>> ( 240.550) [10 01 81D0 000000] '\\x10\\x01\\x81\\xd0\\x00\\x00\\x00'\n\n# ?\n<< ( 245.690) [10 01 81D4 000000] '\\x10\\x01\\x81\\xd4\\x00\\x00\\x00'\n>> ( 245.737) [10 01 81D4 000012] '\\x10\\x01\\x81\\xd4\\x00\\x00\\x12'\n\n# Firmware/bootloader version\n<< ( 281.016) [10 01 81F1 000000] '\\x10\\x01\\x81\\xf1\\x00\\x00\\x00'\n>> ( 282.177) [10 01 8F81 F10300] '\\x10\\x01\\x8f\\x81\\xf1\\x03\\x00'\n\n# ?\n<< ( 284.106) [10 01 81F3 000000] '\\x10\\x01\\x81\\xf3\\x00\\x00\\x00'\n>> ( 284.153) [10 01 81F3 000000] '\\x10\\x01\\x81\\xf3\\x00\\x00\\x00'\n"
  },
  {
    "path": "docs/devices.md",
    "content": "---\ntitle: Supported Devices\nlayout: page\n---\n\n# Supported receivers and devices\n\nSolaar only supports Logitech receivers and devices that use the Logitech proprietary HID++ protocol.\n\nSolaar supports most Logitech Nano, Unifying, and Bolt receivers.\nSolaar supports some Lightspeed receivers.\nSee the receiver table below for the list of currently supported receivers.\n\nSolaar supports all Logitech devices (keyboards, mice, trackballs, touchpads, and headsets)\nthat can connect to supported receivers.\nSolaar supports all Logitech devices that can connect via a USB cable or via Bluetooth,\nas long as the device uses the HID++ protocol.\n\nThe best way to determine whether Solaar supports a device is to run Solaar while the device is connected.\nIf the device is supported, it will show up in the Solaar main window.\n\nThe directory <https://github.com/pwr-Solaar/Solaar/tree/master/docs/devices> contains edited output\nof `solaar show` on many devices and can be used to see what Solaar can do with the device.\n\n\n## Supporting old devices\n\nSome old Logitech devices use an old version of HID++.\nFor Solaar to support these devices well, Solaar needs some information about them.\n\nIf you have an old Logitech device that shows up in Solaar but has no settings\nand you feel that Solaar should be able to do more with the device you can\nopen an enhancement request for Solaar to better support the device.\n\n\n## Adding new receivers\n\nAdding a new receiver requires knowing whether the receiver is a regular\nUnifying receiver, a Nano receiver, a Bolt receiver, or a Lightspeed receiver.\nThis can generally be found using `lsusb`.\n\nTo add a new receiver to the Solaar code\nadd a line to `../lib/logitech_receiver/base_usb.py` defining the receiver as one of these.\nIf the receiver has an unusual number of pairing slots, then this also needs\nto be specified. Then add the receiver to the tuple of receivers (ALL).\n\n### Supported Receivers\n\n| USB ID    | Kind       | Max Paired Devices |\n------------|------------|--------------------|\n| 046d:c517 | 27MHz      | 4                  |\n| 046d:c518 | Nano       | 1                  |\n| 046d:c51a | Nano       | 1                  |\n| 046d:c51b | Nano       | 1                  |\n| 046d:c521 | Nano       | 1                  |\n| 046d:c525 | Nano       | 1                  |\n| 046d:c526 | Nano       | 1                  |\n| 046d:c52b | Unifying   | 6                  |\n| 046d:c52e | Nano       | 1                  |\n| 046d:c52f | Nano       | 1                  |\n| 046d:c531 | Nano       | 1                  |\n| 046d:c532 | Unifying   | 6                  |\n| 046d:c534 | Nano       | 2                  |\n| 046d:c537 | Nano       | 2                  |\n| 046d:c539 | Lightspeed | 1                  |\n| 046d:c53a | Lightspeed | 1                  |\n| 046d:c53d | Lightspeed | 1                  |\n| 046d:c53f | Lightspeed | 1                  |\n| 046d:c541 | Lightspeed | 1                  |\n| 046d:c542 | Nano       | 1                  |\n| 046d:c545 | Lightspeed | 1                  |\n| 046d:c547 | Lightspeed | 1                  |\n| 046d:c548 | Bolt       | 6                  |\n| 17ef:6042 | Nano       | 1                  |\n\nSome Nano receivers are only partly supported\nas they do not implement the full HID++ 1.0 protocol.\nSome Nano receivers are not supported as they do not implement the HID++ protocol at all.\nReceivers with USB ID 046d:c542 fall into this category.\n\nThe receiver with USB ID 046d:c517 is an old 27 MHz receiver, supporting only\na subset of the HID++ 1.0 protocol. Only hardware pairing is supported.\n\n\n\n## Supported Devices (Historical Interest Only)\n\nThe device tables below  provide a list of some of the devices that Solaar supports,\ngiving their product name, WPID product number, and HID++ protocol information.\nThe tables concentrate on older devices that have explicit support information in Solaar\nand are not being updated for new devices that are supported by Solaar.\n\nNote that Logitech has the annoying habit of reusing Device names (e.g., M185)\nso what is important for support is the USB WPID or Bluetooth model ID.\n\n### Keyboards (Unifying)\n\n| Device           | WPID | HID++ |\n|------------------|------|-------|\n| K230             | 400D | 2.0   |\n| K270             | 4003 | 2.0   |\n| K340             | 2007 | 1.0   |\n| K350             | 200A | 1.0   |\n| K360             | 4004 | 2.0   |\n| K375s            | 4071 |       |\n| K400 Touch       | 400E | 2.0   |\n| K400 Touch       | 4024 | 2.0   |\n| K400 Plus        | 404D | 2.0   |\n| K520             | 2011 | 1.0   |\n| K600 TV          | 4078 | 2.0   |\n| K750 Solar       | 4002 | 2.0   |\n| K780             | 405B | 2.0   |\n| K800 Illuminated | 2010 | 1.0   |\n| K800 (new ver)   | 406E | 2.0   |\n| K830 Illuminated | 4032 | 2.0   |\n| MX Keys          | 408A | 2.0   |\n| N545             | 2006 |       |\n| TK820            |      | 2.0   |\n| Craft            | 4066 | 2.0   |\n\n\n### Keyboards (Lightspeed)\n\n| Device           | WPID | HID++ |\n|------------------|------|-------|\n| G915 TKL         | 408E | 4.2   |\n\n### Mice (Unifying)\n\n| Device           | WPID | HID++ |\n|------------------|------|-------|\n| M150             | 4022 | 2.0   |\n| M185             | 4055 | 2.0   |\n| M310             | 4031 | 2.0   |\n| M310             | 4055 | 2.0   |\n| M317             |      |       |\n| M325             | 400A | 2.0   |\n| M330             |      | 2.0   |\n| M345             | 4017 | 2.0   |\n| M350             | 101C | 1.0   |\n| M350             | 4080 | 2.0   |\n| M505             | 101D | 1.0   |\n| M510             | 1025 | 1.0   |\n| M510             | 4051 | 2.0   |\n| M515 Couch       | 4007 | 2.0   |\n| M525             | 4013 | 2.0   |\n| M560             |      | 2.0   |\n| M585             | 406B | 2.0   |\n| M590             | 406B | 2.0   |\n| M600 Touch       | 401A | 2.0   |\n| M705 Marathon    | 101B | 1.0   |\n| M705 Marathon    | 406D | 2.0   |\n| M720 Triathlon   | 405E | 2.0   |\n| T400 Zone Touch  |      | 2.0   |\n| T620 Touch       |      | 2.0   |\n| Performance MX   | 101A | 1.0   |\n| Anywhere MX      | 1017 | 1.0   |\n| Anywhere MX 2    | 404A | 2.0   |\n| MX Master        | 4041 | 2.0   |\n| MX Master 2S     | 4069 | 2.0   |\n| Cube             |      | 2.0   |\n| MX Vertical      | 407B | 2.0   |\n\n### Mice (Nano)\n\n| Device           | WPID | HID++ |\n|------------------|------|-------|\n| G7               | 1002 | 1.0   |\n| G700             | 1023 | 1.0   |\n| G700s            | 102A | 1.0   |\n| V450 Nano        | 1011 | 1.0   |\n| V550 Nano        | 1013 | 1.0   |\n| VX Nano          | 100B | 1.0   |\n| VX Nano          | 100F | 1.0   |\n| M175             | 4008 |       |\n| M185 (old)       | 4038 | 2.0   |\n| M185 (new)       | 4054 | 2.0   |\n| M187             | 4019 | 2.0   |\n| M215             | 1020 | 1.0   |\n| M235             | 4055 | 2.0   |\n| M305             | 101F | 1.0   |\n| M310             | 1024 | 1.0   |\n| M315             |      |       |\n| M330             |      | ?.?   |\n| MX 1100          | 1014 | 1.0   |\n\n* (old): M185 with P/N: 810-003496\n* (new): M185 with P/N: 810-005238 or 810-005232\n\n### Mice (Mini)\n\n| Device            | WPID | HID++ |\n|-------------------|------|-------|\n| MX610             | 1001 | 1.0   |\n| MX610 left handed | 1004 | 1.0   |\n| MX620             | 100A | 1.0   |\n| MX620             | 1016 | 1.0   |\n| V400              | 1003 | 1.0   |\n| V450              | 1005 | 1.0   |\n| VX Revolution     | 1006 | 1.0   |\n| VX Revolution     | 100D | 1.0   |\n| MX Air            | 1007 | 1.0   |\n| MX Air            | 100E | 1.0   |\n| MX Revolution     | 1008 | 1.0   |\n| MX Revolution     | 100C | 1.0   |\n\n\n### Mice (Lightspeed)\n\n| Device                       | WPID | HID++ |\n|------------------------------|------|-------|\n| G604 Wireless Gaming Mouse   | 4085 | 4.2   |\n| PRO X Superlight Wireless    | 4093 | 4.2   |\n\n### Trackballs (Unifying)\n\n| Device            | WPID | HID++ |\n|-------------------|------|-------|\n| M570 Trackball    |      | 1.0   |\n| MX Ergo Trackball |      | 2.0   |\n\n### Touchpads (Unifying)\n\n| Device           | WPID | HID++ |\n|------------------|------|-------|\n| Wireless Touch   | 4011 | 2.0   |\n| T650 Touchpad    | 4101 | 2.0   |\n\n### Mice and Keyboards sold as combos\n\n| Device           | WPID | HID++ |\n|------------------|------|-------|\n| MK220            |      | 2.0   |\n| MK270            | 4023 | 2.0   |\n| MK320            | 200F |       |\n| MK330            |      |       |\n| MK345            | 4023 | 2.0   |\n| MK520            |      | M2/K1 |\n| MK550            |      |       |\n| MK700            | 2008 | 1.0   |\n| MK710            |      | 1.0   |\n| EX100 keyboard   | 0065 | 1.0   |\n| EX100 mouse      | 003f | 1.0   |\n\n* The EX100 is an old, pre-Unifying receiver and device set, supporting only some HID++ 1.0 features\n"
  },
  {
    "path": "docs/features.md",
    "content": "---\ntitle: List of HID++ 2.0 features\nlayout: page\n---\n\n# List of HID++ 2.0 features\n\n## Feature status\n\nSee functions in `hidpp20.py` and `settings_templates.py`\n\nFeature                                | ID       | Status             | Notes\n---------------------------------------|----------|:------------------:|------\n`ROOT`                                 | `0x0000` | Supported          | System\n`FEATURE_SET`                          | `0x0001` | Supported          | System\n`FEATURE_INFO`                         | `0x0002` | Supported          | System\n`DEVICE_FW_VERSION`                    | `0x0003` | Supported          | `get_firmware`, `get_ids`, read only\n`DEVICE_UNIT_ID`                       | `0x0004` | Unsupported        |\n`DEVICE_NAME`                          | `0x0005` | Supported          | `get_kind`, `get_name`, read only\n`DEVICE_GROUPS`                        | `0x0006` | Unsupported        |\n`DEVICE_FRIENDLY_NAME`                 | `0x0007` | Supported          | `get_friendly_name`, read only\n`KEEP_ALIVE`                           | `0x0008` | Unsupported        |\n`RESET`                                | `0x0020` | Unsupported        | aka “Config Change”\n`CRYPTO_ID`                            | `0x0021` | Unsupported        |\n`TARGET_SOFTWARE`                      | `0x0030` | Unsupported        |\n`WIRELESS_SIGNAL_STRENGTH`             | `0x0080` | Unsupported        |\n`DFUCONTROL_LEGACY`                    | `0x00C0` | Unsupported        |\n`DFUCONTROL_UNSIGNED`                  | `0x00C1` | Unsupported        |\n`DFUCONTROL_SIGNED`                    | `0x00C2` | Unsupported        |\n`DFU`                                  | `0x00D0` | Unsupported        |\n`BATTERY_STATUS`                       | `0x1000` | Supported          | `get_battery`, read only\n`BATTERY_VOLTAGE`                      | `0x1001` | Supported          | `get_voltage`, read only\n`UNIFIED_BATTERY`\t\t       | `0x1004` | Supported          | `get_battery`, read only\n`CHARGING_CONTROL`                     | `0x1010` | Unsupported        |\n`LED_CONTROL`                          | `0x1300` | Unsupported        |\n`GENERIC_TEST`                         | `0x1800` | Unsupported        |\n`DEVICE_RESET`                         | `0x1802` | Unsupported        |\n`OOBSTATE`                             | `0x1805` | Unsupported        |\n`CONFIG_DEVICE_PROPS`                  | `0x1806` | Unsupported        |\n`CHANGE_HOST`                          | `0x1814` | Supported          | `ChangeHost`\n`HOSTS_INFO`                           | `0x1815` | Partial Support    | `get_host_names`, partial listing only\n`BACKLIGHT`                            | `0x1981` | Supported          | `Backlight`\n`BACKLIGHT2`                           | `0x1982` | Supported          | `Backlight2`, ...\n`BACKLIGHT3`                           | `0x1983` | Unsupported        |\n`PRESENTER_CONTROL`                    | `0x1A00` | Unsupported        |\n`SENSOR_3D`                            | `0x1A01` | Unsupported        |\n`REPROG_CONTROLS`                      | `0x1B00` | Unsupported        |\n`REPROG_CONTROLS_V2`                   | `0x1B01` | Listing Only       | `get_keys`\n`REPROG_CONTROLS_V2_2`                 | `0x1B02` | Unsupported        |\n`REPROG_CONTROLS_V3`                   | `0x1B03` | Unsupported        |\n`REPROG_CONTROLS_V4`                   | `0x1B04` | Partial Support    | `ReprogrammableKeys`, `DivertKeys`, `MouseGesture`, `get_keys`\n`REPORT_HID_USAGE`                     | `0x1BC0` | Unsupported        |\n`PERSISTENT_REMAPPABLE_ACTION`         | `0x1C00` | Supported          | `PersistentRemappableAction`\n`WIRELESS_DEVICE_STATUS`               | `0x1D4B` | Read only          | status reporting from device\n`REMAINING_PAIRING`                    | `0x1DF0` | Unsupported        |\n`FIRMWARE_PROPERTIES`                  | `0x1F1F` | Unsupported        |\n`ADC_MEASUREMENT`                      | `0x1F20` | Supported          | `ADCPower`\n`LEFT_RIGHT_SWAP`                      | `0x2001` | Unsupported        |\n`SWAP_BUTTON_CANCEL`                   | `0x2005` | Unsupported        |\n`POINTER_AXIS_ORIENTATION`             | `0x2006` | Unsupported        |\n`VERTICAL_SCROLLING`                   | `0x2100` | Supported          | `get_vertical_scrolling_info`, read only\n`SMART_SHIFT`                          | `0x2110` | Supported          | `SmartShift`\n`SMART_SHIFT_ENHANCED` \t\t       | `0x2111` | Supported          | `SmartShiftEnhanced`\n`HI_RES_SCROLLING`                     | `0x2120` | Supported          | `HiResScroll`, `get_hi_res_scrolling_info`\n`HIRES_WHEEL`                          | `0x2121` | Supported          | `HiresSmoothInvert`, `HiresSmoothResolution`, `get_hires_wheel`\n`LOWRES_WHEEL`                         | `0x2130` | Supported          | `LowresSmoothScroll`, `get_lowres_wheel_status`\n`THUMB_WHEEL`                          | `0x2150` | Supported          | `ThumbMode`, `ThumbInvert`\n`MOUSE_POINTER`                        | `0x2200` | Supported          | `get_mouse_pointer_info`, read only\n`ADJUSTABLE_DPI`                       | `0x2201` | Supported          | `AdjustableDpi`, `DpiSliding`\n`POINTER_SPEED`                        | `0x2205` | Supported          | `PointerSpeed`, `SpeedChange`, `get_pointer_speed_info`\n`ANGLE_SNAPPING`                       | `0x2230` | Unsupported        |\n`SURFACE_TUNING`                       | `0x2240` | Unsupported        |\n`HYBRID_TRACKING`                      | `0x2400` | Unsupported        |\n`FN_INVERSION`                         | `0x40A0` | Supported          | `FnSwap`\n`NEW_FN_INVERSION`                     | `0x40A2` | Supported          | `NewFnSwap`, `get_new_fn_inversion\n`K375S_FN_INVERSION`                   | `0x40A3` | Supported          | `K375sFnSwap`\n`ENCRYPTION`                           | `0x4100` | Unsupported        |\n`LOCK_KEY_STATE`                       | `0x4220` | Unsupported        |\n`SOLAR_DASHBOARD`                      | `0x4301` | Unsupported        |\n`KEYBOARD_LAYOUT`                      | `0x4520` | Unsupported        | read only\n`KEYBOARD_DISABLE_KEYS`                | `0x4521` | Supported          | `DisableKeyboardKeys`\n`KEYBOARD_DISABLE_BY_USAGE`            | `0x4522` | Unsupported        |\n`DUALPLATFORM`                         | `0x4530` | Supported          | `Dualplatform`, untested\n`MULTIPLATFORM`                        | `0x4531` | Supported          | `Multiplatform`\n`KEYBOARD_LAYOUT_2`                    | `0x4540` | Unsupported        | read only\n`CROWN`                                | `0x4600` | Supported          | `DivertCrown`, `CrownSmooth`\n`TOUCHPAD_FW_ITEMS`                    | `0x6010` | Unsupported        |\n`TOUCHPAD_SW_ITEMS`                    | `0x6011` | Unsupported        |\n`TOUCHPAD_WIN8_FW_ITEMS`               | `0x6012` | Unsupported        |\n`TAP_ENABLE`                           | `0x6020` | Unsupported        |\n`TAP_ENABLE_EXTENDED`                  | `0x6021` | Unsupported        |\n`CURSOR_BALLISTIC`                     | `0x6030` | Unsupported        |\n`TOUCHPAD_RESOLUTION`                  | `0x6040` | Unsupported        |\n`TOUCHPAD_RAW_XY`                      | `0x6100` | Unsupported        |\n`TOUCHMOUSE_RAW_POINTS`                | `0x6110` | Unsupported        |\n`TOUCHMOUSE_6120`                      | `0x6120` | Unsupported        |\n`GESTURE`                              | `0x6500` | Unsupported        |\n`GESTURE_2`                            | `0x6501` | Partial Support    | `Gesture2Gestures`, `Gesture2Params`\n`GKEY`                                 | `0x8010` | Partial Support    | `DivertGkeys`\n`MKEYS`                                | `0x8020` | Supported          | `MkeyLEDs`\n`MR`                                   | `0x8030` | Supported          | `MRKeyLED`\n`BRIGHTNESS_CONTROL`                   | `0x8040` | Supported          | `BrightnessControl`\n`REPORT_RATE`                          | `0x8060` | Supported          | `ReportRate`\n`COLOR_LED_EFFECTS`                    | `0x8070` | Supported          | `LEDControl`, `LEDZoneSetting`\n`RGB_EFFECTS`                          | `0X8071` | Supported          | `RGBControl`, `RGBEffectSetting`\n`PER_KEY_LIGHTING`                     | `0x8080` | Unsupported        |\n`PER_KEY_LIGHTING_V2`                  | `0x8081` | Supported          | `PerKeyLighting`\n`MODE_STATUS`                          | `0x8090` | Unsupported        |\n`ONBOARD_PROFILES`                     | `0x8100` | Supported          |\n`MOUSE_BUTTON_SPY`                     | `0x8110` | Unsupported        |\n`LATENCY_MONITORING`                   | `0x8111` | Unsupported        |\n`GAMING_ATTACHMENTS`                   | `0x8120` | Unsupported        |\n`FORCE_FEEDBACK`                       | `0x8123` | Unsupported        |\n`SIDETONE`                             | `0x8300` | Supported          | `Sidetone`\n`EQUALIZER`                            | `0x8310` | Supported          | `Equalizer`\n`HEADSET_OUT`                          | `0x8320` | Unsupported        |\n\nA “read only” note means the feature is a read-only feature.\n\n## Implementing a feature\n\nFeatures are implemented as settable features in\n`lib/logitech_receiver/settings_templates.py`.\nSome features also have direct implementation in\n`lib/logitech_receiver/hidpp20.py`.\n\nIn most cases it should suffice to only implement the settable feature\ninterface for each setting in the feature.  That will add one or more\nwidgets in the Solaar main window to show and change the setting,\nwill permit storing and restoring changed settings, and\nwill output the feature settings in `solaar show`.\n\nA setting implementation is a subclass of one of the built-in setting classes\nillustrated by the pointer speed setting implementation.\n\n```python\nclass PointerSpeed(_Setting):\n    name = 'pointer_speed'\n    label = _('Sensitivity (Pointer Speed)')\n    description = _('Speed multiplier for mouse (256 is normal multiplier).')\n    feature = _F.POINTER_SPEED\n    validator_class = _RangeV\n    min_value = 0x002e\n    max_value = 0x01ff\n    validator_options = {'byte_count': 2}\n```\n\nA setting implementation needs a name, a label, and a description.\nThe name is used in the persistent settings structure to store and restore changed settings and\nshould be a valid Python identifier.  (Some older settings have dashes.)\nThe label is displayed in the Solaar main window and the description is used as a tooltip there.\nThe label and description should be specified as translatable strings.\nA setting implementation for a feature (for modern devices that use the HID++ 2.0 protocol)\nneeds a feature identifier.\nA setting implementation needs a reader/writer and a validator.\n\nThe reader/writer is responsible for actually writing settings to the device\nand reading them from the device, writing and reading the byte strings that\nrepresent the setting values on the device.\nFor most feature settings the setting implementation can just inherit\nthe standard feature reader/writer, `FeatureRW`.\n\nOptions for `FeatureRW` are supplied by the `rw_options` class variable,\nwhich is used to provide command numbers for reading and writing as well\nas other information needed to identify the parts of the command and response\nthat hold the setting value and modify the reading and writing procedure.\n`PointerSpeed` uses the defaults; here is an example of specifying non-default commands\nfor reading and writing:\n\n```\n    rw_options = {'read_fnid': 0x10, 'write_fnid': 0x20}\n```\n\nSome old devices use registers instead and the setting needs to use the register reader/writer.\nOnly implement a register interface for the setting if you are very brave and\nyou have access to a device that has a register interface for the setting.\nRegister interfaces cannot be auto-discovered and need to be stated in descriptors.py\nfor each device with the register interface.\n\nThe validator instance is responsible for turning raw values read from the device into Python data\nand Python data into raw values to be written to the device and validating that the Python data is\nacceptable for the setting.\nThere are several possible kinds of Python data for setting interfaces,\nranging from simple toggles, to ranges, to fixed lists, to\ndynamic choices, to maps of dynamic choices.\nPointer speed is a setting whose values are integers in a range so _RangeV validator is used.\nArguments to validators are specified as class variables.\nThe _RangeV validator requires the minimum and maximum for the value as separate class variables\nand the byte size of the value on the device as part of `validator_options`.\nSplitting the minimum and maximum makes it easier for code that works with\nsettings to determine this information.\nSettings that are toggles or choices work similarly,\nbut their validators have different arguments.\nMap settings have more complicated validators and more arguments.\n\nSettings where the acceptable values are determined from the device\nsubclass the validator and provide a build class method that queries the device\nand creates an instance of the validator.\nThis method can also return `None`, indicating that even though the\ndevice implements the feature it does not usefully support the setting.\n\nSettings need to be added to the `SETTINGS` list so that setting discovery can be done.\n\nFor more information on implementing feature settings\nsee the comments in `lib/logitech_receiver/settings_templates.py`.\n"
  },
  {
    "path": "docs/hidpp-documentation.txt",
    "content": "Documentation on HID++ can be found in the Google drive directory\nhttps://drive.google.com/drive/folders/0BxbRzx7vEV7eWmgwazJ3NUFfQ28\n"
  },
  {
    "path": "docs/i18n.md",
    "content": "---\ntitle: Translating Solaar\nlayout: page\n---\n\n# Translating Solaar\n\nFirst, make sure you have installed the `gettext` package. Also, you would need to install language pack for Gnome for your language, e.g. `language-pack-gnome-XX-base` for Debian/Ubuntu.\n\nHere are the steps to add/update a translation (you should run all scripts from\nthe source root):\n\n1. Get an up-to-date copy of the source files. Preferably, make a fork on\n   GitHub and clone it locally on your machine; this way you can later make a\n   pull request to the main project.\n\n2. Run `./tools/po-update.sh <language>`; it will create/update the file\n   `./po/<language>.po`.\n\n3. Edit `./po/<language>.po` with your favorite editor (just make sure it saves\n   the file with the UTF-8 encoding). For each string in English (msgid), edit\n   the translation (msgstr); if you leave msgstr empty, the string will remain\n   untranslated.\n\n   Alternatively, you can use the excellent [Poedit](https://poedit.net/) or [Lokalize](https://apps.kde.org/lokalize/).\n\n4. Run `./tools/po-compile.sh`. It will bring up-to-date all the compiled\n   language files, necessary at runtime.\n\n5. Start Solaar (`./bin/solaar`). By default, it will pick up the system language\n   from your environment; to start it in another language, run\n   `LANGUAGE=<language> ./bin/solaar`.\n\nTo edit the translation iteratively, just repeat from step 3.\nIf the upstream changes, do a `git pull` and then repeat from step 2.\n\nBefore opening a pull request, please run `./tools/po-update.sh <language>` again. This will\nformat and sort the translation file, and ensure a minimal diff when updating\na translation.\n\n## Supported languages\n\nSome of the languages Solaar has been translated to are listed below. A full list of available translations can be obtained by checking the `/po` folder for translation files.\n\n- Chinese (Simplified): [Rongrong][Rongronggg9]\n- Chinese (Taiwan): Peter Dave Hello\n- Czech: Marián Kyral\n- Croatian: gogo\n- Danish: John Erling Blad\n- Dutch: Heimen Stoffels\n- Français: [Papoteur][papoteur], [David Geiger][david-geiger], [Damien Lallement][damsweb]\n- Finnish: Tomi Leppänen, [Niko Savola][nikosavola]\n- German: Daniel Frost\n- Greek: Vangelis Skarmoutsos\n- Indonesia: [Ferdina Kusumah][feku]\n- Italiano: [Michele Olivo][micheleolivo], Lorenzo\n- Japanese: Ryunosuke Toda\n- Norsk (Bokmål): [John Erling Blad][jeblad]\n- Norsk (Nynorsk): [John Erling Blad][jeblad]\n- Polski: [Adrian Piotrowicz][nexces], Matthaiks\n- Portuguese: Américo Monteiro\n- Portuguese-BR: [Drovetto][drovetto], [Josenivaldo Benito Jr.][jrbenito], Vinícius\n- Română: Daniel Pavel\n- Russian: [Dimitriy Ryazantcev][DJm00n], Anton Soroko\n- Serbian: [Renato Kaurić][renatoka]\n- Slovak: [Jose Riha][jose1711]\n- Spanish, Castilian: Jose Luis Tirado\n- Swedish: John Erling Blad, [Daniel Zippert][zipperten], Emelie Snecker, Jonatan Nyberg\n- Turkish: Osman Karagöz\n- Ukrainian: Олександр Афанасьєв\n\n[Rongronggg9]: https://github.com/Rongronggg9\n[papoteur]: https://github.com/papoteur\n[david-geiger]: https://github.com/david-geiger\n[damsweb]: https://github.com/damsweb\n[DJm00n]: https://github.com/DJm00n\n[jose1711]: https://github.com/jose1711\n[nexces]: https://github.com/nexces\n[zipperten]: https://github.com/zipperten\n[micheleolivo]: https://github.com/micheleolivo\n[drovetto]: https://github.com/drovetto\n[jrbenito]: https://github.com/jrbenito\n[jeblad]: https://github.com/jeblad\n[feku]: https://github.com/FerdinaKusumah\n[renatoka]: https://github.com/renatoka\n[nikosavola]: https://github.com/nikosavola\n"
  },
  {
    "path": "docs/implementation.md",
    "content": "---\ntitle: Solaar Implementation\nlayout: page\n---\n\n# Solaar Implementation\n\nSolaar has three main components: code mostly about receivers and devices, code for the command line interface, and code for the graphical user interface.\n\nThe following graph shows the main components of Solaar and how they interact.\n```mermaid\ngraph TD\n    subgraph User interface\n    U[UI]\n    C[CLI]\n    end\n\n    subgraph Core\n    U --> S{Solaar}\n    C --> S\n    S --> L[Logitech receiver]\n    L --> R[Receiver]\n    L --> D[Device]\n    S --> B[dbus]\n    end\n\n    subgraph Hardware interface\n    R --> A\n    D --> A\n    A[hidapi]--> P[hid parser]\n    end\n\n    subgraph Peripherals\n    P <-.-> M[Logitech mouse]\n    P <-.-> K[Logitech keyboard]\n    end\n```\n\n\n## Receivers and Devices\n\nThe code in `logitech_receiver` is responsible for creating and maintaining receiver (`receiver/Receiver`) and device (`device/Device`) objects for each device on the computer that uses the Logitech HID++ protocol.  These objects are discovered in Linux by interacting with the Linux `udev` system using code in `hidapi`.\n\nThe code in `logitech_receiver/receiver' is responsible for receiver objects.\n...\n\nThe code in `logitech_receiver/device' is responsible for device objects.\n\n... the complex device setup process\n\nA device object stores the currrent value of many aspects of the device.  It provides methods for retrieving and setting these aspects.  The setters generally store the new value and call an hidpp10 or hidpp20 function to modify the device accordingly.  The retrievers generally check whether the value is cached on the device if so just returning the cached value and if not calling an hidpp10 or hidpp20 function to retrieve the value and returning the value after caching it.\n...\n\nNot all communication with a device is done through the `Device` class.    Some is done directly from settings.\n....\n\n### HID++\n\n#### HID++ 2.0\n\nThe code in `logitech_receiver/hidpp20' interacts with devices using the HID++ 2.0 (and greater) protocol.  Many of the functions in this module send messages to devices to modify their internal state, for example setting a host name stored in the device.  Many other functions send messages to devices that query their internal state and interpret the response, for example returning how often a mouse sends movement reports.  The result of these latter functions are generally cached in device objects.\n\nA few of these functions create and return a large structure or a class object.\n\nThe HID++ 2.0 protocol is built around a number of features, each with its own functionality.  One of the features, that is required to be implemented by all devices supporting the protocol, provide information on which features the device provides.  The `hidpp20` module provides a class (`FeaturesArray`) to store information on what features are provided by a device and how to access them.  Each device that implements the HID++ 2.0 protocol has an instance of this class.  The heavily used function `feature_request` creates an HID++ 2.0 message using this information to help determine what data to put into the message.\n\nMany devices allow reprogramming some keys or buttons.  One the main reasons for reprogramming a key or device is to cause it to produce an HID++ message instead of its normal HID message, this is referred to as diverting the key (to HID++).  The `ReprogrammableKey` class stores information about the reprogramming of one key for one version of this capability, with methods to access and update this information.  The `PersistentRemappableAction` class does the same for another version.  The `KeysArray` class stores information about the reprogramming of a collection of keys, with methods to access this information.  Functions in the Device class request `KeysArray` information for a device when appropriate and store it on the device.\n\nMany pointing devices provide a facility for recognizing gestures and sending an HID message for the gesture.  The `Gesture` class stores inforation for one gesture and the `Gestures` class stores information for all the gestures on a device.  Functions in the Device class request `KeysArray` information and store it on devices.  Functions in the Device class request `Gestures` information for a device when appropriate and store it on the device.\n\nMany gaming devices provide an interface to controlling their LEDs by zone.  The `LEDEffectSetting` class stores the current state of one zone of LEDs.   This information can come directly from an LED feature but is also part of Onboard Profiles so this class provides a byte string interface.   Solaar stores this information in YAML so this class provides a YAML interface.   The `LEDEffectsInfo` class stores information about what LED zones are on a device and what effects they can perform and provides a method that builds an object by querying a device.\n\nMany gaming devices can be controlled by selecting one of their Onboard Profiles.  An Onboard Profile sets up the rate at which the device reports movement, a set of sensitivites of its movement detector, a set of actions to be performed by mouse buttons or G and M keys, and effects for up to two LED zones.  The `Button` class stores information about a button or key action.  The `OnboardProfile` class stores a single profile, using the `LEDEffectSetting` and `Button` classes.  Because retrieving and changing a profile is complex, this class provides a byte string interface.  Because Solaar dumps profiles from devices as YAML documents and loads them into devices from YAML documents, this class provides a YAML interface.  The `OnboardProfiles` class class stores the entire profiles information for a device.  It provides an interface to construct an `OnboardProfiles` object by querying a device.\nBecause Solaar dumps profiles from devices as YAML documents and loads them into devices from YAML documents, these classes also provide a YAML interface.\n\n#### HID++ 1.0\n\nThe code in `logitech_receiver/hidpp10' interacts with devices using the HID++ 1.0 protocol.\n\n...\n\n### Low Level Information and Access\n\nThe module `descriptors` sets up information on device models for which Solaar needs information to support.  Solaar can determine all this information for most modern devices so it is only needed for older devices or devices that are unusual in some way.  The information may include the name of the device model, short name of the device model, the HID++ protocol used by the device model, HID++ registers supported by the device model, various identifiers for the device model, and the USB interface that the device model uses for HID++ messages.  It used to include the HID++-based settings for the device model but this information is now added in `setting_templates`.  The information about a device model can be retrieved in several ways.\n\n\nThe module `base_usb` sets up information for most of the receiver models that Solaar supports, including USB id, USB interface used for HID++ messages, what kind of receiver model it is, and some capabilities of the receiver model.  Solaar can now support other receivers as long as they are not too unusual.  The module lso sets up lists of device models by USB ID and Bluetooth ID and provides a function to determine whether a USB ID or Bluetooth ID is an HID++ device model\n\nThe module `base` provides functions that call discovery to enumerate all current receivers and devices and to set up a callback for when new receivers or devices are discovered.  It provides functions to open and close I/O channels to receivers and devices, write HID++ messages to receivers and devices, and read HID++ messages from receivers and devices.  It provides a function to turn an HID++ message into a notification.\n\nThe module provides a function to send an HID++ message to a receiver or device, constructing the message from parameters to the function, and optionally waiting for and returning a response.  The function checks messages from the receiver or device, only terminating at timeout or when a message that appears to be the response is seen.  Other messages are turned into notifications if appropriate and ignoreed otherwise.  A separate function sends a ping message and waits for a reply to the ping.\n\n\n### Notifications and Status\n\nHID++ devices not only respond to commands but can spontaneously emit HID++ messages, such as when their movement sensitivity changes or when a diverted key is pressed.  These spontaneous messages are called notifications and if software is well behaved can be distinguished from messages that are responses to commands.  (The Linux HIDPP driver was not well behaved at some time and still may not be well behaved, resulting in it causing devices to send responses that cannot be distinguished from notifications.)\n\nThe `listener` module provides a class to set up a thread that listens to all the HID++ messages that come from a given device or receiver, convert the message that are notifications to a Solaar notification structure, and invoke a callback on the notification.\n\nThe 'notifications` module provides a function to take a notification from a receiver or device and initiate processing required for that notification.  For receivers notifications are used to signal the progress of pairing attempts.  For devices some notifications are for pairing, some signal device connection and diconnection from a receiver, some are other parts of the HID++ 1.0 protocol, and some are for the HID++ 2.0 protocol.  Devices can provide a callback for special handling of notifications.  This facility is used for two special kinds of Solaar settings.\n\nThe module contains code that determines the meaning of a notification based on fields in the notification and the status and HID++ 2.0 features of the device if appropriate and updates the device and its status accordingly.  Updates to device status can trigger updates to the Solaar user interface.  The processing of some notifications also directly runs a function to update the Solaar user interface.\n\nAfter this processing HID++ 2.0 notifications are sent to the `diversion` module where they initiate Solaar rule processing.\n\nThe `status` module provides the `DeviceStatus` class to record the battery status of a device.  It also provides an interface to signal changes to the connection status of the device that can invoke a callback.  This callback is used to update the Solaar user interface when the status changes.\n\n\n### Settings\n\nThe Solaar GUI is based around settings.\nA setting contains all the information needed to store the value of some aspect of a device, read it from the device, write it to the device, and record its state in a dictionary.  A setting also contains information to display and manipulate a setting, namely what kind of user interface element to use, what values are permissable, a label to use for the setting, and a tooltip to provide additional information for the setting.  Settings can be either based on HID++ 1.0, using an HID++ 1.0 register that the device provides, or based on HID++ 2.0, using an HID++ 2.0 feature that the device provides.  The module `settings` provides classes and methods to create and support a setting.  The module `setting_templates` contains all the settings that Solaar supports as well as functions to determine what feature-based settings a device can support.\n\nA simple boolean setting can be set up as follows:\n```\nclass HiresSmoothInvert(_Setting):\n    name = 'hires-smooth-invert'\n    label = _('Scroll Wheel Direction')\n    description = _('Invert direction for vertical scroll with wheel.')\n    feature = _F.HIRES_WHEEL\n    rw_options = {'read_fnid': 0x10, 'write_fnid': 0x20}\n    validator_options = {'true_value': 0x04, 'mask': 0x04}\n```\nThe setting is a boolean setting, the default for settings.\n`name` is the dictionary key for recording the state of the setting.\n`label` is the label to be shown for the setting in a user interface and `description` is the tooltip.\n`feature` is the HID++ 2.0 feature that is used to read the current state of the setting from a device and write it back to a device.\n`rw_options` contains options used when reading or writing the state of the setting, here to use feature command 0x10 to read the value and feature command 0x20 to write the value.\n`validator_options` contains options to turn setting values into bytes and bytes into setting values. The options here to take a single byte (the default) and mask it with 0x04 to get a value with a result of 0x04 being true and anything else being false.  They also say to use 0x04 when writing a true value and 0x00 (the default) when writing a false value.  Because this is a boolean setting and the mask masks off part of a byte the value to be written is or'ed with the byte read for the setting before writing to the device.\n\nA simple choice setting can be set up as follows:\n```\nclass Backlight(_Setting):\n    name = 'backlight-qualitative'\n    label = _('Backlight')\n    description = _('Set illumination time for keyboard.')\n    feature = _F.BACKLIGHT\n    choices_universe = _NamedInts(Off=0, Varying=2, VeryShort=5, Short=10, Medium=20, Long=60, VeryLong=180)\n    validator_class = _ChoicesV\n    validator_options = {'choices': choices_universe}\n```\nThis is a choice setting because of the value for `validator_class`.\n`choices_universe` is all the possible stored values for the setting along with how they are to be displayed in a user interface.\n`validator_options` provides the current permissable choices, here always are the same as all the choices.\n\nThe Solaar GUI takes these settings and constructs an interface for displaying and changing the setting.\n\nThis setup allows for very quick implementation of simple settings but it bypasses the data stored in a device object.\n\n\n### Solaar Rules\n\nThe `diversion` module (so-named because it initially mostly handled diverted key notifications) implements Solaar rules.\n\n...\n\n\n### Utility Functions, Structures, and Classes\n\nThe module `common.py` provides utility functions, structures, and classes.\n`crc16` is a function to compute checksums used in profiles.\n`NamedInt`, `NamedInts`, and `UnsortedNamedInts` provide integers and sets of integers with attached names.\n`FirmwareInfo` provides information about device firmware.\n`BATTERY_APPROX` provides named integers used for approximate battery levels of devices.\n\n`i18n.py` provides a few strings that need translations and might not otherwise be visible to translation software.\n\n`special_keys.py` provides named integers for various collections of key codes and colors.\n\n\n## Discovery of HID++ Receivers and Devices and I/O\n\nThe code in `hidapi` is responsible for discovery of receivers and devices that use the HID++ protocol.   The module used in Linux is `hidapi/udev` which is a modification of some old Python code that provides an interface to the Linux `udev` system.\n\nThe code originally was only for receivers that used USB and devices paired with them.  It identifies HID++ receivers by their USB ids, based on a list of Logitech HID++ receivers with their USB ids.  It then added all devices that were paired with them and that were in a list of HID++ devices with their WPID.  A WPID is used to identify the device type for devices paired with HID++ receivers.  This code now also adds all devices paired with HID++ receivers whether they are in this list or not.\n\nThe code now also identifies HID ++ devices that are directly connected via either USB or Bluetooth.  These devices are recognized by several means: the internal list of HID++ devices for elements of the list that have either a USB IS or a Bluetooth ID, any device with a USB ID or Bluetooth ID that falls in one of several ranges of IDs that are known to support HID++, or any device that has an HID protocol descriptor that claims support for HID++.  This last method requires an external Pyshon module to decipher HID protocol descriptors that is not always present.\n\nDevice and receiver discovery is performed when Solaar starts.  While the Solaar GUI is running the `udev` code also listens for connections of new hardware using facilities from `GLib`.\n\nThis code is also responsible for actual writing data to devices and receivers and reading data from them.\n\n\n## Solaar\n\n### Startup and Commonalities\n\n__init__.py\nconfiguration.py\ngtk.py*\ni18n.py\nlistener.py\ntasks.py\nupower.py\n\nThe files `version` and `commit` contain data about the current version and git commit of Solaar.\n\n### Solaar Command Line Interface\n\nsolaar/cli\n\n### Solaar (Graphical) User Interface\n\nsolaar/ui\n"
  },
  {
    "path": "docs/index.md",
    "content": "---\ntitle: Solaar\nlayout: default\n---\n\n**Solaar** is a Linux manager for many Logitech keyboards, mice, and trackpads\nthat connect wirelessly to a USB [Unifying][unifying], Bolt, Lightspeed, or Nano receiver;\nconnect directly via a USB cable; or connect via Bluetooth.\nSolaar does not work with peripherals from other companies.\n\nDocumentation here is for the current version of Solaar.\nSome Linux distributions distribute old versions of Solaar.\nIf you are using an old version and something described here does not work you should upgrade\nusing one of the methods described below.\n\nSolaar runs as a regular user process, albeit with direct access to the Linux interface\nthat lets it directly communicate with the Logitech devices it manages using special\nLogitech-proprietary (HID++) commands.\nEach Logitech device implements a different subset of these commands.\nSolaar is thus only able to make the changes that a particular device supports.\n\nSolaar is not a device driver and does not process normal input from devices.\nIt is thus unable to fix problems that arise from incorrect handling of\nmouse movements or keycodes by Linux drivers or other software.\n\nSolaar can be used as a GUI application, the usual case, or via its command-line interface.\nThe Solaar GUI is meant to run continuously in the background,\nmonitoring devices, making changes to them, and responding to some messages they emit.\nTo this end, it is useful to have Solaar start at user login so that\nchanges made to devices by Solaar are applied at login and throughout the user's session.\n\nBoth Solaar interfaces are able to list the connected devices and\nshow information about each device, often including battery status.\nSolaar is able to pair and unpair devices with\nreceivers as supported by the device and receiver.\nSolaar can also control some changeable settings of devices,\nsuch as scroll wheel direction and function key behavior.\nSolaar keeps track of most of these settings on a per-computer basis,\nbecause devices forget most settings when powered down,\nand the GUI application restores them whenever a device connects.\nFor more information on how to use Solaar see\n[the usage page](https://pwr-solaar.github.io/Solaar/usage),\nand for more information on its capabilities see\n[the capabilities page](https://pwr-solaar.github.io/Solaar/capabilities).\n\n\nSolaar's GUI normally uses an icon in the system tray and starts with its main window visible.\nThis aspect of Solaar depends on having an active system tray, which is not the default\nsituation for recent versions of Gnome.  For information on how to set up a system tray under\nGnome see [the capabilities page](https://pwr-solaar.github.io/Solaar/capabilities).\n\nSolaar's GUI can be started in several ways\n\n- `--window=show` (the default) starts with its main window visible,\n- `--window=hide` starts with its main window hidden,\n- `--window=only` does not use the system tray, and starts with main window visible.\n\nFor more information on Solaar's command-line interface use the help option,\nas in `solaar --help`.\n\nSolaar has progressed past version 1.1. Problems with earlier versions should\nnot be reported as bugs. Instead, upgrade to a recent version or manually install\nthe current version from [GitHub](https://github.com/pwr-Solaar/Solaar).\nSome capabilities of Solaar have been developed by observing the behavior of\nLogitech receivers and devices and generalizing from these observations.\nIf your Logitech receiver or device behaves strangely this may be caused by\nan incorrect behavior generalization.\nPlease report such experiences by creating an issue in\n[the Solaar repository](https://github.com/pwr-Solaar/Solaar/issues).\n\n[unifying]: https://en.wikipedia.org/wiki/Logitech_Unifying_receiver\n\n\n## Supported Devices\n\nSolaar will detect all devices paired with supported Unifying, Bolt, Lightspeed, or Nano\nreceivers, and at the very least display some basic information about them.\nSolaar will detect many Logitech devices that connect via a USB cable or Bluetooth.\n\nSolaar can pair and unpair a Logitech device showing the Unifying logo\n(Solaar's version of the [logo][logo])\nwith any Unifying receiver,\nand pair and unpair a Logitech device showing the Bolt logo\nwith any Bolt receiver,\nand\ncan pair and unpair Lightspeed devices with Lightspeed receivers for the same model.\nSolaar can pair some Logitech devices with Logitech Nano receivers, but not all Logitech\ndevices can be paired with Nano receivers.\nLogitech devices without a Unifying or Bolt logo\ngenerally cannot be paired with Unifying or Bolt receivers.\n\nSolaar does not handle connecting or disconnecting via Bluetooth,\nwhich is done using the usual Bluetooth mechanisms.\n\nFor a partial list of supported devices\nand their features, see [the devices page](https://pwr-solaar.github.io/Solaar/devices).\n\n[logo]: https://pwr-solaar.github.io/Solaar/img/solaar.svg\n\n## Prebuilt packages\n\nUp-to-date prebuilt packages are available for some Linux distros\n(e.g., Fedora 33+) in their standard repositories.\nIf a recent version of Solaar is not\navailable from the standard repositories for your distribution, you can try\none of these packages.\n\n- Arch solaar package in the [extra repository][arch]\n- Ubuntu/Kubuntu package in [Solaar stable ppa][ppa2]\n- NixOS Flake package in [Svenum/Solaar-Flake][nix flake]\n\nSolaar is available from some other repositories\nbut they may be several versions behind the current version.\n\n- for Ubuntu/Kubuntu 16.04+: the solaar package from [universe repository][universe repository]\n- a [Gentoo package][gentoo], courtesy of Carlos Silva and Tim Harder\n- a [Mageia package][mageia], courtesy of David Geiger\n\nSolaar uses a standard system tray implementation; solaar-gnome3 is no longer required for Gnome or Unity integration.\n\n[ppa4]: https://launchpad.net/~trebelnik-stefina\n[ppa2]: https://launchpad.net/~solaar-unifying/+archive/ubuntu/stable\n[arch]: https://www.archlinux.org/packages/extra/any/solaar/\n[gentoo]: https://packages.gentoo.org/packages/app-misc/solaar\n[mageia]: http://mageia.madb.org/package/show/release/cauldron/application/0/name/solaar\n[universe repository]: http://packages.ubuntu.com/search?keywords=solaar&searchon=names&suite=all&section=all\n[nix flake]: https://github.com/Svenum/Solaar-Flake\n\n## Manual installation\n\nSee [the installation page](https://pwr-solaar.github.io/Solaar/installation)\nfor the step-by-step procedure for manual installation.\n\n## License\n\nThis software is distributed under the terms of the\n[GNU Public License, v2](LICENSE.txt), or later.\n\n## Contributing to Solaar\n\nContributions to Solaar are very welcome.\n\nSolaar has complete or partial translations of its GUI strings in several languages.\nIf you want to update a translation or add a new one see [the translation page](https://pwr-solaar.github.io/Solaar/i18n) for more information.\n\nIf you find a bug, please check first if it has already been reported. If yes, please add additional information you may have to the existing issue. If not, please open a new bug report issue. If you can provide a fix for it, please also open a GitHub pull request. Label your commits using the naming conventions in recent commits to Solaar.\n\nIf you want to add a new feature to Solaar, feel free to open a feature request issue to discuss your proposal.\nThere are also usually several open issues for enhancements that have already been requested.\n\n## Contributors\n\nThis project began as a third-hand clone of [Noah K. Tilton](https://github.com/noah)'s\nlogitech-solar-k750 project on GitHub (no longer available). It was developed\nfurther thanks to the contributions of many other people, including:\n\n- [Daniel Pavel](https://github.com/pwr)\n- [Filipe Lains](https://github.com/FFY00)\n- [Peter Wu](https://github.com/Lekensteyn), who also did some [reverse engineering on pairing](https://lekensteyn.nl/logitech-unifying.html)\n- Julien Danjou\n- [Lars-Dominik Braun](http://6xq.net/git/lars/lshidpp.git)\n- [Alexander Hofbauer](http://derhofbauer.at/blog/blog/2012/08/28/logitech-performance-mx)\n- [Clach04](https://github.com/clach04)\n- [Peter F. Patel-Schneider](https://github.com/pfps)\n\nThanks go to Nestor Lopez Casado, who\nprovided [public Logitech specifications for the HID++ protocol](http://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28).\nAlso, thanks to Douglas Wagner, Julien Gascard, and others for helping with application testing and supporting new devices.\n"
  },
  {
    "path": "docs/installation.md",
    "content": "---\ntitle: Manual Installation\nlayout: page\n---\n\n# Installing from PyPI\n\nAn easy way to install the most recent release version of Solaar is from the PyPI repository.\nFirst install pip, and then run\n`pip install --user solaar` or `pipx install --system-site-packages solaar`.\n\nThis will not install the Solaar udev rule, which you will need to install manually by copying\n`~/.local/lib/udev/rules.d/42-logitech-unify-permissions.rules`\nto `/etc/udev/rules.d` as root.\n\n## Installing in macOS\n\nSolaar has limited support for macOS. You can use it to pair devices and configure settings\nbut the rule system and diversion will not work.\n\nAfter installing Solaar via pip use homebrew to install the needed libraries:\n```\nbrew update\nbrew install hidapi gtk+3 pygobject3\n```\n\n### Optional: Set up macOS launcher\n* Option A (recommended): Configure a LaunchAgent to automatically start Solaar and keep it running in the background.\nIt will also automatically restart Solaar if it crashed or closed.\n```\nbash <(curl -fsSL https://raw.githubusercontent.com/pwr-Solaar/Solaar/refs/heads/master/tools/create-macos-launchagent.sh)\n```\n* Option B: Create Solaar.app launcher in /Applications.\nIt can be added to Login Items to start on login, but it will not automatically recover on crashes.\n```\nbash <(curl -fsSL https://raw.githubusercontent.com/pwr-Solaar/Solaar/refs/heads/master/tools/create-macos-app.sh)\n```\n\n# Installating from GitHub\n\n## Downloading\n\nClone Solaar from GitHub by `git clone https://github.com/pwr-Solaar/Solaar.git`.\n\n## Installing using the Makefile\n\nSolaar has a makefile that can be used to easily install Solaar after cloning the repository.\n\nFirst, install the needed system packages by `make install_apt`\nor `make install_dnf` or `make install_brew`.\nThese might not install all needed packages in older versions of your distribution.\nNext, install the Solaar rule via `make install_udev`.\nFinally, install Solaar via `make install_pip` or `make install_pipx`.\n\nParts of the installation process require sudo privileges so you may be asked for your password.\n\n## Running from the download directory\n\nTo run Solaar from the download directory, just cd to there and run `bin/solaar` for the GUI\nor `bin/solaar <command> <arguments>` for the CLI.\n\n## Requirements for Solaar\n\nThis is only relevant if you have problems with the easier methods above.\n\nSolaar needs a reasonably new kernel with kernel modules `hid-logitech-dj` and `hid-logitech-hidpp` loaded.\nThe kernel option CONFIG_HIDRAW also needs to be enabled.\nMost of Solaar should work fine with any kernel more recent than 5.2,\nbut newer kernels might be needed for some devices to be correctly recognized and handled.\nThe `udev` package must be installed and its daemon running.\n\nSolaar requires Python 3.7+ and requires several packages to be installed.\nIf you are running the system version of Python you should have the\n`python3-pyudev`, `python3-psutil`, `python3-xlib`, `python3-evdev`, `python3-typing-extensions`, `dbus-python`\nor `python3-dbus`, and `python3-yaml` or `python3-pyyaml` packages installed.\n\nTo run the GUI Solaar also requires Gtk3 and its GObject introspection bindings.\nIf you are running the system version of Python in Debian/Ubuntu you should have the\n`python3-gi` and `gir1.2-gtk-3.0` packages installed.\nIn Fedora you need `gtk3` and `python3-gobject`.\nYou may have to install `gcc` and the Python development package (`python3-dev` or `python3-devel`,\ndepending on your distribution).\nOther system packages may be required depending on your distribution, such as `python-gobject-common-devel` and `python-typing-extensions'.\nAlthough the Solaar CLI does not require Gtk3,\n`solaar config` does use Gtk3 capabilities to determine whether the Solaar GUI is running\nand thus should tell the Solaar GUI to update its information about settings\nso it is a good idea to have Gtk3 available even for the Solaar CLI.\n\nSolaar needs a library to interact with the system tray.\nThe library that provides this interaction depends on the distribution and window system.\nIf ayatana appindicator is available then it is best to have this library installed,\ne.g., by installing `libayatana-appindicator` or `gir1.2-ayatanaappindicator3-0.1` or similar,\ndepending on distribution.\nOtherwise appindicator can sometimes be used,\ne.g., by installing `libappindicator-gtk3` or `gir1.2-appindicator3-0.1` or similar,\ndepending on distribution.\n\nIf desktop notifications bindings are also installed\n(`gir1.2-notify-0.7` for Debian/Ubuntu),\nyou will also see desktop notifications when devices come online and go offline.\n\nSolaar includes its own version of `hid_parser` because the version that is in PyPi\n(at https://pypi.org/project/hid-parser/) does not have some changes that are in\nhttps://github.com/usb-tools/python-hid-parser and are needed for some devices.\nDo not use pip to install hid_parser!\nSome distributions (e.g., Fedora) may separately package this code.\n\nIf the `gitinfo` Python package is available, Solaar shows better information\nabout which version of Solaar is running.\nThis package may not be available in some distributions but can be installed using pip\nvia `pip install --user python-git-info`.\n\nIf you are running a version of Python different from the system version,\nyou may need to use pip to install projects that provide the above Python packages.\n\nSolaar runs best under X11 with the Xtest extension enabled so that Solaar rules can fake keyboard input using Xtest.\nSolaar also uses the X11 library to access the XKB extension,\nwhich requires installation of the X11 development package.\n(In Fedora this is `libX11-devel`.  In other distributions it may be `libX11-dev`.)\nSolaar will run under Wayland but some parts of Solaar rules will not work.\nFor more information see [the rules page](https://pwr-solaar.github.io/Solaar/rules).\n\n## Installing Solaar's udev rule manually\n\nYou can install Solaar's udev rule manually by copying the file\n`rules.d/42-logitech-unify-permissions.rules`\nas root from the Solaar repository to `/etc/udev/rules.d`.\nLet udev reload its rules by running `sudo udevadm control --reload-rules`.\n\n# Solaar in other languages\n\nIf you want to have Solaar's user messages in some other language you need to run\n`tools/po-compile.sh` to create the translation files before running or installing Solaar\nand set the LANGUAGE environment variable appropriately when running Solaar.\n\n# Running Solaar at Startup\n\nDistributions can cause Solaar can be run automatically at user login by installing a desktop file at\n`/etc/xdg/autostart/solaar.desktop`. An example of this file content can be seen in the repository at\n[`share/autostart/solaar.desktop`](https://github.com/pwr-Solaar/Solaar/blob/master/share/autostart/solaar.desktop).\n\nIf you install Solaar yourself you may need to create or modify this file or install a startup file under your home directory.\n"
  },
  {
    "path": "docs/issues.md",
    "content": "---\ntitle: Known Issues\nlayout: page\n---\n\n# Known Issues\n\n- Some internal structures in Solaar have been updated to use more standard Python language features.\n  This has caused some problems and introduced bugs are still being found.\n\n- Onboard Profiles, when active, can prevent changes to other settings, such as Polling Rate, DPI, and various LED settings. Which settings are affected depends on the device.  To make changes to affected settings, disable Onboard Profiles.  If Onboard Profiles are later enabled the affected settings may change to the value in the profile.\n\n- Bluez 5.73 does not remove Bluetooth devices when they disconnect.\n  Solaar 1.1.12 processes the DBus disconnection and connection messages from Bluez and does re-initialize devices when they reconnect.\n  The HID++ driver does not re-initialize devices, which causes problems with smooth scrolling.\n  Until the problem is resolved having Scroll Wheel Resolution set to true (and not ignored) may be helpful.\n\n- The Linux HID++ driver modifies the Scroll Wheel Resolution setting to\n  implement smooth scrolling.  If Solaar changes this setting, scrolling\n  can be either very fast or very slow.  To fix this problem\n  click on the icon at the right edge of the setting to set it to\n  \"Ignore this setting\", which is the default for new devices.\n  The mouse has to be reset (e.g., by turning it off and on again) before this fix will take effect.\n\n- Solaar expects that it has exclusive control over settings that are not ignored.\n  Running other programs that modify these settings, such as logiops,\n  will likely result in unexpected device behavior.\n\n- The driver also sets the scrolling direction to its normal setting when implementing smooth scrolling.\n  This can interfere with the Scroll Wheel Direction setting, requiring flipping this setting back and forth\n  to restore reversed scrolling.\n\n- The driver sends messages to devices that do not conform with the Logitech HID++ specification\n  resulting in responses being sent back that look like other messages.  For some devices this causes\n  Solaar to report incorrect battery levels.\n\n- Solaar normally uses icon names for its icons, which in some system tray implementations\n  results in missing or wrong-sized icons.\n  The `--tray-icon-size` option forces Solaar to use icon files of appropriate size\n  for tray icons instead, which produces better results in some system tray implementations.\n  To use icon files close to 32 pixels in size use `--tray-icon-size=32`.\n\n- The icon in the system tray can show up as 'black on black' in dark\n  themes or as non-symbolic when the theme uses symbolic icons.  This is due to problems\n  in some system tray implementations. Changing to a different theme may help.\n  The `--battery-icons=symbolic` option can be used to force symbolic icons.\n\n- Solaar uses uinput to simulate input\n  but this needs write permission on /dev/uinput.\n  For more information see [the rules page](https://pwr-solaar.github.io/Solaar/rules).\n\n- Diverted keys remain diverted and so do not have their normal behavior when Solaar terminates\n  or a device disconnects from a host that is running Solaar.  If necessary, their normal behavior\n  can be reestablished by turning the device off and on again.  This is most important to restore\n  the host switching behavior of a host switch key that was diverted, for example to switch away\n  from a host that crashed or was turned off.\n\n- When a receiver-connected device changes hosts Solaar remembers which diverted keys were down on it.\n  When the device changes back the first time any of these diverted keys is depressed Solaar will not\n  realize that the key was newly depressed.  For this reason Solaar rules that can change hosts should\n  trigger on key releasing.\n"
  },
  {
    "path": "docs/rules.md",
    "content": "---\ntitle: Rule Processing of HID++ Notifications\nlayout: page\n---\n\n# Rule Processing of HID++ Notifications\nCreating and editing most rules can be done in the Solaar GUI, by pressing the 'Rule Editor' button in the\nSolaar main window.\n\nNote that rule processing only fully works under X11.\nWhen running under Wayland with X11 libraries loaded some features will not be available.\nWhen running under Wayland without X11 libraries loaded even more features will not be available.\nRule features known not to work under Wayland include process and mouse process conditions,\nalthough on GNOME desktop under Wayland, you can use those with the Solaar Gnome extension installed,\nYou can install it from `https://extensions.gnome.org/extension/6162/solaar-extension`.\nUnder Wayland using keyboard groups may result in incorrect symbols being input for simulated input.\nUnder Wayland simulating inputs when modifier keys are pressed may result in incorrect symbols being sent.\nSimulated input uses uinput to simulate input so the user has to have write access to /dev/uinput.\nThe easiest way to maintain write access to /dev/uinput is to use Solaar's udev rule by downloading\n`https://raw.githubusercontent.com/pwr-Solaar/Solaar/master/rules.d/42-logitech-unify-permissions.rules`\nand copying it as root into the `/etc/udev/rules.d` directory.\nYou may have to reboot your system for the write permission to be set up.\nAnother way to get write access to /dev/uinput is to run `sudo setfacl -m u:${USER}:rw /dev/uinput`\nbut this needs to be done every time the system is rebooted.\n\n## HID++ notifications and diversion\nLogitech devices that use HID++ version 2.0 or greater, produce feature-based\nnotifications that Solaar can process using a simple rule language. For\nexample, using rules Solaar can emulate an `XF86_MonBrightnessDown` key tap\nin response to the pressing of the `Brightness Down` key on Craft keyboards,\nwhich normally does not produce any input at all when the keyboard is in\nWindows mode.\n\nSolaar's rules only trigger on HID++ notifications so device actions that\nnormally produce HID output have to be first be set (diverted) to\nproduce HID++ notifications instead of their normal behavior.\nCurrently, Solaar can divert some mouse scroll wheels, some\nmouse thumb wheels, the crown of Craft keyboards, and some keys and buttons.\nIf the scroll wheel, thumb wheel, crown, key, or button is\nnot diverted by setting the appropriate setting then no HID++ notification is\ngenerated and rules will not be triggered by manipulating the wheel, crown, key, or button.\nLook for `HID++` or `Diversion` settings to see what\ndiversion can be done with your devices.\n\n### Show notifications\nRunning Solaar with the `-ddd`\noption will show information about notifications, including their feature\nname, report number, and data.\n\nIn response to a feature-based HID++ notification Solaar runs a sequence of\nrules. A `Rule` is a sequence of components, which are either sub-rules,\nconditions, or actions. Conditions and actions are dictionaries with one\nentry whose key is the name of the condition or action and whose value is\nthe argument of the action.\n\nIf the last thing that a rule does is execute an action, no more rules are\nprocessed for the notification.\n\nRules are evaluated by evaluating each of their components in order. The\nevaluation of a rule is terminated early if a condition component evaluates\nto false or the last evaluated subcomponent of a component is an action. A\nrule is false if its last evaluated component evaluates to false.\n\n## Conditions\n\n### Not\n`Not` conditions take a single component and are true if their component\nevaluates to a false value.\n\n### Or\n`Or` conditions take a sequence of components and are evaluated by\nevaluating each of their components in order.\nAn Or condition is terminated early if a component evaluates to true or the\nlast evaluated subcomponent of a component is an action.\nA Or condition is true if its last evaluated component evaluates to a true\nvalue. `And` conditions take a sequence of components which are evaluated the same\nas rules.\n\n### Feature\n`Feature` conditions are true if the name of the feature of the current\nnotification is their string argument.\n`Report` conditions are true if the report number in the current\nnotification is their integer argument.\n\n### Key\n`Key` conditions are true if the Logitech name of the current **diverted** key or button being pressed is their\nstring argument. Alternatively, if the argument is a list `[name, action]` where `action`\nis either `'pressed'` or `'released'`, the key down or key up events of `name` argument are\nmatched, respectively. Logitech key and button names are shown in the `Key/Button Diversion`\nsetting. These names are also shown in the output of `solaar show` in the 'Reprogrammable keys'\nsection. Only keys or buttons that have 'Divertable' in their report can be diverted.\nSome keyboards have 'Gn', 'Mn', or 'MR' keys, which are diverted using the 'Divert G Keys' setting.\n\n### Key is down\n`KeyIsDown` conditions are true if the **diverted** key or button that is their string argument is currently down.\nNote that this only works for **diverted** keys or buttons, including diverted Gn, Mn, and MR keys.\n\n### Key and button diversion\nSolaar can also create special notifications in response to mouse movements on some mice.\nSetting `Key/Button Diversion` for a key or button to Mouse Gestures causes the key or button to create a `Mouse Gesture`\nnotification for the period that the key or button is depressed.\nMoving the mouse creates a mouse movement event.\nStopping the mouse for a little while and moving it again creates another mouse movement event.\nPressing a diverted key creates a key event.\nWhen the key is released the sequence of events is sent as a synthetic notification\nthat can be matched with `Mouse Gesture` conditions.\n\n### Mouse gestures\n`Mouse Gesture` conditions are true if the actions (mouse movements and diverted key presses) taken while a mouse gestures button is held down match the arguments of the condition.\nMouse gestures buttons can be set using the 'Key/Button Diversion' setting, by changing the value to `Mouse Gestures`.\nThe arguments of a Mouse Gesture condition can be a direction, i.e., `Mouse Up`, `Mouse Down`, `Mouse Left`, `Mouse Right`, `Mouse Up-Left`, `Mouse Up-Right`, `Mouse Down-Left`, or `Mouse Down-Right`, or the Logitech name of a key.\nIf the first argument is the Logitech name of a key then that argument is matched against the button that was held down to initiate mouse gesture processing.\nFor example, a Mouse Gesture condition of `Mouse Up` -> `Mouse Up` would match pressing any Mouse Gestures button, moving the mouse upwards, pausing momentarily, moving the mouse upwards again, and releasing the button.\nThe condition `Smart Shift` -> `Mouse Down` -> `Back Button` would match pressing the Smart Shift button (provided that it is a Mouse Gestures button!), moving the mouse downwards, clicking the Back button (provided that it is diverted!), and then releasing the Smart Shift button.\nDirections and buttons can be mixed and chained together however you like.\nIt's possible to create a `No-op` gesture by clicking 'Delete' on the initial Action when you first create the rule. This gesture will trigger when you simply click a Mouse Gestures button.\n\n### Key modifiers\n`Modifiers` conditions take either a string or a sequence of strings, which\ncan only be `Shift`, `Control`, `Alt`, and `Super`.\nModifiers conditions are true if their argument is the current keyboard\nmodifiers.\n\n### Process focused\n`Process` conditions are true if the process for the focused input window\nor the window's Window manager class or instance name starts with their string argument.\n\n### Window under cursor\n`MouseProcess` conditions are true if the process for the window under the mouse\nor the window's Window manager class or instance name starts with their string argument.\n\n### Device notification and device active\n`Device` conditions are true if a particular device originated the notification.\n`Active` conditions are true if a particular device is active.\n`Device` and `Active` conditions take one argument, which is the serial number or unit ID of a device,\nas shown in Solaar's detail pane, or either of its names, as shown by Solaar.\nSome older devices do not have a useful serial number or unit ID and so cannot\ndistinguished from other devices with the same names.\n\n### Host\n`Host` conditions are true if the computers hostname starts with the condition's argument.\n\n### Solaar device setting\n`Setting` conditions check the value of a Solaar setting on a device.\n`Setting` conditions take three or four arguments, depending on the setting:\nthe Serial number or Unit ID of a device, as shown in Solaar's detail pane,\nor null for the device that initiated rule processing;\nthe internal name of a setting (which can be found from solaar config \\<device\\>);\none or two arguments for the setting.\nFor settings that use keys or buttons as an argument the Logtech name can be used\nas shown in the Solaar main window for these settings,\nor the numeric value for the key or button.\nFor settings that use gestures as an argument the internal name of the gesture is used,\nwhich can be found in the GESTURE2_GESTURES_LABELS structure in lib/logitech_receiver/settings_templates.\nFor settings that need one of a set of names as an argument the name can be used or its internal integer value,\nas used in the Solaar config file.\n\n`Setting` conditions check device settings of devices, provided the device is on-line.\nThe first arguments to the condition are the Serial number or Unit ID of a device, as shown in Solaar's detail pane,\nor null for the device that initiated rule processing; and\nthe internal name of a setting (which can be found from solaar config \\<device\\>).\nMost simple settings take one extra argument, the value to check the setting value against.\nRange setting can also take two arguments, which form an inclusive range to check against.\nOther settings take two arguments, a key indicating which sub-setting to check and the value to check it against.\nFor settings that use gestures as an argument the internal name of the gesture is used,\nwhich can be found in the GESTURE2_GESTURES_LABELS structure in lib/logitech_receiver/settings_templates.\nFor boolean settings '~' can be used to toggle the setting.\n\n### Test and TestBytes\n`Test` and `TestBytes` conditions are true if their test evaluates to true on the feature,\nreport and data of the current notification.\n`TestBytes` conditions can return a number instead of a boolean.\n\n`TestBytes` conditions consist of a sequence of three or four integers and use the first\ntwo to select bytes of the notification data.\nWriting this kind of test condition is not trivial.\nThree-element `TestBytes` conditions are true if the selected bytes bit-wise AND\nwith its third element is non-zero.\nThe value of these test conditions is the result of the AND.\nFour-element `TestBytes` conditions are true if the selected bytes form a signed\ninteger between the third and fourth elements.\nThe value of these conditions is the signed value of the selected bytes\nif that is non-zero otherwise True.\n\n`Test` conditions are mnemonic shorthands for meaningful feature,\nreport, and data combinations in notifications.\nA `crown_right` test is the rotation amount of a `CROWN` right rotation notification.\nA `crown_left` test is the rotation amount of a `CROWN` left rotation notification.\nA `crown_right_ratchet` test is the ratchet amount of a `CROWN` right ratchet rotation notification.\nA `crown_left_ratchet` test is the ratchet amount of a `CROWN` left ratchet rotation notification.\nA `crown_tap` test is true for a `CROWN` tap notification.\nA `crown_start_press` test is true for the start of a `CROWN` press notification.\nA `crown_stop_press` test is true for the end of a `CROWN` press notification.\nA `crown_pressed` test is true for a `CROWN` notification with the Crown pressed.\nA `thumb_wheel_up` test is the rotation amount of a `THUMB WHEEL` upward rotation notification.\nA `thumb_wheel_down` test is the rotation amount of a `THUMB WHEEL` downward rotation notification.\n`lowres_wheel_up`, `lowres_wheel_down`, `hires_wheel_up`, `hires_wheel_down` are the\nsame but for `LOWRES WHEEL` and `HIRES WHEEL`.\n`True` and `False` tests return True and False, respectively.\n\nSolaar keeps track of the total signed displacement of the current thumb wheel movement.\nThis displacement is reset when the thumb wheel is inactive.\n`thumb_wheel_up` and `thumb_wheel_down` tests take an optional integer parameter.\nWith a parameter the test is only true if the current thumb wheel displacement is greater than the parameter.\nThe displacement is then lessened by the amount of the parameter.\n\n## Actions\n\n### Key press\nA `KeyPress` action takes either the name of an X11 key symbol, such as \"a\",\na list of X11 key symbols, such as \"a\" or \"CTRL + A\",\nor a two-element list with the first element as above\nand the second element one of `'click'`, `'depress'`, or `'release'`\nand executes key actions on a simulated keyboard to produce these symbols.\nUse separate `KeyPress` actions for multiple characters,\ni.e., don't use a single `KeyPress` like 'a+b'.\nThe `KeyPress` action normally both depresses and releases (clicks) the keys,\nbut can also just depress the keys or just release the keys.\nUse the depress or release options with extreme care,\nensuring that the depressed keys are later released,\notherwise it may become difficult to use your system.\nThe keys are depressed in forward order and released in reverse order.\n\nIf a key symbol can only be produced by a shfited or level 3 keypress, e.g., \"A\",\nthen Solaar will add keypresses to produce that key symbol,\ne.g., simulating a left shift keypress to get \"A\" instead of \"a\".\nIf a key symbol is not available in the current keymap or needs other shift-like keys,\nthen Solaar cannot simulate it.\nUnder X11 Solaar can determine the current key modifiers (shift, control, etc.).\nAny key symbols that correspond to these modifier keys are not depressed and released when clicking.\nSo if the shift key is currently down on a keyboard Solaar will not bother to simulate a shift key.\nUnder Wayland this check cannot be done so the net result of a `KeyPress` action that is not a `depress` or a `release`\nand that contains modifier keys might be to release the modifier keys.\n\nSimulating input in Linux is complex.\nSolaar has to try to determine which keyboard key corresponds to which input character as it cannot directly\nsimulate inputting a key symbol.\nUnfortunately, this determination can go wrong in several ways and is more likely\nto go wrong under Wayland than under X11.\n\n### Mouse scroll\nA `MouseScroll` action takes a sequence of two numbers and simulates a horizontal and vertical mouse scroll of these amounts.\nIf the previous condition in the parent rule returns a number the scroll amounts are multiplied by this number.\n\n### Mouse click\nA `MouseClick` action takes a mouse button name (`left`, `middle` or `right`) and a positive number or 'click', 'depress', or 'release'.\nThe action simulates that number of clicks of the specified button or just one click, depress, or release of the button.\n\n### Execute\nAn `Execute` action takes a program and arguments and executes it asynchronously.\n\n### Set setting\nA `Set` action changes a Solaar setting for a device, provided that the device is on-line.\n`Set` actions take three or four arguments, depending on the setting.\nThe first two are the Serial number or Unit ID of a device, as shown in Solaar's detail pane,\nor null for the device that initiated rule processing; and\nthe internal name of a setting (which can be found from `solaar config <device>`).\nSimple settings take one extra argument, the value to set the setting to.\nFor boolean settings `~` can be used to toggle the setting.\nOther simple settings take two extra arguments, a key indicating which sub-setting to set and the value to set it to.\nFor settings that use gestures as an argument the internal name of the gesture is used,\nwhich can be found in the GESTURE2_GESTURES_LABELS structure in `lib/logitech_receiver/settings_templates`.\nAll settings are supported.\n\n### Later\nA `Later` action executes rule components later.\n`Later` actions take an integer delay in seconds between 1 and 100 followed by zero or more rule components that will be executed later.\nProcessing of the rest of the rule continues immediately.\n\n## Built-in Rules\n\nSolaar has a built-in rule, which is run after user-created rules and so can be overridden by user-created rules.\nThis rule turns\n`Brightness Down` key press notifications into `XF86_MonBrightnessDown` key taps\nand `Brightness Up` key press notifications into `XF86_MonBrightnessUp` key taps.\n\n## Example Solaar Rule File\n\nSolaar reads rules from a YAML configuration file (normally `~/.config/solaar/rules.yaml`).\nThis file contains zero or more documents, each a rule.\n\nHere is a file with six rules:\n\n```\n%YAML 1.3\n---\n- Key: [M2, pressed]\n- Set: [198E3EB8, dpi, 3000]\n- Execute: [notify-send, Increased mouse speed]\n...\n---\n- Key: [Host Switch Channel 2, pressed]\n- Set: [43DAF041, change-host, 1]\n- Set: [198E3EB8, change-host, 1]\n- Execute: [notify-send, Switched to host 2]\n...\n---\n- MouseGesture: [Mouse Up, Mouse Down]\n- Execute: [notify-send, Locking]\n- Execute: xflock4\n...\n- Feature: CROWN\n- Process: quodlibet\n- Rule: [ Test: crown_start_press, KeyPress: XF86_AudioMute ]\n- Rule: [ Test: crown_pressed, Test: crown_right_ratchet, KeyPress: XF86_AudioNext ]\n- Rule: [ Test: crown_pressed, Test: crown_left_ratchet, KeyPress: XF86_AudioPrev ]\n- Rule: [ Test: crown_right_ratchet, KeyPress: XF86_AudioRaiseVolume ]\n- Rule: [ Test: crown_left_ratchet, KeyPress: XF86_AudioLowerVolume ]\n...\n---\n- Feature: THUMB WHEEL\n- Rule: [ Modifiers: Control, Test: thumb_wheel_up, MouseScroll: [-2, 0] ]\n- Rule:\n  - Modifiers: Control\n  - Test: thumb_wheel_down\n  - MouseScroll: [-2, 0]\n- Rule: [ Or: [ Test: thumb_wheel_up, Test: thumb_wheel_down ], MouseScroll: [-1, 0] ]\n...\n---\n- Feature: LOWRES WHEEL\n- Rule: [ Or: [ Test: lowres_wheel_up, Test: lowres_wheel_down ], MouseScroll: [0, 2] ]\n...\n```\n\n## Button diversion example\nHere is an example showing how to divert the Back Button on an MX Master 3 so that pressing\nthe button will initiate rule processing and a rule that triggers on this notification and\nswitches the mouse to host 3 after popping up a simple notification.\n\n![Solaar-divert-back](screenshots/Solaar-main-window-back-divert.png)\n\n![Solaar-rule-back-host](screenshots/Solaar-rule-editor.png)\n"
  },
  {
    "path": "docs/uninstallation.md",
    "content": "---\ntitle: Uninstalling Solaar\nlayout: page\n---\n\n# Uninstalling Solaar\n\n## Uninstalling from Debian systems\n\nIf you installed Solaar using `apt`, you can remove it by running:\n\n```bash\nsudo apt remove --purge solaar\n```\n\n## Uninstalling from GitHub\n\nIf you cloned and installed Solaar from GitHub manually, navigate to the cloned directory and run:\n\n```bash\nsudo make uninstall\n```\n\n## Removing Configuration Files\n\nSolaar may leave behind configuration files in your home directory. To delete them, run:\n\n```bash\nrm -rf ~/.config/solaar\n```\n\n## Verifying Uninstallation\n\nTo confirm that Solaar is fully removed, try running:\n\n```bash\nwhich solaar\n```\n\nIf no output is returned, Solaar has been successfully uninstalled.\n"
  },
  {
    "path": "docs/usage.md",
    "content": "---\ntitle: Solaar GUI Usage\nlayout: page\n---\n\n# Solaar GUI Usage\n\nThe Solaar GUI (the usual way to run Solaar) is meant to run continuously in the background,\nmonitoring devices, making changes to them, and responding to some messages they emit.\nThe Solaar GUI normally creates an icon in your system tray that provides an interface\nto Solaar.  This icon is\nusually a battery icon showing the approximate battery level for your device\nwith the lowest known battery level. If there are no devices with battery information,\nthen the icon is one of the Solaar icons.\n\nSolaar also has a main window.  When the main window is invisible,\nclick on Solaar's icon in the system tray to bring up the Solaar menu, and then\nclick on a receiver or device in the menu to see information about\nthat receiver or device.\n\nThe following is an image of the Solaar menu and the icon (the battery\nsymbol is in the system tray at the left of the image). The icon can\nalso be other battery icons or versions of the Logitech Unifying icon.\n\n![Solaar-menu](screenshots/Solaar-menu.png)\n\nClicking on “Quit” in the Solaar menu terminates the program.\nClicking on “About Solaar” pops up a window with further information about Solaar.\n\n## Solaar options\n\nThere are several options that affect how the Solaar GUI behaves:\n\n* `--help` shows a help message and then quits\n* `--version` shows the version of Solaar and then quits\n* `--window=show` starts Solaar with the main window showing\n* `--window=hide` starts Solaar with the main window not showing\n* `--window=only` starts Solaar with no system tray icon and the main window showing\n* `--battery-icons=regular` uses regular icons for battery levels\n* `--battery-icons=symbolic` uses symbolic icons for battery levels\n* `--battery-icons=solaar` uses only the Solaar icon in the system tray\n\n## Solaar main window\n\nThe Solaar main window shows your Logitech receivers and devices that Solaar\nknows about and can be used to pair new devices, unpair paired devices, and\nview and change some settings of the selected receiver or device.\nTo select a receiver or device click on it in the left side of the window.\n\nClosing the main window does not terminate Solaar (unless Solaar is not using the system tray).\nClicking on “Quit Solaar” terminates the program, and “About Solaar” pops up a window with further information.\nThe light bulb (or a similar icon) displays detailed information\nabout the selected receiver or device (useful for debugging).\n\n### Pairing and unpairing devices\n\nWhen a receiver is selected in the main window, you can pair a new device by\nclicking on the “Pair new device” button.\nThen turn on the device and it should pair with the receiver if that is possible\nand the device is not already paired with another active receiver.\nFor multi-host devices first select the host position that you want.\nBolt devices and some Lightspeed devices pair by pressing a special pairing button.\nTo pair with a Bolt receiver you have to type a passcode followed by enter\nor click the left and right buttons in the correct sequence followed by\nclicking both buttons simultaneously.\n\n![Solaar-main-window-receiver](screenshots/Solaar-main-window-receiver.png)\n\nWhen a device is selected you can unpair the device if your receiver supports\nunpairing. To unpair the device, just click on the “Unpair” button and\nconfirm in the window that pops up.\n\nA receiver with the Unifying logo should be able to pair with any device\nwith the Unifying logo\nand a receiver with the Bolt logo should be able to pair with any device\nwith the Bolt logo.\nIf there are no open pairing slots, however, you will\nnot be able to pair a new device. In this case to pair a new device you\nfirst need to unpair a device.\n\nOther receivers can only pair with certain kinds of devices.\nMost of these receivers do not allow unpairing - instead\npairing a new device replaces an existing paired device of the same kind.\nSome receivers can only pair a limited number of times.\n\n### Viewing and changing device settings\n\nWhen a device is selected you can see the approximate battery level of the\ndevice, if that is reported by the device, and the status of the link\nbetween the device and its receiver.\n\nYou can also see and change the settings of devices.\nChanging settings is performed by clicking on buttons,\nmoving sliders, or selecting from alternatives.\n\n![Solaar-main-window-keyboard](screenshots/Solaar-main-window-keyboard.png)\n\n![Solaar-main-window-mouse](screenshots/Solaar-main-window-mouse.png)\n\nDevice settings now have a clickable icon that determines whether the\nsetting can be changed and whether the setting is ignored.\n\n![Solaar-divert-back](screenshots/Solaar-main-window-back-divert.png)\n\nIf the selected device that is paired with a receiver is powered down or\notherwise disconnected its settings cannot be changed\nbut it still can be unpaired if its receiver allows unpairing.\n\n![Solaar-main-window-offline](screenshots/Solaar-main-window-offline.png)\n\nIf a device is paired with a receiver but directly connected via USB or Bluetooth\nthe receiver pairing will show up as well as the direct connection.\nThe device can only be manipulated using the direct connection.\n\n![Solaar-main-window-multiple](screenshots/Solaar-main-window-multiple.png)\n\n#### Remapping key and button actions\n\nFor many devices Solaar can remap some of their keys or buttons to\nperform a different action. (This changes the information that the\ndevice sends when the key or button is activated.) Only some keys on some\ndevices can be remapped and they can only be remapped to a limited\nnumber of actions. The remapping is done by selecting a key\nor button in the left-hand box on the “Action” setting line and then\nselecting the action to be performed in the right-hand box. The default\naction is always the one shown first in the list. As with all settings,\nSolaar will remember past action settings and restore them on the device\nfrom then on.\n\n![Solaar-main-window-actions](screenshots/Solaar-main-window-button-actions.png)\n\nThe names of the keys, buttons, and actions are mostly taken from Logitech\ndocumentation and may not be completely obvious.\n\nIt is possible to end up with an unusable system, for example by having no\nway to do a mouse left click, so exercise caution when remapping keys or\nbuttons that are needed to operate your system.\n\n## Solaar command-line interface\n\nSolaar also has a command-line interface that can do most of what can be\ndone using the main window. For more information on the\ncommand line interface, run `solaar --help` to see the commands and\nthen `solaar <command> --help` to see the arguments to any of the commands.\n\n## Solaar settings\n\nSolaar supports at least the following settings:\n\nSetting                          | Description\n---------------------------------|------------\nHand Detection\t\t\t | Turn on backlight when your hands hover over the keyboard\nScroll Wheel Smooth Scrolling\t | Higher-speed vertical scrolling\nSide Scrolling\t    \t\t | When off, side scrolling sends custom button events\nScroll Wheel High Resolution\t | Higher-speed vertical scrolling\nScroll Wheel HID++ Scrolling\t | When on, vertical scrolling uses HID++ events\nScroll Wheel Direction\t\t | Reverse direction of vertical scrolling\nScroll Wheel Resolution\t\t | Higher-speed vertical scrolling (use with caution)\nScroll Wheel Rachet\t\t | Shift wheel ratchet on and off based on wheel speed\nThumb Wheel HID++ Scrolling\t | When on, thumb-wheel scrolling uses HID++ events\nThumb Wheel Direction\t\t | Reverse direction of thumb-wheel scrolling\nSensitivity (DPI)\t\t | Mouse movement sensitivity\nSensitivity (Pointer Speed)\t | Mouse movement sensitivity\nBacklight   \t\t\t | Turn on backlight\nSwap Fx function\t\t | Change Fn keys to normally do their special action\nDPI Sliding Adjustment\t\t | Change Sensitivity (DPI) by holding a button and moving the mouse\nMouse Gestures\t\t\t | Create HID++ events by holding a button and moving the mouse\nKey/Button Actions   \t\t | Change what a key or button does\nKey/Button Diversion\t\t | Divert keys and buttons to create HID++ events\nDivert crown events\t\t | Divert crown actions to create HID++ events\nDivert G Keys\t\t\t | Divert G keys to create HID++ events\nDisable keys\t\t\t | Disable one or more keys\nSet OS\t\t\t\t | Change keys to match OS\nChange Host\t\t\t | Connect to a different host\nGestures\t\t\t | Turn on and off various (mostly touchpad) gestures\nGesture params\t\t\t | Modify parameters for gestures\n\nHID++ events are mostly not processed by Linux input drivers.\nSettings that involve sending HID++ events exist so that these events can be\nprocessed by Solaar rules instead of by Linux.\n\nDifferent Logitech devices may implement the same functionality in different ways,\nthus the different settings that do the same thing.\n"
  },
  {
    "path": "docs/usb.ids.txt",
    "content": "#\n#\tList of USB ID's\n#\n#\tMaintained by Stephen J. Gowdy <linux.usb.ids@gmail.com>\n#\tIf you have any new entries, please submit them via\n#\t\thttp://www.linux-usb.org/usb-ids.html\n#\tor send entries as patches (diff -u old new) in the\n#\tbody of your email (a bot will attempt to deal with it).\n#\tThe latest version can be obtained from\n#\t\thttp://www.linux-usb.org/usb.ids\n#\n# Version: 2019.11.05\n# Date:    2019-11-05 20:34:06\n#\n\n# Vendors, devices and interfaces. Please keep sorted.\n\n# Syntax:\n# vendor  vendor_name\n#\tdevice  device_name\t\t\t\t<-- single tab\n#\t\tinterface  interface_name\t\t<-- two tabs\n\n046d  Logitech, Inc.\n\t0082  Acer Aspire 5672 Webcam\n\t0200  WingMan Extreme Joystick\n\t0203  M2452 Keyboard\n\t0242  Chillstream for Xbox 360\n\t0301  M4848 Mouse\n\t0401  HP PageScan\n\t0402  NEC PageScan\n\t040f  Logitech/Storm PageScan\n\t0430  Mic (Cordless)\n\t0801  QuickCam Home\n\t0802  Webcam C200\n\t0804  Webcam C250\n\t0805  Webcam C300\n\t0807  Webcam B500\n\t0808  Webcam C600\n\t0809  Webcam Pro 9000\n\t080a  Portable Webcam C905\n\t080f  Webcam C120\n\t0810  QuickCam Pro\n\t0819  Webcam C210\n\t081a  Webcam C260\n\t081b  Webcam C310\n\t081d  HD Webcam C510\n\t0820  QuickCam VC\n\t0821  HD Webcam C910\n\t0823  HD Webcam B910\n\t0825  Webcam C270\n\t0826  HD Webcam C525\n\t0828  HD Webcam B990\n\t082b  Webcam C170\n\t082c  HD Webcam C615\n\t082d  HD Pro Webcam C920\n\t0830  QuickClip\n\t0836  B525 HD Webcam\n\t0837  BCC950 ConferenceCam\n\t0840  QuickCam Express\n\t0843  Webcam C930e\n\t0850  QuickCam Web\n\t085c  C922 Pro Stream Webcam\n\t0870  QuickCam Express\n\t0890  QuickCam Traveler\n\t0892  OrbiCam\n\t0894  CrystalCam\n\t0895  QuickCam for Dell Notebooks\n\t0896  OrbiCam\n\t0897  QuickCam for Dell Notebooks\n\t0899  QuickCam for Dell Notebooks\n\t089d  QuickCam E2500 series\n\t08a0  QuickCam IM\n\t08a1  QuickCam IM with sound\n\t08a2  Labtec Webcam Pro\n\t08a3  QuickCam QuickCam Chat\n\t08a6  QuickCam IM\n\t08a7  QuickCam Image\n\t08a9  Notebook Deluxe\n\t08aa  Labtec Notebooks\n\t08ac  QuickCam Cool\n\t08ad  QuickCam Communicate STX\n\t08ae  QuickCam for Notebooks\n\t08af  QuickCam Easy/Cool\n\t08b0  QuickCam 3000 Pro [pwc]\n\t08b1  QuickCam Notebook Pro\n\t08b2  QuickCam Pro 4000\n\t08b3  QuickCam Zoom\n\t08b4  QuickCam Zoom\n\t08b5  QuickCam Sphere\n\t08b9  QuickCam IM\n\t08bd  Microphone (Pro 4000)\n\t08c0  QuickCam Pro 3000\n\t08c1  QuickCam Fusion\n\t08c2  QuickCam PTZ\n\t08c3  Camera (Notebooks Pro)\n\t08c5  QuickCam Pro 5000\n\t08c6  QuickCam for DELL Notebooks\n\t08c7  QuickCam OEM Cisco VT Camera II\n\t08c9  QuickCam Ultra Vision\n\t08ca  Mic (Fusion)\n\t08cb  Mic (Notebooks Pro)\n\t08cc  Mic (PTZ)\n\t08ce  QuickCam Pro 5000\n\t08cf  QuickCam UpdateMe\n\t08d0  QuickCam Express\n\t08d7  QuickCam Communicate STX\n\t08d8  QuickCam for Notebook Deluxe\n\t08d9  QuickCam IM/Connect\n\t08da  QuickCam Messenger\n\t08dd  QuickCam for Notebooks\n\t08e0  QuickCam Express\n\t08e1  Labtec Webcam\n\t08f0  QuickCam Messenger\n\t08f1  QuickCam Express\n\t08f2  Microphone (Messenger)\n\t08f3  QuickCam Express\n\t08f4  Labtec Webcam\n\t08f5  QuickCam Messenger Communicate\n\t08f6  QuickCam Messenger Plus\n\t0900  ClickSmart 310\n\t0901  ClickSmart 510\n\t0903  ClickSmart 820\n\t0905  ClickSmart 820\n\t0910  QuickCam Cordless\n\t0920  QuickCam Express\n\t0921  Labtec Webcam\n\t0922  QuickCam Live\n\t0928  QuickCam Express\n\t0929  Labtec Webcam Pro\n\t092a  QuickCam for Notebooks\n\t092b  Labtec Webcam Plus\n\t092c  QuickCam Chat\n\t092d  QuickCam Express / Go\n\t092e  QuickCam Chat\n\t092f  QuickCam Express Plus\n\t0950  Pocket Camera\n\t0960  ClickSmart 420\n\t0970  Pocket750\n\t0990  QuickCam Pro 9000\n\t0991  QuickCam Pro for Notebooks\n\t0992  QuickCam Communicate Deluxe\n\t0994  QuickCam Orbit/Sphere AF\n\t09a1  QuickCam Communicate MP/S5500\n\t09a2  QuickCam Communicate Deluxe/S7500\n\t09a4  QuickCam E 3500\n\t09a5  Quickcam 3000 For Business\n\t09a6  QuickCam Vision Pro\n\t09b0  Acer OrbiCam\n\t09b2  Fujitsu Webcam\n\t09c0  QuickCam for Dell Notebooks Mic\n\t09c1  QuickCam Deluxe for Notebooks\n\t0a01  USB Headset\n\t0a02  Premium Stereo USB Headset 350\n\t0a03  Logitech USB Microphone\n\t0a04  V20 portable speakers (USB powered)\n\t0a07  Z-10 Speakers\n\t0a0b  ClearChat Pro USB\n\t0a0c  Clear Chat Comfort USB Headset\n\t0a13  Z-5 Speakers\n\t0a14  USB Headset\n\t0a15  G35 Headset\n\t0a17  G330 Headset\n\t0a1f  G930\n\t0a29  H600 [Wireless Headset]\n\t0a37  USB Headset H540\n\t0a38  Headset H340\n\t0a44  Headset H390\n\t0a45  960 Headset\n\t0a4d  G430 Surround Sound Gaming Headset\n\t0a5b  G933 Wireless Headset Dongle\n\t0a66  [G533 Wireless Headset Dongle]\n\t0b02  C-UV35 [Bluetooth Mini-Receiver] (HID proxy mode)\n\t8801  Video Camera\n\tb014  Bluetooth Mouse M336/M337/M535\n\tb305  BT Mini-Receiver\n\tbfe4  Premium Optical Wheel Mouse\n\tc000  N43 [Pilot Mouse]\n\tc001  N48/M-BB48/M-UK96A [FirstMouse Plus]\n\tc002  M-BA47 [MouseMan Plus]\n\tc003  MouseMan\n\tc004  WingMan Gaming Mouse\n\tc005  WingMan Gaming Wheel Mouse\n\tc00b  MouseMan Wheel\n\tc00c  Optical Wheel Mouse\n\tc00d  MouseMan Wheel+\n\tc00e  M-BJ58/M-BJ69 Optical Wheel Mouse\n\tc00f  MouseMan Traveler/Mobile\n\tc011  Optical MouseMan\n\tc012  Mouseman Dual Optical\n\tc014  Corded Workstation Mouse\n\tc015  Corded Workstation Mouse\n\tc016  Optical Wheel Mouse\n\tc018  Optical Wheel Mouse\n\tc019  Optical Tilt Wheel Mouse\n\tc01a  M-BQ85 Optical Wheel Mouse\n\tc01b  MX310 Optical Mouse\n\tc01c  Optical Mouse\n\tc01d  MX510 Optical Mouse\n\tc01e  MX518 Optical Mouse\n\tc024  MX300 Optical Mouse\n\tc025  MX500 Optical Mouse\n\tc030  iFeel Mouse\n\tc031  iFeel Mouse+\n\tc032  MouseMan iFeel\n\tc033  iFeel MouseMan+\n\tc034  MouseMan Optical\n\tc035  Mouse\n\tc036  Mouse\n\tc037  Mouse\n\tc038  Mouse\n\tc03d  M-BT96a Pilot Optical Mouse\n\tc03e  Premium Optical Wheel Mouse (M-BT58)\n\tc03f  M-BT85 [UltraX Optical Mouse]\n\tc040  Corded Tilt-Wheel Mouse\n\tc041  G5 Laser Mouse\n\tc042  G3 Laser Mouse\n\tc043  MX320/MX400 Laser Mouse\n\tc044  LX3 Optical Mouse\n\tc045  Optical Mouse\n\tc046  RX1000 Laser Mouse\n\tc047  Laser Mouse M-UAL120\n\tc048  G9 Laser Mouse\n\tc049  G5 Laser Mouse\n\tc050  RX 250 Optical Mouse\n\tc051  G3 (MX518) Optical Mouse\n\tc053  Laser Mouse\n\tc054  Bluetooth mini-receiver\n\tc058  M115 Mouse\n\tc05a  M90/M100 Optical Mouse\n\tc05b  M-U0004 810-001317 [B110 Optical USB Mouse]\n\tc05d  Optical Mouse\n\tc05f  M115 Optical Mouse\n\tc061  RX1500 Laser Mouse\n\tc062  M-UAS144 [LS1 Laser Mouse]\n\tc063  DELL Laser Mouse\n\tc064  M110 corded optical mouse (M-B0001)\n\tc066  G9x Laser Mouse\n\tc068  G500 Laser Mouse\n\tc069  M-U0007 [Corded Mouse M500]\n\tc06a  USB Optical Mouse\n\tc06b  G700 Wireless Gaming Mouse\n\tc06c  Optical Mouse\n\tc077  M105 Optical Mouse\n\tc07c  M-R0017 [G700s Rechargeable Gaming Mouse]\n\tc07d  G502 Mouse\n\tc07e  G402 Gaming Mouse\n\tc080  G303 Gaming Mouse\n\tc083  G403 Prodigy Gaming Mouse\n\tc084  G203 Gaming Mouse\n\tc101  UltraX Media Remote\n\tc110  Harmony 785/880/885 Remote\n\tc111  Harmony 525 Remote\n\tc112  Harmony 890 Remote\n\tc11f  Harmony 900/1100 Remote\n\tc121  Harmony One Remote\n\tc122  Harmony 650/700 Remote\n\tc124  Harmony 300/350 Remote\n\tc125  Harmony 200 Remote\n\tc126  Harmony Link\n\tc129  Harmony Hub\n\tc12b  Harmony Touch/Ultimate Remote\n\tc201  WingMan Extreme Joystick with Throttle\n\tc202  WingMan Formula\n\tc207  WingMan Extreme Digital 3D\n\tc208  WingMan Gamepad Extreme\n\tc209  WingMan Gamepad\n\tc20a  WingMan RumblePad\n\tc20b  WingMan Action Pad\n\tc20c  WingMan Precision\n\tc20d  WingMan Attack 2\n\tc20e  WingMan Formula GP\n\tc211  iTouch Cordless Receiver\n\tc212  WingMan Extreme Digital 3D\n\tc213  J-UH16 (Freedom 2.4 Cordless Joystick)\n\tc214  ATK3 (Attack III Joystick)\n\tc215  Extreme 3D Pro\n\tc216  F310 Gamepad [DirectInput Mode]\n\tc218  F510 Gamepad [DirectInput Mode]\n\tc219  F710 Gamepad [DirectInput Mode]\n\tc21a  Precision Gamepad\n\tc21c  G13 Advanced Gameboard\n\tc21d  F310 Gamepad [XInput Mode]\n\tc21e  F510 Gamepad [XInput Mode]\n\tc21f  F710 Wireless Gamepad [XInput Mode]\n\tc221  G11/G15 Keyboard / Keyboard\n\tc222  G15 Keyboard / LCD\n\tc223  G11/G15 Keyboard / USB Hub\n\tc225  G11/G15 Keyboard / G keys\n\tc226  G15 Refresh Keyboard\n\tc227  G15 Refresh Keyboard\n\tc228  G19 Gaming Keyboard\n\tc229  G19 Gaming Keyboard Macro Interface\n\tc22a  Gaming Keyboard G110\n\tc22b  Gaming Keyboard G110 G-keys\n\tc22d  G510 Gaming Keyboard\n\tc22e  G510 Gaming Keyboard onboard audio\n\tc231  G13 Virtual Mouse\n\tc245  G400 Optical Mouse\n\tc246  Gaming Mouse G300\n\tc248  G105 Gaming Keyboard\n\tc24a  G600 Gaming Mouse\n\tc24c  G400s Optical Mouse\n\tc24d  G710 Gaming Keyboard\n\tc24e  G500s Laser Gaming Mouse\n\tc281  WingMan Force\n\tc283  WingMan Force 3D\n\tc285  WingMan Strike Force 3D\n\tc286  Force 3D Pro\n\tc287  Flight System G940\n\tc291  WingMan Formula Force\n\tc293  WingMan Formula Force GP\n\tc294  Driving Force\n\tc295  Momo Force Steering Wheel\n\tc298  Driving Force Pro\n\tc299  G25 Racing Wheel\n\tc29b  G27 Racing Wheel\n\tc29c  Speed Force Wireless Wheel for Wii\n\tc2a0  Wingman Force Feedback Mouse\n\tc2a1  WingMan Force Feedback Mouse\n\tc2ab  G13 Joystick\n\tc301  iTouch Keyboard\n\tc302  iTouch Pro Keyboard\n\tc303  iTouch Keyboard\n\tc305  Internet Keyboard\n\tc307  Internet Keyboard\n\tc308  Internet Navigator Keyboard\n\tc309  Y-BF37 [Internet Navigator Keyboard]\n\tc30a  iTouch Composite\n\tc30b  NetPlay Keyboard\n\tc30c  Internet Keys (X)\n\tc30d  Internet Keys\n\tc30e  UltraX Keyboard (Y-BL49)\n\tc30f  Logicool HID-Compliant Keyboard (106 key)\n\tc311  Y-UF49 [Internet Pro Keyboard]\n\tc312  DeLuxe 250 Keyboard\n\tc313  Internet 350 Keyboard\n\tc315  Classic Keyboard 200\n\tc316  HID-Compliant Keyboard\n\tc317  Wave Corded Keyboard\n\tc318  Illuminated Keyboard\n\tc31a  Comfort Wave 450\n\tc31b  Compact Keyboard K300\n\tc31c  Keyboard K120\n\tc31d  Media Keyboard K200\n\tc31f  Comfort Keyboard K290\n\tc326  Washable Keyboard K310\n\tc328  Corded Keyboard K280e\n\tc332  G502 Proteus Spectrum Optical Mouse\n\tc335  G910 Orion Spectrum Mechanical Keyboard\n\tc33a  G413 Gaming Keyboard\n\tc401  TrackMan Marble Wheel\n\tc402  Marble Mouse (2-button)\n\tc403  Turbo TrackMan Marble FX\n\tc404  TrackMan Wheel\n\tc408  Marble Mouse (4-button)\n\tc501  Cordless Mouse Receiver\n\tc502  Cordless Mouse & iTouch Keys\n\tc503  Cordless Mouse+Keyboard Receiver\n\tc504  Cordless Mouse+Keyboard Receiver\n\tc505  Cordless Mouse+Keyboard Receiver\n\tc506  MX700 Cordless Mouse Receiver\n\tc508  Cordless Trackball\n\tc509  Cordless Keyboard & Mouse\n\tc50a  Cordless Mouse\n\tc50b  Cordless Desktop Optical\n\tc50c  Cordless Desktop S510\n\tc50d  Cordless Mouse\n\tc50e  Cordless Mouse Receiver\n\tc510  Cordless Mouse\n\tc512  LX-700 Cordless Desktop Receiver\n\tc513  MX3000 Cordless Desktop Receiver\n\tc514  Cordless Mouse\n\tc515  Cordless 2.4 GHz Presenter Presentation remote control\n\tc517  LX710 Cordless Desktop Laser\n\tc518  MX610 Laser Cordless Mouse\n\tc51a  MX Revolution/G7 Cordless Mouse\n\tc51b  V220 Cordless Optical Mouse for Notebooks\n\tc521  Cordless Mouse Receiver\n\tc525  MX Revolution Cordless Mouse\n\tc526  Nano Receiver\n\tc529  Logitech Keyboard + Mice\n\tc52b  Unifying Receiver\n\tc52d  R700 Remote Presenter receiver\n\tc52e  MK260 Wireless Combo Receiver\n\tc52f  Unifying Receiver\n\tc531  C-U0007 [Unifying Receiver]\n\tc532  Unifying Receiver\n\tc534  Unifying Receiver\n\tc603  3Dconnexion Spacemouse Plus XT\n\tc605  3Dconnexion CADman\n\tc606  3Dconnexion Spacemouse Classic\n\tc621  3Dconnexion Spaceball 5000\n\tc623  3Dconnexion Space Traveller 3D Mouse\n\tc625  3Dconnexion Space Pilot 3D Mouse\n\tc626  3Dconnexion Space Navigator 3D Mouse\n\tc627  3Dconnexion Space Explorer 3D Mouse\n\tc628  3Dconnexion Space Navigator for Notebooks\n\tc629  3Dconnexion SpacePilot Pro 3D Mouse\n\tc62b  3Dconnexion Space Mouse Pro\n\tc640  NuLOOQ navigator\n\tc702  Cordless Presenter\n\tc703  Elite Keyboard Y-RP20 + Mouse MX900 (Bluetooth)\n\tc704  diNovo Wireless Desktop\n\tc705  MX900 Bluetooth Wireless Hub (C-UJ16A)\n\tc707  Bluetooth wireless hub\n\tc708  Bluetooth wireless hub\n\tc709  BT Mini-Receiver (HCI mode)\n\tc70a  MX5000 Cordless Desktop\n\tc70b  BT Mini-Receiver (HID proxy mode)\n\tc70c  BT Mini-Receiver (HID proxy mode)\n\tc70d  Bluetooth wireless hub\n\tc70e  MX1000 Bluetooth Laser Mouse\n\tc70f  Bluetooth wireless hub\n\tc712  Bluetooth wireless hub\n\tc714  diNovo Edge Keyboard\n\tc715  Bluetooth wireless hub\n\tc71a  Bluetooth wireless hub\n\tc71d  Bluetooth wireless hub\n\tc71f  diNovo Mini Wireless Keyboard\n\tc720  Bluetooth wireless hub\n\tca03  MOMO Racing\n\tca04  Formula Vibration Feedback Wheel\n\tca84  Cordless Controller for Xbox\n\tca88  Thunderpad for Xbox\n\tca8a  Precision Vibration Feedback Wheel for Xbox\n\tcaa3  DriveFX Racing Wheel\n\tcab1  Cordless Keyboard for Wii HID Receiver\n\td001  QuickCam Pro\n\tf301  Controller\n"
  },
  {
    "path": "lib/hid_parser/__init__.py",
    "content": "# SPDX-License-Identifier: MIT\n\nfrom __future__ import annotations  # noqa:F407\n\nimport functools\nimport struct\nimport sys\nimport textwrap\nimport typing\nimport warnings\n\nfrom typing import Any\nfrom typing import Dict\nfrom typing import Iterable\nfrom typing import Iterator\nfrom typing import List\nfrom typing import Literal\nfrom typing import Optional\nfrom typing import Sequence\nfrom typing import TextIO\nfrom typing import Tuple\nfrom typing import Union\n\nimport hid_parser.data\n\n__version__ = \"0.0.3\"\n\n\nclass HIDWarning(Warning):\n    pass\n\n\nclass HIDComplianceWarning(HIDWarning):\n    pass\n\n\nclass HIDReportWarning(HIDWarning):\n    pass\n\n\nclass HIDUnsupportedWarning(HIDWarning):\n    pass\n\n\nclass Type:\n    MAIN = 0\n    GLOBAL = 1\n    LOCAL = 2\n\n\nclass TagMain:\n    INPUT = 0b1000\n    OUTPUT = 0b1001\n    FEATURE = 0b1011\n    COLLECTION = 0b1010\n    END_COLLECTION = 0b1100\n\n\nclass TagGlobal:\n    USAGE_PAGE = 0b0000\n    LOGICAL_MINIMUM = 0b0001\n    LOGICAL_MAXIMUM = 0b0010\n    PHYSICAL_MINIMUM = 0b0011\n    PHYSICAL_MAXIMUM = 0b0100\n    UNIT_EXPONENT = 0b0101\n    UNIT = 0b0110\n    REPORT_SIZE = 0b0111\n    REPORT_ID = 0b1000\n    REPORT_COUNT = 0b1001\n    PUSH = 0b1010\n    POP = 0b1011\n\n\nclass TagLocal:\n    USAGE = 0b0000\n    USAGE_MINIMUM = 0b0001\n    USAGE_MAXIMUM = 0b0010\n    DESIGNATOR_INDEX = 0b0011\n    DESIGNATOR_MINIMUM = 0b0100\n    DESIGNATOR_MAXIMUM = 0b0101\n    STRING_INDEX = 0b0111\n    STRING_MINIMUM = 0b1000\n    STRING_MAXIMUM = 0b1001\n    DELIMITER = 0b1010\n\n\ndef _data_bit_shift(data: Sequence[int], offset: int, length: int) -> Sequence[int]:\n    if not length > 0:\n        raise ValueError(f\"Invalid specified length: {length}\")\n\n    left_extra = offset % 8\n    right_extra = 8 - (offset + length) % 8\n    start_offset = offset // 8\n    end_offset = (offset + length - 1) // 8\n    byte_length = (length - 1) // 8 + 1\n\n    if not end_offset < len(data):\n        raise ValueError(f\"Invalid data length: {len(data)} (expecting {end_offset + 1})\")\n\n    shifted = [0] * byte_length\n\n    if right_extra == 8:\n        right_extra = 0\n\n    i = end_offset\n    shifted_offset = byte_length - 1\n    while shifted_offset >= 0:\n        shifted[shifted_offset] = data[i] >> right_extra\n\n        if i - start_offset >= 0:\n            shifted[shifted_offset] |= (data[i - 1] & (0xFF >> (8 - right_extra))) << (8 - right_extra)\n\n        shifted_offset -= 1\n        i -= 1\n\n    shifted[0] &= 0xFF >> ((left_extra + right_extra) % 8)\n\n    if not len(shifted) == byte_length:\n        raise ValueError(\"Invalid data\")\n\n    return shifted\n\n\nclass BitNumber(int):\n    def __init__(self, value: int):\n        self._value = value\n\n    def __int__(self) -> int:\n        return self._value\n\n    def __eq__(self, other: Any) -> bool:\n        try:\n            return self._value == int(other)\n        except:  # noqa: E722\n            return False\n\n    @property\n    def byte(self) -> int:\n        \"\"\"\n        Number of bytes\n        \"\"\"\n        return self._value // 8\n\n    @property\n    def bit(self) -> int:\n        \"\"\"\n        Number of unaligned bits\n\n        n.byte * 8 + n.bits = n\n        \"\"\"\n        if self.byte == 0:\n            return self._value\n\n        return self._value % (self.byte * 8)\n\n    @staticmethod\n    def _param_repr(value: int, unit: str) -> str:\n        if value != 1:\n            unit += \"s\"\n        return f\"{value}{unit}\"\n\n    def __repr__(self) -> str:\n        byte_str = self._param_repr(self.byte, \"byte\")\n        bit_str = self._param_repr(self.bit, \"bit\")\n\n        if self.byte == 0 and self.bit == 0:\n            return bit_str\n\n        parts = []\n        if self.byte != 0:\n            parts.append(byte_str)\n        if self.bit != 0:\n            parts.append(bit_str)\n\n        return \" \".join(parts)\n\n\nclass Usage:\n    def __init__(\n        self, page: Optional[int] = None, usage: Optional[int] = None, *, extended_usage: Optional[int] = None\n    ) -> None:\n        if extended_usage and page and usage:\n            raise ValueError(\"You need to specify either the usage page and usage or the extended usage\")\n        if extended_usage is not None:\n            self.page = extended_usage >> (2 * 8)\n            self.usage = extended_usage & 0xFFFF\n        elif page is not None and usage is not None:\n            self.page = page\n            self.usage = usage\n        else:\n            raise ValueError(\"No usage specified\")\n\n    def __int__(self) -> int:\n        return self.page << (2 * 8) | self.usage\n\n    def __eq__(self, other: Any) -> bool:\n        if not isinstance(other, self.__class__):\n            return False\n        return self.page == other.page and self.usage == other.usage\n\n    def __hash__(self) -> int:\n        return self.usage << (2 * 8) + self.page\n\n    def __repr__(self) -> str:\n        try:\n            page_str = hid_parser.data.UsagePages.get_description(self.page)\n        except KeyError:\n            page_str = f\"0x{self.page:04x}\"\n            usage_str = f\"0x{self.usage:04x}\"\n        else:\n            try:\n                page = hid_parser.data.UsagePages.get_subdata(self.page)\n                usage_str = page.get_description(self.usage)\n            except (KeyError, ValueError):\n                usage_str = f\"0x{self.usage:04x}\"\n        return f\"Usage(page={page_str}, usage={usage_str})\"\n\n    @property\n    def usage_types(self) -> Tuple[hid_parser.data.UsageTypes]:\n        subdata = hid_parser.data.UsagePages.get_subdata(self.page).get_subdata(self.usage)\n\n        if isinstance(subdata, tuple):\n            types = subdata\n        else:\n            types = (subdata,)\n\n        for typ in types:\n            if not isinstance(typ, hid_parser.data.UsageTypes):\n                raise ValueError(f\"Expecting usage type but got '{type(typ)}'\")\n\n        return typing.cast(Tuple[hid_parser.data.UsageTypes], types)\n\n\nclass UsageValue:\n    def __init__(self, item: MainItem, value: int):\n        self._item = item\n        self._value = value\n\n    def __int__(self) -> int:\n        return self.value\n\n    def __repr__(self) -> str:\n        return repr(self.value)\n\n    @property\n    def value(self) -> Union[int, bool]:\n        return self._value\n\n    @property\n    def constant(self) -> bool:\n        return self._item.constant\n\n    @property\n    def data(self) -> bool:\n        return self._item.data\n\n    @property\n    def relative(self) -> bool:\n        return self._item.relative\n\n    @property\n    def absolute(self) -> bool:\n        return self._item.absolute\n\n\nclass VendorUsageValue(UsageValue):\n    def __init__(\n        self,\n        item: MainItem,\n        *,\n        value: Optional[int] = None,\n        value_list: Optional[List[int]] = None,\n    ):\n        self._item = item\n        if value:\n            self._list = [value]\n        elif value_list:\n            self._list = value_list\n        else:\n            self._list = []\n\n    def __int__(self) -> int:\n        return self.value\n\n    def __iter__(self) -> Iterator[int]:\n        return iter(self.list)\n\n    @property\n    def value(self) -> Union[int, bool]:\n        return int.from_bytes(self._list, byteorder=\"little\")\n\n    @property\n    def list(self) -> List[int]:\n        return self._list\n\n\nclass BaseItem:\n    def __init__(self, offset: int, size: int):\n        self._offset = BitNumber(offset)\n        self._size = BitNumber(size)\n\n    @property\n    def offset(self) -> BitNumber:\n        return self._offset\n\n    @property\n    def size(self) -> BitNumber:\n        return self._size\n\n    def __repr__(self) -> str:\n        return f\"{self.__class__.__name__}(offset={self.offset}, size={self.size})\"\n\n\nclass PaddingItem(BaseItem):\n    pass\n\n\nclass MainItem(BaseItem):\n    def __init__(\n        self,\n        offset: int,\n        size: int,\n        flags: int,\n        logical_min: int,\n        logical_max: int,\n        physical_min: Optional[int] = None,\n        physical_max: Optional[int] = None,\n    ):\n        super().__init__(offset, size)\n        self._flags = flags\n        self._logical_min = logical_min\n        self._logical_max = logical_max\n        self._physical_min = physical_min\n        self._physical_max = physical_max\n        # TODO: unit\n\n    @property\n    def offset(self) -> BitNumber:\n        return self._offset\n\n    @property\n    def size(self) -> BitNumber:\n        return self._size\n\n    @property\n    def logical_min(self) -> int:\n        return self._logical_min\n\n    @property\n    def logical_max(self) -> int:\n        return self._logical_max\n\n    @property\n    def physical_min(self) -> Optional[int]:\n        return self._physical_min\n\n    @property\n    def physical_max(self) -> Optional[int]:\n        return self._physical_max\n\n    # flags\n\n    @property\n    def constant(self) -> bool:\n        return self._flags & (1 << 0) != 0\n\n    @property\n    def data(self) -> bool:\n        return self._flags & (1 << 0) == 0\n\n    @property\n    def relative(self) -> bool:\n        return self._flags & (1 << 2) != 0\n\n    @property\n    def absolute(self) -> bool:\n        return self._flags & (1 << 2) == 0\n\n\nclass VariableItem(MainItem):\n    _INCOMPATIBLE_TYPES = (\n        # array types\n        hid_parser.data.UsageTypes.SELECTOR,\n        # collection types\n        hid_parser.data.UsageTypes.NAMED_ARRAY,\n        hid_parser.data.UsageTypes.COLLECTION_APPLICATION,\n        hid_parser.data.UsageTypes.COLLECTION_LOGICAL,\n        hid_parser.data.UsageTypes.COLLECTION_PHYSICAL,\n        hid_parser.data.UsageTypes.USAGE_SWITCH,\n        hid_parser.data.UsageTypes.USAGE_MODIFIER,\n    )\n\n    def __init__(\n        self,\n        offset: int,\n        size: int,\n        flags: int,\n        usage: Usage,\n        logical_min: int,\n        logical_max: int,\n        physical_min: Optional[int] = None,\n        physical_max: Optional[int] = None,\n    ):\n        super().__init__(offset, size, flags, logical_min, logical_max, physical_min, physical_max)\n        self._usage = usage\n\n        try:\n            if all(usage_type in self._INCOMPATIBLE_TYPES for usage_type in usage.usage_types):\n                warnings.warn(HIDComplianceWarning(f\"{usage} has no compatible usage types with a variable item\"))  # noqa\n        except (KeyError, ValueError):\n            pass\n\n    def __repr__(self) -> str:\n        return f\"VariableItem(offset={self.offset}, size={self.size}, usage={self.usage})\"\n\n    def parse(self, data: Sequence[int]) -> UsageValue:\n        data = _data_bit_shift(data, self.offset, self.size)\n\n        if hid_parser.data.UsageTypes.LINEAR_CONTROL in self.usage.usage_types or any(\n            usage_type in hid_parser.data.UsageTypesData and usage_type != hid_parser.data.UsageTypes.SELECTOR\n            for usage_type in self.usage.usage_types\n        ):  # int\n            value = int.from_bytes(data, byteorder=\"little\")\n        elif (\n            hid_parser.data.UsageTypes.ON_OFF_CONTROL in self.usage.usage_types\n            and not self.preferred_state\n            and self.logical_min == -1\n            and self.logical_max == 1\n        ):  # bool - -1 is false\n            value = int.from_bytes(data, byteorder=\"little\") == 1\n        else:  # bool\n            value = bool.from_bytes(data, byteorder=\"little\")\n\n        return UsageValue(self, value)\n\n    @property\n    def usage(self) -> Usage:\n        return self._usage\n\n    # flags (variable only, see HID spec 1.11 page 32)\n\n    @property\n    def wrap(self) -> bool:\n        return self._flags & (1 << 3) != 0\n\n    @property\n    def linear(self) -> bool:\n        return self._flags & (1 << 4) != 0\n\n    @property\n    def preferred_state(self) -> bool:\n        return self._flags & (1 << 5) != 0\n\n    @property\n    def null_state(self) -> bool:\n        return self._flags & (1 << 6) != 0\n\n    @property\n    def buffered_bytes(self) -> bool:\n        return self._flags & (1 << 7) != 0\n\n    @property\n    def bitfield(self) -> bool:\n        return self._flags & (1 << 7) == 0\n\n\nclass ArrayItem(MainItem):\n    _INCOMPATIBLE_TYPES = (\n        # variable types\n        hid_parser.data.UsageTypes.LINEAR_CONTROL,\n        hid_parser.data.UsageTypes.ON_OFF_CONTROL,\n        hid_parser.data.UsageTypes.MOMENTARY_CONTROL,\n        hid_parser.data.UsageTypes.ONE_SHOT_CONTROL,\n        hid_parser.data.UsageTypes.RE_TRIGGER_CONTROL,\n        hid_parser.data.UsageTypes.STATIC_VALUE,\n        hid_parser.data.UsageTypes.STATIC_FLAG,\n        hid_parser.data.UsageTypes.DYNAMIC_VALUE,\n        hid_parser.data.UsageTypes.DYNAMIC_FLAG,\n        # collection types\n        hid_parser.data.UsageTypes.NAMED_ARRAY,\n        hid_parser.data.UsageTypes.COLLECTION_APPLICATION,\n        hid_parser.data.UsageTypes.COLLECTION_LOGICAL,\n        hid_parser.data.UsageTypes.COLLECTION_PHYSICAL,\n        hid_parser.data.UsageTypes.USAGE_SWITCH,\n        hid_parser.data.UsageTypes.USAGE_MODIFIER,\n    )\n    _IGNORE_USAGE_VALUES = ((hid_parser.data.UsagePages.KEYBOARD_KEYPAD_PAGE, hid_parser.data.KeyboardKeypad.NO_EVENT),)\n\n    def __init__(\n        self,\n        offset: int,\n        size: int,\n        count: int,\n        flags: int,\n        usages: List[Usage],\n        logical_min: int,\n        logical_max: int,\n        physical_min: Optional[int] = None,\n        physical_max: Optional[int] = None,\n    ):\n        super().__init__(offset, size, flags, logical_min, logical_max, physical_min, physical_max)\n        self._count = count\n        self._usages = usages\n        self._page = self._usages[0].page if usages else None\n\n        for usage in self._usages:\n            if usage.page != self._page:\n                raise ValueError(f\"Mismatching usage page in usage: {usage} (expecting {self._usages[0]})\")\n            try:\n                if all(usage_type in self._INCOMPATIBLE_TYPES for usage_type in usage.usage_types):\n                    warnings.warn(HIDComplianceWarning(f\"{usage} has no compatible usage types with an array item\"))  # noqa\n            except (KeyError, ValueError):\n                pass\n\n        self._ignore_usages: List[Usage] = []\n        for page, usage_id in self._IGNORE_USAGE_VALUES:\n            assert isinstance(page, int) and isinstance(usage_id, int)\n            self._ignore_usages.append(Usage(page, usage_id))\n\n    def __repr__(self) -> str:\n        return (\n            textwrap.dedent(\n                \"\"\"\n            ArrayItem(\n                offset={}, size={}, count={},\n                usages=[\n                    {},\n                ],\n            )\n        \"\"\"\n            )\n            .strip()\n            .format(\n                self.offset,\n                self.size,\n                self.count,\n                \",\\n        \".join(repr(usage) for usage in self.usages),\n            )\n        )\n\n    def parse(self, data: Sequence[int]) -> Dict[Usage, UsageValue]:\n        usage_values: Dict[Usage, UsageValue] = {}\n\n        for i in range(self.count):\n            aligned_data = _data_bit_shift(data, self.offset + i * 8, self.size)\n            usage = Usage(self._page, int.from_bytes(aligned_data, byteorder=\"little\"))\n\n            if usage in self._ignore_usages:\n                continue\n\n            # vendor usages don't have usage any standard type - just save the raw data\n            if usage.page in hid_parser.data.UsagePages.VENDOR_PAGE:\n                if usage not in usage_values:\n                    usage_values[usage] = VendorUsageValue(\n                        self,\n                        value=int.from_bytes(aligned_data, byteorder=\"little\"),\n                    )\n                typing.cast(VendorUsageValue, usage_values[usage]).list.append(\n                    int.from_bytes(aligned_data, byteorder=\"little\")\n                )\n                continue\n\n            not_incompatible_type = all(usage_type not in self._INCOMPATIBLE_TYPES for usage_type in usage.usage_types)\n            if usage in self._usages and not_incompatible_type:\n                usage_values[usage] = UsageValue(self, True)\n\n        return usage_values\n\n    @property\n    def count(self) -> int:\n        return self._count\n\n    @property\n    def usages(self) -> List[Usage]:\n        return self._usages\n\n\nclass InvalidReportDescriptor(Exception):\n    pass\n\n\n# report ID (None for no report ID), item list\n_ITEM_POOL = Dict[Optional[int], List[BaseItem]]\n\n\nclass ReportDescriptor:\n    def __init__(self, data: Sequence[int]) -> None:\n        self._data = data\n\n        for byte in data:\n            if byte < 0 or byte > 255:\n                raise InvalidReportDescriptor(\n                    f\"A report descriptor should be represented by a list of bytes: found value {byte}\"\n                )\n\n        self._input: _ITEM_POOL = {}\n        self._output: _ITEM_POOL = {}\n        self._feature: _ITEM_POOL = {}\n\n        self._parse()\n\n    @property\n    def data(self) -> Sequence[int]:\n        return self._data\n\n    @property\n    def input_report_ids(self) -> List[Optional[int]]:\n        return list(self._input.keys())\n\n    @property\n    def output_report_ids(self) -> List[Optional[int]]:\n        return list(self._output.keys())\n\n    @property\n    def feature_report_ids(self) -> List[Optional[int]]:\n        return list(self._feature.keys())\n\n    def _get_report_size(self, items: List[BaseItem]) -> BitNumber:\n        size = 0\n        for item in items:\n            if isinstance(item, ArrayItem):\n                size += item.size * item.count\n            else:\n                size += item.size\n        return BitNumber(size)\n\n    def get_input_items(self, report_id: Optional[int] = None) -> List[BaseItem]:\n        return self._input[report_id]\n\n    @functools.lru_cache(maxsize=16)  # noqa\n    def get_input_report_size(self, report_id: Optional[int] = None) -> BitNumber:\n        return self._get_report_size(self.get_input_items(report_id))\n\n    def get_output_items(self, report_id: Optional[int] = None) -> List[BaseItem]:\n        return self._output[report_id]\n\n    @functools.lru_cache(maxsize=16)  # noqa\n    def get_output_report_size(self, report_id: Optional[int] = None) -> BitNumber:\n        return self._get_report_size(self.get_output_items(report_id))\n\n    def get_feature_items(self, report_id: Optional[int] = None) -> List[BaseItem]:\n        return self._feature[report_id]\n\n    @functools.lru_cache(maxsize=16)  # noqa\n    def get_feature_report_size(self, report_id: Optional[int] = None) -> BitNumber:\n        return self._get_report_size(self.get_feature_items(report_id))\n\n    def _parse_report_items(self, items: List[BaseItem], data: Sequence[int]) -> Dict[Usage, UsageValue]:\n        parsed: Dict[Usage, UsageValue] = {}\n        for item in items:\n            if isinstance(item, VariableItem):\n                parsed[item.usage] = item.parse(data)\n            elif isinstance(item, ArrayItem):\n                usage_values = item.parse(data)\n                for usage in usage_values:\n                    if usage in parsed:\n                        warnings.warn(HIDReportWarning(f\"Overriding usage: {usage}\"))  # noqa\n                parsed.update(usage_values)\n            elif isinstance(item, PaddingItem):\n                pass\n            else:\n                raise TypeError(f\"Unknown item: {item}\")\n        return parsed\n\n    def _parse_report(self, item_poll: _ITEM_POOL, data: Sequence[int]) -> Dict[Usage, UsageValue]:\n        if None in item_poll:  # unnumbered reports\n            return self._parse_report_items(item_poll[None], data)\n        else:  # numbered reports\n            return self._parse_report_items(item_poll[data[0]], data[1:])\n\n    def parse_input_report(self, data: Sequence[int]) -> Dict[Usage, UsageValue]:\n        return self._parse_report(self._input, data)\n\n    def parse_output_report(self, data: Sequence[int]) -> Dict[Usage, UsageValue]:\n        return self._parse_report(self._output, data)\n\n    def parse_feature_report(self, data: Sequence[int]) -> Dict[Usage, UsageValue]:\n        return self._parse_report(self._feature, data)\n\n    def _iterate_raw(self) -> Iterable[Tuple[int, int, Optional[int]]]:\n        i = 0\n        while i < len(self.data):\n            prefix = self.data[i]\n            tag = (prefix & 0b11110000) >> 4\n            typ = (prefix & 0b00001100) >> 2\n            size = prefix & 0b00000011\n\n            if size == 3:  # 6.2.2.2\n                size = 4\n\n            if size == 0:\n                data = None\n            elif size == 1:\n                if i + 1 >= len(self.data):\n                    raise InvalidReportDescriptor(f\"Invalid size: expecting >={i + 1}, got {len(self.data)}\")\n                data = self.data[i + 1]\n            else:\n                if i + 1 + size >= len(self.data):\n                    raise InvalidReportDescriptor(f\"Invalid size: expecting >={i + 1 + size}, got {len(self.data)}\")\n                if size == 2:\n                    pack_type = \"H\"\n                elif size == 4:\n                    pack_type = \"L\"\n                else:\n                    raise ValueError(f\"Invalid item size: {size}\")\n                data = struct.unpack(f\"<{pack_type}\", bytes(self.data[i + 1 : i + 1 + size]))[0]\n\n            yield typ, tag, data\n\n            i += size + 1\n\n    def _append_item(\n        self,\n        offset_list: Dict[Optional[int], int],\n        pool: _ITEM_POOL,\n        report_id: Optional[int],\n        item: BaseItem,\n    ) -> None:\n        offset_list[report_id] += item.size\n        if report_id in pool:\n            pool[report_id].append(item)\n        else:\n            pool[report_id] = [item]\n\n    def _append_items(\n        self,\n        offset_list: Dict[Optional[int], int],\n        pool: _ITEM_POOL,\n        report_id: Optional[int],\n        report_count: int,\n        report_size: int,\n        usages: List[Usage],\n        flags: int,\n        data: Dict[str, Any],\n    ) -> None:\n        item: BaseItem\n        is_array = flags & (1 << 1) == 0  # otherwise variable\n\n        \"\"\"\n        HID 1.11, 6.2.2.9 says reports can be byte aligned by declaring a\n        main item without usage. A main item can have multiple usages, as I\n        interpret it, items are only considered padding when they have NO\n        usages.\n        \"\"\"\n        if len(usages) == 0 or not usages:\n            for _ in range(report_count):\n                item = PaddingItem(offset_list[report_id], report_size)\n                self._append_item(offset_list, pool, report_id, item)\n            return\n\n        if is_array:\n            item = ArrayItem(\n                offset=offset_list[report_id],\n                size=report_size,\n                usages=usages,\n                count=report_count,\n                flags=flags,\n                **data,\n            )\n            self._append_item(offset_list, pool, report_id, item)\n        else:\n            if len(usages) != report_count:\n                error_str = f\"Expecting {report_count} usages but got {len(usages)}\"\n                if len(usages) == 1:\n                    warnings.warn(HIDComplianceWarning(error_str))  # noqa\n                    usages *= report_count\n                else:\n                    raise InvalidReportDescriptor(error_str)\n\n            for usage in usages:\n                item = VariableItem(\n                    offset=offset_list[report_id],\n                    size=report_size,\n                    usage=usage,\n                    flags=flags,\n                    **data,\n                )\n                self._append_item(offset_list, pool, report_id, item)\n\n    def _parse(self, level: int = 0, file: TextIO = sys.stdout) -> None:  # noqa: C901\n        offset_input: Dict[Optional[int], int] = {\n            None: 0,\n        }\n        offset_output: Dict[Optional[int], int] = {\n            None: 0,\n        }\n        offset_feature: Dict[Optional[int], int] = {\n            None: 0,\n        }\n        report_id: Optional[int] = None\n        report_count: Optional[int] = None\n        report_size: Optional[int] = None\n        usage_page: Optional[int] = None\n        usages: List[Usage] = []\n        usage_min: Optional[int] = None\n        glob: Dict[str, Any] = {}\n        local: Dict[str, Any] = {}\n\n        for typ, tag, data in self._iterate_raw():\n            if typ == Type.MAIN:\n                if tag in (TagMain.COLLECTION, TagMain.END_COLLECTION):\n                    usages = []\n\n                # we only care about input, output and features for now\n                if tag not in (TagMain.INPUT, TagMain.OUTPUT, TagMain.FEATURE):\n                    continue\n\n                if report_count is None:\n                    raise InvalidReportDescriptor(\"Trying to append an item but no report count given\")\n                if report_size is None:\n                    raise InvalidReportDescriptor(\"Trying to append an item but no report size given\")\n\n                if tag == TagMain.INPUT:\n                    if data is None:\n                        raise InvalidReportDescriptor(\"Invalid input item\")\n                    self._append_items(\n                        offset_input, self._input, report_id, report_count, report_size, usages, data, {**glob, **local}\n                    )\n\n                elif tag == TagMain.OUTPUT:\n                    if data is None:\n                        raise InvalidReportDescriptor(\"Invalid output item\")\n                    self._append_items(\n                        offset_output,\n                        self._output,\n                        report_id,\n                        report_count,\n                        report_size,\n                        usages,\n                        data,\n                        {**glob, **local},\n                    )\n\n                elif tag == TagMain.FEATURE:\n                    if data is None:\n                        raise InvalidReportDescriptor(\"Invalid feature item\")\n                    self._append_items(\n                        offset_feature,\n                        self._feature,\n                        report_id,\n                        report_count,\n                        report_size,\n                        usages,\n                        data,\n                        {**glob, **local},\n                    )\n\n                # clear local\n                usages = []\n                usage_min = None\n                local = {}\n\n                # we don't care about collections for now, maybe in the future...\n\n            elif typ == Type.GLOBAL:\n                if tag == TagGlobal.USAGE_PAGE:\n                    usage_page = data\n\n                elif tag == TagGlobal.LOGICAL_MINIMUM:\n                    glob[\"logical_min\"] = data\n\n                elif tag == TagGlobal.LOGICAL_MAXIMUM:\n                    glob[\"logical_max\"] = data\n\n                elif tag == TagGlobal.PHYSICAL_MINIMUM:\n                    glob[\"physical_min\"] = data\n\n                elif tag == TagGlobal.PHYSICAL_MAXIMUM:\n                    glob[\"physical_max\"] = data\n\n                elif tag == TagGlobal.REPORT_SIZE:\n                    report_size = data\n\n                elif tag == TagGlobal.REPORT_ID:\n                    if not report_id and (self._input or self._output or self._feature):\n                        raise InvalidReportDescriptor(\"Tried to set a report ID in a report that does not use them\")\n                    report_id = data\n                    # initialize the item offset for this report ID\n                    for offset_list in (offset_input, offset_output, offset_feature):\n                        if report_id not in offset_list:\n                            offset_list[report_id] = 0\n\n                elif tag in (TagGlobal.UNIT, TagGlobal.UNIT_EXPONENT):\n                    warnings.warn(  # noqa\n                        HIDUnsupportedWarning(\"Data specifies a unit or unit exponent, but we don't support those yet\")\n                    )\n\n                elif tag in (TagGlobal.PUSH, TagGlobal.POP):\n                    warnings.warn(HIDUnsupportedWarning(\"Push and pop are not supported yet\"))  # noqa\n\n                elif tag == TagGlobal.REPORT_COUNT:\n                    report_count = data\n\n                else:\n                    raise NotImplementedError(f\"Unsupported global tag: {bin(tag)}\")\n\n            elif typ == Type.LOCAL:\n                if tag == TagLocal.USAGE:\n                    if usage_page is None:\n                        raise InvalidReportDescriptor(\"Usage field found but no usage page\")\n                    usages.append(Usage(usage_page, data))\n\n                elif tag == TagLocal.USAGE_MINIMUM:\n                    usage_min = data\n\n                elif tag == TagLocal.USAGE_MAXIMUM:\n                    if usage_min is None:\n                        raise InvalidReportDescriptor(\"Usage maximum set but no usage minimum\")\n                    if data is None:\n                        raise InvalidReportDescriptor(\"Invalid usage maximum value\")\n                    for i in range(usage_min, data + 1):\n                        usages.append(Usage(usage_page, i))\n                    usage_min = None\n\n                elif tag in (TagLocal.STRING_INDEX, TagLocal.STRING_MINIMUM, TagLocal.STRING_MAXIMUM):\n                    pass  # we don't care about this information to parse the reports\n\n                else:\n                    raise NotImplementedError(f\"Unsupported local tag: {bin(tag)}\")\n\n    @staticmethod\n    def _get_main_item_desc(value: int) -> str:\n        fields = [\n            \"Constant\" if value & (1 << 0) else \"Data\",\n            \"Variable\" if value & (1 << 1) else \"Array\",\n            \"Relative\" if value & (1 << 2) else \"Absolute\",\n        ]\n        if value & (1 << 1):\n            # variable only\n            fields += [\n                \"Wrap\" if value & (1 << 3) else \"No Wrap\",\n                \"Non Linear\" if value & (1 << 4) else \"Linear\",\n                \"No Preferred State\" if value & (1 << 5) else \"Preferred State\",\n                \"Null State\" if value & (1 << 6) else \"No Null position\",\n                \"Buffered Bytes\" if value & (1 << 8) else \"Bit Field\",\n            ]\n        return \", \".join(fields)\n\n    def print(self, level: int = 0, file: TextIO = sys.stdout) -> None:  # noqa: C901\n        def printl(string: str) -> None:\n            print(\" \" * level + string, file=file)\n\n        usage_data: Union[Literal[False], Optional[hid_parser.data._Data]] = False\n\n        for typ, tag, data in self._iterate_raw():\n            if typ == Type.MAIN:\n                if tag == TagMain.INPUT:\n                    if data is None:\n                        raise InvalidReportDescriptor(\"Invalid input item\")\n                    printl(f\"Input ({self._get_main_item_desc(data)})\")\n\n                elif tag == TagMain.OUTPUT:\n                    if data is None:\n                        raise InvalidReportDescriptor(\"Invalid output item\")\n                    printl(f\"Output ({self._get_main_item_desc(data)})\")\n\n                elif tag == TagMain.FEATURE:\n                    if data is None:\n                        raise InvalidReportDescriptor(\"Invalid feature item\")\n                    printl(f\"Feature ({self._get_main_item_desc(data)})\")\n\n                elif tag == TagMain.COLLECTION:\n                    printl(f\"Collection ({hid_parser.data.Collections.get_description(data)})\")\n                    level += 1\n\n                elif tag == TagMain.END_COLLECTION:\n                    level -= 1\n                    printl(\"End Collection\")\n\n            elif typ == Type.GLOBAL:\n                if tag == TagGlobal.USAGE_PAGE:\n                    try:\n                        printl(f\"Usage Page ({hid_parser.data.UsagePages.get_description(data)})\")\n                        try:\n                            usage_data = hid_parser.data.UsagePages.get_subdata(data)\n                        except ValueError:\n                            usage_data = None\n                    except KeyError:\n                        printl(f\"Usage Page (Unknown 0x{data:04x})\")\n\n                elif tag == TagGlobal.LOGICAL_MINIMUM:\n                    printl(f\"Logical Minimum ({data})\")\n\n                elif tag == TagGlobal.LOGICAL_MAXIMUM:\n                    printl(f\"Logical Maximum ({data})\")\n\n                elif tag == TagGlobal.PHYSICAL_MINIMUM:\n                    printl(f\"Physical Minimum ({data})\")\n\n                elif tag == TagGlobal.PHYSICAL_MAXIMUM:\n                    printl(f\"Physical Maximum ({data})\")\n\n                elif tag == TagGlobal.UNIT_EXPONENT:\n                    printl(f\"Unit Exponent (0x{data:04x})\")\n\n                elif tag == TagGlobal.UNIT:\n                    printl(f\"Unit (0x{data:04x})\")\n\n                elif tag == TagGlobal.REPORT_SIZE:\n                    printl(f\"Report Size ({data})\")\n\n                elif tag == TagGlobal.REPORT_ID:\n                    printl(f\"Report ID (0x{data:02x})\")\n\n                elif tag == TagGlobal.REPORT_COUNT:\n                    printl(f\"Report Count ({data})\")\n\n                elif tag == TagGlobal.PUSH:\n                    printl(f\"Push ({data})\")\n\n                elif tag == TagGlobal.POP:\n                    printl(f\"Pop ({data})\")\n\n            elif typ == Type.LOCAL:\n                if tag == TagLocal.USAGE:\n                    if usage_data is False:\n                        raise InvalidReportDescriptor(\"Usage field found but no usage page\")\n\n                    if usage_data:\n                        try:\n                            printl(f\"Usage ({usage_data.get_description(data)})\")\n                        except KeyError:\n                            printl(f\"Usage (Unknown, 0x{data:04x})\")\n                    else:\n                        printl(f\"Usage (0x{data:04x})\")\n\n                elif tag == TagLocal.USAGE_MINIMUM:\n                    printl(f\"Usage Minimum ({data})\")\n\n                elif tag == TagLocal.USAGE_MAXIMUM:\n                    printl(f\"Usage Maximum ({data})\")\n\n                elif tag == TagLocal.DESIGNATOR_INDEX:\n                    printl(f\"Designator Index ({data})\")\n\n                elif tag == TagLocal.DESIGNATOR_MINIMUM:\n                    printl(f\"Designator Minimum ({data})\")\n\n                elif tag == TagLocal.DESIGNATOR_MAXIMUM:\n                    printl(f\"Designator Maximum ({data})\")\n\n                elif tag == TagLocal.STRING_INDEX:\n                    printl(f\"String Index ({data})\")\n\n                elif tag == TagLocal.STRING_MINIMUM:\n                    printl(f\"String Minimum ({data})\")\n\n                elif tag == TagLocal.STRING_MAXIMUM:\n                    printl(f\"String Maximum ({data})\")\n\n                elif tag == TagLocal.DELIMITER:\n                    printl(f\"Delemiter ({data})\")\n"
  },
  {
    "path": "lib/hid_parser/data.py",
    "content": "# SPDX-License-Identifier: MIT\n\nimport enum\n\nfrom typing import Any\nfrom typing import Dict\nfrom typing import List\nfrom typing import Optional\nfrom typing import Tuple\n\n\nclass _DataMeta(type):\n    \"\"\"\n    This metaclass populates _single and _range, following the structure described bellow\n\n    The class should declare data as follows\n\n        MY_DATA_VALUE = 0x01, 'Data description'\n\n    or, for ranges,\n\n        MY_DATA_RANGE = 0x02, ..., 0x06, 'Data range description'\n\n    _single and _range will then be populated with\n\n        MY_DATA_VALUE = 0x01\n        _single[0x01] = ('Data description', None)\n        MY_DATA_RANGE = range(0x02, 0x06+1)\n        _range.append(tuple(0x02, 0x06, ('Data range description', None)))\n\n    As you can see, for single data insertions, the variable will be kept with\n    the first value of the tuple. Both single and range data insertions will\n    register the data into the correspondent data holders.\n\n    You can also define subdata,\n\n        MY_DATA_VALUE = 0x01, 'Data description', OTHER_DATA_TYPE\n        MY_DATA_RANGE = 0x02, ..., 0x06, 'Data range description', YET_OTHER_DATA_TYPE\n\n    Which will result in\n\n        MY_DATA_VALUE = 0x01\n        _single[0x01] = ('Data description', OTHER_DATA_TYPE)\n        _range.append(tuple(0x02, 0x06, ('Data range description', YET_OTHER_DATA_TYPE)))\n\n    This metaclass also does some verification to prevent duplicated data.\n    \"\"\"\n\n    def __new__(mcs, name: str, bases: Tuple[Any], dic: Dict[str, Any]):  # type: ignore  # noqa: C901\n        dic[\"_single\"] = {}\n        dic[\"_range\"] = []\n\n        # allow constructing data via a data dictionary as opposed to directly in the object body\n        if \"data\" in dic:\n            data = dic.pop(\"data\")\n        else:\n            data = dic\n\n        for attr in data:\n            if not attr.startswith(\"_\") and isinstance(data[attr], tuple):\n                if len(data[attr]) == 2 or len(data[attr]) == 4:  # missing sub data\n                    data[attr] = data[attr] + (None,)\n\n                if len(data[attr]) == 3:  # single\n                    num, desc, sub = data[attr]\n\n                    if not isinstance(num, int):\n                        raise TypeError(f\"First element of '{attr}' should be an int\")\n                    if not isinstance(desc, str):\n                        raise TypeError(f\"Second element of '{attr}' should be a string\")\n\n                    if num in dic[\"_single\"]:\n                        raise ValueError(f\"Duplicated value in '{attr}' ({num})\")\n\n                    for nmin, nmax, _ in dic[\"_range\"]:\n                        if nmin <= num <= nmax:\n                            raise ValueError(f\"Duplicated value in '{attr}' ({num})\")\n\n                    dic[attr] = num\n                    dic[\"_single\"][num] = desc, sub\n                elif len(data[attr]) == 5:  # range\n                    nmin, el, nmax, desc, sub = data[attr]\n\n                    if not el == Ellipsis:\n                        raise TypeError(f\"Second element of '{attr}' should be an ellipsis (...)\")\n                    if not isinstance(nmin, int):\n                        raise TypeError(f\"First element of '{attr}' should be an int\")\n                    if not isinstance(nmax, int):\n                        raise TypeError(f\"Third element of '{attr}' should be an int\")\n                    if not isinstance(desc, str):\n                        raise TypeError(f\"Fourth element of '{attr}' should be a string\")\n\n                    for num in dic[\"_single\"]:\n                        if nmin <= num <= nmax:\n                            raise ValueError(f\"Duplicated value in '{attr}' ({num})\")\n\n                    dic[attr] = range(nmin, nmax + 1)\n                    dic[\"_range\"].append((nmin, nmax, (desc, sub)))\n\n                else:\n                    raise ValueError(f\"Invalid field: {attr}\")\n\n        return super().__new__(mcs, name, bases, dic)\n\n\nclass _Data(metaclass=_DataMeta):\n    \"\"\"\n    This class provides a get_description method to get data out of _single and _range.\n    See the _DataMeta documentation for more information.\n    \"\"\"\n\n    _DATA = Tuple[str, Optional[Any]]\n    _single: Dict[int, _DATA]\n    _range: List[Tuple[int, int, _DATA]]\n\n    @classmethod\n    def _get_data(cls, num: Optional[int]) -> _DATA:\n        if num is None:\n            raise KeyError(\"Data index is not an int\")\n\n        if num in cls._single:\n            return cls._single[num]\n\n        for nmin, nmax, data in cls._range:\n            if nmin <= num <= nmax:\n                return data\n\n        raise KeyError(f\"Data not found for index 0x{num:02x} in {cls.__name__}\")\n\n    @classmethod\n    def get_description(cls, num: Optional[int]) -> str:\n        return cls._get_data(num)[0]\n\n    @classmethod\n    def get_subdata(cls, num: Optional[int]) -> Any:\n        subdata = cls._get_data(num)[1]\n\n        if not subdata:\n            raise ValueError(\"Sub-data not available\")\n\n        return subdata\n\n\nclass UsageTypes(enum.Enum):\n    # controls\n    LINEAR_CONTROL = LC = 0\n    ON_OFF_CONTROL = OOC = 1\n    MOMENTARY_CONTROL = MC = 2\n    ONE_SHOT_CONTROL = OSC = 3\n    RE_TRIGGER_CONTROL = RTC = 4\n    # data\n    SELECTOR = SEL = 5\n    STATIC_VALUE = SV = 6\n    STATIC_FLAG = SF = 7\n    DYNAMIC_FLAG = DF = 8\n    DYNAMIC_VALUE = DV = 9\n    # collection\n    NAMED_ARRAY = NARY = 10\n    COLLECTION_APPLICATION = CA = 11\n    COLLECTION_LOGICAL = CL = 12\n    COLLECTION_PHYSICAL = CP = 13\n    USAGE_SWITCH = US = 14\n    USAGE_MODIFIER = UM = 15\n\n\nUsageTypesControls = (\n    UsageTypes.LINEAR_CONTROL,\n    UsageTypes.ON_OFF_CONTROL,\n    UsageTypes.ONE_SHOT_CONTROL,\n    UsageTypes.RE_TRIGGER_CONTROL,\n)\n\n\nUsageTypesData = (\n    UsageTypes.SELECTOR,\n    UsageTypes.STATIC_VALUE,\n    UsageTypes.STATIC_FLAG,\n    UsageTypes.DYNAMIC_VALUE,\n    UsageTypes.DYNAMIC_FLAG,\n)\n\n\nUsageTypesCollection = (\n    UsageTypes.NAMED_ARRAY,\n    UsageTypes.COLLECTION_APPLICATION,\n    UsageTypes.COLLECTION_LOGICAL,\n    UsageTypes.COLLECTION_PHYSICAL,\n    UsageTypes.USAGE_SWITCH,\n    UsageTypes.USAGE_MODIFIER,\n)\n\n\nclass Collections(_Data):\n    PHYSICAL = 0x00, \"Physical\"\n    APPLICATION = 0x01, \"Application\"\n    LOGICAL = 0x02, \"Logical\"\n    REPORT = 0x03, \"Report\"\n    NAMED_ARRAY = 0x04, \"Named Array\"\n    USAGE_SWITCH = 0x05, \"Usage Switch\"\n    USAGE_MODIFIER = 0x06, \"Usage Modifier\"\n    VENDOR = 0x80, ..., 0xFF, \"Vendor\"\n\n\nclass GenericDesktopControls(_Data):\n    POINTER = 0x01, \"Pointer\", UsageTypes.CP\n    MOUSE = 0x02, \"Mouse\", UsageTypes.CA\n    JOYSTICK = 0x04, \"Joystick\", UsageTypes.CA\n    GAMEPAD = 0x05, \"Game Pad\", UsageTypes.CA\n    KEYBOARD = 0x06, \"Keyboard\", UsageTypes.CA\n    KEYPAD = 0x07, \"Keypad\", UsageTypes.CA\n    MULTI_AXIS_CONTROLLER = 0x08, \"Multi-axis Controller\", UsageTypes.CA\n    TABLET_PC_SYSTEM_CONTROLS = 0x09, \"Tablet PC System Controls\", UsageTypes.CA\n    X = 0x30, \"X\", UsageTypes.DV\n    Y = 0x31, \"Y\", UsageTypes.DV\n    Z = 0x32, \"Z\", UsageTypes.DV\n    RX = 0x33, \"Rx\", UsageTypes.DV\n    RY = 0x34, \"Ry\", UsageTypes.DV\n    RX = 0x35, \"Rz\", UsageTypes.DV\n    SLIDER = 0x36, \"Slider\", UsageTypes.DV\n    DIAL = 0x37, \"Dial\", UsageTypes.DV\n    WHEEL = 0x38, \"Wheel\", UsageTypes.DV\n    HAT_SWITCH = 0x39, \"Hat switch\", UsageTypes.DV\n    COUNTED_BUFFER = 0x3A, \"Counted Buffer\", UsageTypes.CL\n    BYTE_COUNT = 0x3B, \"Byte Count\", UsageTypes.DV\n    MOTION_WAKEUP = 0x3C, \"Motion Wakeup\", UsageTypes.OSC\n    START = 0x3D, \"Start\", UsageTypes.OOC\n    SELECT = 0x3E, \"Select\", UsageTypes.OOC\n    VX = 0x40, \"Vx\", UsageTypes.DV\n    VY = 0x41, \"Vy\", UsageTypes.DV\n    VZ = 0x42, \"Vz\", UsageTypes.DV\n    VBRX = 0x43, \"Vbrx\", UsageTypes.DV\n    VBRY = 0x44, \"Vbry\", UsageTypes.DV\n    VBRZ = 0x45, \"Vbrz\", UsageTypes.DV\n    VNO = 0x46, \"Vno\", UsageTypes.DV\n    FEATURE_NOTIFICATION = 0x47, \"Feature Notification\", (UsageTypes.DV, UsageTypes.DF)\n    RESOLUTION_MULTIPLIER = 0x48, \"Resolution Multiplier\", UsageTypes.DV\n    SYSTEM_CONTROL = 0x80, \"System Control\", UsageTypes.CA\n    SYSTEM_POWER_CONTROL = 0x81, \"System Power Down\", UsageTypes.OSC\n    SYSTEM_SLEEP = 0x82, \"System Sleep\", UsageTypes.OSC\n    SYSTEM_WAKE_UP = 0x83, \"System Wake Up\", UsageTypes.OSC\n    SYSTEM_CONTEXT_MENU = 0x84, \"System Context Menu\", UsageTypes.OSC\n    SYSTEM_MAIN_MENU = 0x85, \"System Main Menu\", UsageTypes.OSC\n    SYSTEM_APP_MENU = 0x86, \"System App Menu\", UsageTypes.OSC\n    SYSTEM_MENU_HELP = 0x87, \"System Menu Help\", UsageTypes.OSC\n    SYSTEM_MENU_EXIT = 0x88, \"System Menu Exit\", UsageTypes.OSC\n    SYSTEM_MENU_SELECT = 0x89, \"System Menu Select\", UsageTypes.OSC\n    SYSTEM_MENU_RIGHT = 0x8A, \"System Menu Right\", UsageTypes.RTC\n    SYSTEM_MENU_LEFT = 0x8B, \"System Menu Left\", UsageTypes.RTC\n    SYSTEM_MENU_UP = 0x8C, \"System Menu Up\", UsageTypes.RTC\n    SYSTEM_MENU_DOWN = 0x8D, \"System Menu Down\", UsageTypes.RTC\n    SYSTEM_COLD_RESTART = 0x8E, \"System Cold Restart\", UsageTypes.OSC\n    SYSTEM_WARM_RESTART = 0x8F, \"System Warm Restart\", UsageTypes.OSC\n    DPAD_UP = 0x90, \"D-pad Up\", UsageTypes.OOC\n    DPAD_DOWN = 0x91, \"D-pad Down\", UsageTypes.OOC\n    DPAD_RIGHT = 0x92, \"D-pad Right\", UsageTypes.OOC\n    DPAD_LEFT = 0x93, \"D-pad Left\", UsageTypes.OOC\n    SYSTEM_DOCK = 0xA0, \"System Dock\", UsageTypes.OSC\n    SYSTEM_UNDOCK = 0xA1, \"System Undock\", UsageTypes.OSC\n    SYSTEM_SETUP = 0xA2, \"System Setup\", UsageTypes.OSC\n    SYSTEM_BREAK = 0xA3, \"System Break\", UsageTypes.OSC\n    SYSTEM_DEBBUGER_BREAK = 0xA4, \"System Debugger Break\", UsageTypes.OSC\n    APPLICATION_BREAK = 0xA5, \"Application Break\", UsageTypes.OSC\n    APPLICATION_DEBBUGER_BREAK = 0xA6, \"Application Debugger Break\", UsageTypes.OSC\n    SYSTEM_SPEAKER_MUTE = 0xA7, \"System Speaker Mute\", UsageTypes.OSC\n    SYSTEM_HIBERNATE = 0xA8, \"System Hibernate\", UsageTypes.OSC\n    SYSTEM_DISPLAY_INVERT = 0xB0, \"System Display Invert\", UsageTypes.OSC\n    SYSTEM_DISPLAY_INTERNAL = 0xB1, \"System Display Internal\", UsageTypes.OSC\n    SYSTEM_DISPLAY_EXTERNAL = 0xB2, \"System Display External\", UsageTypes.OSC\n    SYSTEM_DISPLAY_BOTH = 0xB3, \"System Display Both\", UsageTypes.OSC\n    SYSTEM_DISPLAY_DUAL = 0xB4, \"System Display Dual\", UsageTypes.OSC\n    SYSTEM_DISPLAY_TOGGLE = 0xB5, \"System Display Toggle Int/Ext\", UsageTypes.OSC\n    SYSTEM_DISPLAY_SWAP = 0xB6, \"System Display Swap Primary/Secondary\", UsageTypes.OSC\n    SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7, \"System Display LCD Autoscale\", UsageTypes.OSC\n\n\nclass KeyboardKeypad(_Data):\n    NO_EVENT = 0x00, \"No event indicated\", UsageTypes.SEL\n    KEYBOARD_ERROR_ROLL_OVER = 0x01, \"Keyboard ErrorRollOver\", UsageTypes.SEL\n    KEYBOARD_POST = 0x02, \"Keyboard POSTFail\", UsageTypes.SEL\n    KEYBOARD_ERROR_UNDEFINED = 0x03, \"Keyboard ErrorUndefined\", UsageTypes.SEL\n    KEYBOARD_A = 0x04, \"Keyboard a and A\", UsageTypes.SEL\n    KEYBOARD_B = 0x05, \"Keyboard b and B\", UsageTypes.SEL\n    KEYBOARD_C = 0x06, \"Keyboard c and C\", UsageTypes.SEL\n    KEYBOARD_D = 0x07, \"Keyboard d and D\", UsageTypes.SEL\n    KEYBOARD_E = 0x08, \"Keyboard e and E\", UsageTypes.SEL\n    KEYBOARD_F = 0x09, \"Keyboard f and F\", UsageTypes.SEL\n    KEYBOARD_G = 0x0A, \"Keyboard g and G\", UsageTypes.SEL\n    KEYBOARD_H = 0x0B, \"Keyboard h and H\", UsageTypes.SEL\n    KEYBOARD_I = 0x0C, \"Keyboard i and I\", UsageTypes.SEL\n    KEYBOARD_J = 0x0D, \"Keyboard j and J\", UsageTypes.SEL\n    KEYBOARD_K = 0x0E, \"Keyboard k and K\", UsageTypes.SEL\n    KEYBOARD_L = 0x0F, \"Keyboard l and L\", UsageTypes.SEL\n    KEYBOARD_M = 0x10, \"Keyboard m and M\", UsageTypes.SEL\n    KEYBOARD_N = 0x11, \"Keyboard n and N\", UsageTypes.SEL\n    KEYBOARD_O = 0x12, \"Keyboard o and O\", UsageTypes.SEL\n    KEYBOARD_P = 0x13, \"Keyboard p and P\", UsageTypes.SEL\n    KEYBOARD_Q = 0x14, \"Keyboard q and Q\", UsageTypes.SEL\n    KEYBOARD_R = 0x15, \"Keyboard r and R\", UsageTypes.SEL\n    KEYBOARD_S = 0x16, \"Keyboard s and S\", UsageTypes.SEL\n    KEYBOARD_T = 0x17, \"Keyboard t and T\", UsageTypes.SEL\n    KEYBOARD_U = 0x18, \"Keyboard u and U\", UsageTypes.SEL\n    KEYBOARD_V = 0x19, \"Keyboard v and V\", UsageTypes.SEL\n    KEYBOARD_W = 0x1A, \"Keyboard w and W\", UsageTypes.SEL\n    KEYBOARD_X = 0x1B, \"Keyboard x and X\", UsageTypes.SEL\n    KEYBOARD_Y = 0x1C, \"Keyboard y and Y\", UsageTypes.SEL\n    KEYBOARD_Z = 0x1D, \"Keyboard z and Z\", UsageTypes.SEL\n    KEYBOARD_1 = 0x1E, \"Keyboard 1 and !\", UsageTypes.SEL\n    KEYBOARD_2 = 0x1F, \"Keyboard 2 and @\", UsageTypes.SEL\n    KEYBOARD_3 = 0x20, \"Keyboard 3 and #\", UsageTypes.SEL\n    KEYBOARD_4 = 0x21, \"Keyboard 4 and $\", UsageTypes.SEL\n    KEYBOARD_5 = 0x22, \"Keyboard 5 and %\", UsageTypes.SEL\n    KEYBOARD_6 = 0x23, \"Keyboard 6 and ^\", UsageTypes.SEL\n    KEYBOARD_7 = 0x24, \"Keyboard 7 and &\", UsageTypes.SEL\n    KEYBOARD_8 = 0x25, \"Keyboard 8 and *\", UsageTypes.SEL\n    KEYBOARD_9 = 0x26, \"Keyboard 9 and (\", UsageTypes.SEL\n    KEYBOARD_0 = 0x27, \"Keyboard 0 and )\", UsageTypes.SEL\n    KEYBOARD_ENTER = 0x28, \"Keyboard Return (ENTER)\", UsageTypes.SEL\n    KEYBOARD_ESCAPE = 0x29, \"Keyboard ESCAPE\", UsageTypes.SEL\n    KEYBOARD_DELETE = 0x2A, \"Keyboard DELETE (Backspace)\", UsageTypes.SEL\n    KEYBOARD_TAB = 0x2B, \"Keyboard Tab\", UsageTypes.SEL\n    KEYBOARD_SPACEBAR = 0x2C, \"Keyboard Spacebar\", UsageTypes.SEL\n    KEYBOARD_MINUS = 0x2D, \"Keyboard - and (underscore)\", UsageTypes.SEL\n    KEYBOARD_PLUS = 0x2E, \"Keyboard = and +\", UsageTypes.SEL\n    KEYBOARD_LEFT_BRACKET = 0x2F, \"Keyboard [ and {\", UsageTypes.SEL\n    KEYBOARD_RIGHT_BRACKET = 0x30, \"Keyboard ] and }\", UsageTypes.SEL\n    KEYBOARD_BACKSLASH = 0x31, \"Keyboard \\\\ and |\", UsageTypes.SEL\n    KEYBOARD_CARDINAL = 0x32, \"Keyboard Non-US # and ~\", UsageTypes.SEL\n    KEYBOARD_SEMICOLON = 0x33, \"Keyboard ; and :\", UsageTypes.SEL\n    KEYBOARD_QUOTE = 0x34, \"Keyboard ' and \\\"\", UsageTypes.SEL\n    KEYBOARD_GRAVE = 0x35, \"Keyboard Grave Accent and Tilde\", UsageTypes.SEL\n    KEYBOARD_COMMA = 0x36, \"Keyboard , and <\", UsageTypes.SEL\n    KEYBOARD_DOT = 0x37, \"Keyboard . and >\", UsageTypes.SEL\n    KEYBOARD_SLASH = 0x38, \"Keyboard / and ?\", UsageTypes.SEL\n    KEYBOARD_CAPS_LOCK = 0x39, \"Keyboard Caps Lock\", UsageTypes.SEL\n    KEYBOARD_F1 = 0x3A, \"Keyboard F1\", UsageTypes.SEL\n    KEYBOARD_F2 = 0x3B, \"Keyboard F2\", UsageTypes.SEL\n    KEYBOARD_F3 = 0x3C, \"Keyboard F3\", UsageTypes.SEL\n    KEYBOARD_F4 = 0x3D, \"Keyboard F4\", UsageTypes.SEL\n    KEYBOARD_F5 = 0x3E, \"Keyboard F5\", UsageTypes.SEL\n    KEYBOARD_F6 = 0x3F, \"Keyboard F6\", UsageTypes.SEL\n    KEYBOARD_F7 = 0x40, \"Keyboard F7\", UsageTypes.SEL\n    KEYBOARD_F8 = 0x41, \"Keyboard F8\", UsageTypes.SEL\n    KEYBOARD_F9 = 0x42, \"Keyboard F9\", UsageTypes.SEL\n    KEYBOARD_F10 = 0x43, \"Keyboard F10\", UsageTypes.SEL\n    KEYBOARD_F11 = 0x44, \"Keyboard F11\", UsageTypes.SEL\n    KEYBOARD_F12 = 0x45, \"Keyboard F12\", UsageTypes.SEL\n    KEYBOARD_PRINTSCREEN = 0x46, \"Keyboard PrintScreen\", UsageTypes.SEL\n    KEYBOARD_SCROLL_LOCK = 0x47, \"Keyboard Scroll Lock\", UsageTypes.SEL\n    KEYBOARD_PAUSE = 0x48, \"Keyboard Pause\", UsageTypes.SEL\n    KEYBOARD_INSERT = 0x49, \"Keyboard Insert\", UsageTypes.SEL\n    KEYBOARD_HOME = 0x4A, \"Keyboard Home\", UsageTypes.SEL\n    KEYBOARD_PAGE_UP = 0x4B, \"Keyboard PageUp\", UsageTypes.SEL\n    KEYBOARD_DELETE_FORWARD = 0x4C, \"Keyboard Delete Forward\", UsageTypes.SEL\n    KEYBOARD_END = 0x4D, \"Keyboard End\", UsageTypes.SEL\n    KEYBOARD_PAGE_DOWN = 0x4E, \"Keyboard PageDown\", UsageTypes.SEL\n    KEYBOARD_RIGHT_ARROW = 0x4F, \"Keyboard RightArrow\", UsageTypes.SEL\n    KEYBOARD_LEFT_ARROW = 0x50, \"Keyboard LeftArrow\", UsageTypes.SEL\n    KEYBOARD_UP_ARROW = 0x51, \"Keyboard DownArrow\", UsageTypes.SEL\n    KEYBOARD_DOWN_ARROW = 0x52, \"Keyboard UpArrow\", UsageTypes.SEL\n    KEYBOARD_NUM_LOCK = 0x53, \"Keypad Num Lock and Clear\", UsageTypes.SEL\n    KEYPAD_SLASH = 0x54, \"Keypad /\", UsageTypes.SEL\n    KEYPAD_ASTERISK = 0x55, \"Keypad *\", UsageTypes.SEL\n    KEYPAD_MINUS = 0x56, \"Keypad -\", UsageTypes.SEL\n    KEYPAD_PLUS = 0x57, \"Keypad +\", UsageTypes.SEL\n    KEYPAD_ENTER = 0x58, \"Keypad ENTER\", UsageTypes.SEL\n    KEYPAD_1 = 0x59, \"Keypad 1 and End\", UsageTypes.SEL\n    KEYPAD_2 = 0x5A, \"Keypad 2 and Down Arrow\", UsageTypes.SEL\n    KEYPAD_3 = 0x5B, \"Keypad 3 and PageDn\", UsageTypes.SEL\n    KEYPAD_4 = 0x5C, \"Keypad 4 and Left Arrow\", UsageTypes.SEL\n    KEYPAD_5 = 0x5D, \"Keypad 5\", UsageTypes.SEL\n    KEYPAD_6 = 0x5E, \"Keypad 6 and Right Arrow\", UsageTypes.SEL\n    KEYPAD_7 = 0x5F, \"Keypad 7 and Home\", UsageTypes.SEL\n    KEYPAD_8 = 0x60, \"Keypad 8 and Up Arrow\", UsageTypes.SEL\n    KEYPAD_9 = 0x61, \"Keypad 9 and PageUp\", UsageTypes.SEL\n    KEYPAD_0 = 0x62, \"Keypad 0 and Insert\", UsageTypes.SEL\n    KEYPAD_DOT = 0x63, \"Keypad . and Delete\", UsageTypes.SEL\n    KEYPAD_BACKSLASH = 0x64, \"Keyboard Non-US \\\\ and |\", UsageTypes.SEL\n    KEYPAD_APPLICATION = 0x65, \"Keyboard Application\", UsageTypes.SEL\n    KEYPAD_POWER = 0x66, \"Keyboard Power\", UsageTypes.SEL\n    KEYPAD_EQUALS = 0x67, \"Keypad =\", UsageTypes.SEL\n    KEYBOARD_F13 = 0x68, \"Keyboard F13\", UsageTypes.SEL\n    KEYBOARD_F14 = 0x69, \"Keyboard F14\", UsageTypes.SEL\n    KEYBOARD_F15 = 0x6A, \"Keyboard F15\", UsageTypes.SEL\n    KEYBOARD_F16 = 0x6B, \"Keyboard F16\", UsageTypes.SEL\n    KEYBOARD_F17 = 0x6C, \"Keyboard F17\", UsageTypes.SEL\n    KEYBOARD_F18 = 0x6D, \"Keyboard F18\", UsageTypes.SEL\n    KEYBOARD_F19 = 0x6E, \"Keyboard F19\", UsageTypes.SEL\n    KEYBOARD_F20 = 0x6F, \"Keyboard F20\", UsageTypes.SEL\n    KEYBOARD_F21 = 0x70, \"Keyboard F21\", UsageTypes.SEL\n    KEYBOARD_F22 = 0x71, \"Keyboard F22\", UsageTypes.SEL\n    KEYBOARD_F23 = 0x72, \"Keyboard F23\", UsageTypes.SEL\n    KEYBOARD_F24 = 0x73, \"Keyboard F24\", UsageTypes.SEL\n    KEYBOARD_EXECUTE = 0x74, \"Keyboard Execute\", UsageTypes.SEL\n    KEYBOARD_HELP = 0x75, \"Keyboard Help\", UsageTypes.SEL\n    KEYBOARD_MENU = 0x76, \"Keyboard Menu\", UsageTypes.SEL\n    KEYBOARD_SELECT = 0x77, \"Keyboard Select\", UsageTypes.SEL\n    KEYBOARD_STOP = 0x78, \"Keyboard Stop\", UsageTypes.SEL\n    KEYBOARD_AGAIN = 0x79, \"Keyboard Again\", UsageTypes.SEL\n    KEYBOARD_UNDO = 0x7A, \"Keyboard Undo\", UsageTypes.SEL\n    KEYBOARD_CUT = 0x7B, \"Keyboard Cut\", UsageTypes.SEL\n    KEYBOARD_COPY = 0x7C, \"Keyboard Copy\", UsageTypes.SEL\n    KEYBOARD_PASTE = 0x7D, \"Keyboard Paste\", UsageTypes.SEL\n    KEYBOARD_FIND = 0x7E, \"Keyboard Find\", UsageTypes.SEL\n    KEYBOARD_MUTE = 0x7F, \"Keyboard Mute\", UsageTypes.SEL\n    KEYBOARD_VOLUME_UP = 0x80, \"Keyboard Volume Up\", UsageTypes.SEL\n    KEYBOARD_VOLUME_DOWN = 0x81, \"Keyboard Volume Down\", UsageTypes.SEL\n    KEYBOARD_LOCKING_CAPS_LOCK = 0x82, \"Keyboard Locking Caps Lock\", UsageTypes.SEL\n    KEYBOARD_LOCKING_NUM_LOCK = 0x83, \"Keyboard Locking Num Lock\", UsageTypes.SEL\n    KEYBOARD_LOCKING_SCROLL_LOCK = 0x84, \"Keyboard Locking Scroll Lock\", UsageTypes.SEL\n    KEYPAD_COMMA = 0x85, \"Keypad Comma\", UsageTypes.SEL\n    KEYPAD_EQUALS_SIGN = 0x86, \"Keypad Equal Sign\", UsageTypes.SEL\n    KEYBOARD_INTERNATIONAL1 = 0x87, \"Keyboard International1\", UsageTypes.SEL\n    KEYBOARD_INTERNATIONAL2 = 0x88, \"Keyboard International2\", UsageTypes.SEL\n    KEYBOARD_INTERNATIONAL3 = 0x89, \"Keyboard International3\", UsageTypes.SEL\n    KEYBOARD_INTERNATIONAL4 = 0x8A, \"Keyboard International4\", UsageTypes.SEL\n    KEYBOARD_INTERNATIONAL5 = 0x8B, \"Keyboard International5\", UsageTypes.SEL\n    KEYBOARD_INTERNATIONAL6 = 0x8C, \"Keyboard International6\", UsageTypes.SEL\n    KEYBOARD_INTERNATIONAL7 = 0x8D, \"Keyboard International7\", UsageTypes.SEL\n    KEYBOARD_INTERNATIONAL8 = 0x8E, \"Keyboard International8\", UsageTypes.SEL\n    KEYBOARD_INTERNATIONAL9 = 0x8F, \"Keyboard International9\", UsageTypes.SEL\n    KEYBOARD_LANG1 = 0x90, \"Keyboard LANG1\", UsageTypes.SEL\n    KEYBOARD_LANG2 = 0x91, \"Keyboard LANG2\", UsageTypes.SEL\n    KEYBOARD_LANG3 = 0x92, \"Keyboard LANG3\", UsageTypes.SEL\n    KEYBOARD_LANG4 = 0x93, \"Keyboard LANG4\", UsageTypes.SEL\n    KEYBOARD_LANG5 = 0x94, \"Keyboard LANG5\", UsageTypes.SEL\n    KEYBOARD_LANG6 = 0x95, \"Keyboard LANG6\", UsageTypes.SEL\n    KEYBOARD_LANG7 = 0x96, \"Keyboard LANG7\", UsageTypes.SEL\n    KEYBOARD_LANG8 = 0x97, \"Keyboard LANG8\", UsageTypes.SEL\n    KEYBOARD_LANG9 = 0x98, \"Keyboard LANG9\", UsageTypes.SEL\n    KEYBOARD_ALTERNATE_ERASE = 0x99, \"Keyboard Alternate Erase\", UsageTypes.SEL\n    KEYBOARD_SYSREQ_ATTENTION = 0x9A, \"Keyboard SysReq/Attention\", UsageTypes.SEL\n    KEYBOARD_CANCEL = 0x9B, \"Keyboard Cancel\", UsageTypes.SEL\n    KEYBOARD_CLEAR = 0x9C, \"Keyboard Clear\", UsageTypes.SEL\n    KEYBOARD_PRIOR = 0x9D, \"Keyboard Prior\", UsageTypes.SEL\n    KEYBOARD_RETURN = 0x9E, \"Keyboard Return\", UsageTypes.SEL\n    KEYBOARD_SEPARATOE = 0x9F, \"Keyboard Separator\", UsageTypes.SEL\n    KEYBOARD_OUT = 0xA0, \"Keyboard Out\", UsageTypes.SEL\n    KEYBOARD_OPER = 0xA1, \"Keyboard Oper\", UsageTypes.SEL\n    KEYBOARD_CLEAR_AGAIN = 0xA2, \"Keyboard Clear/Again\", UsageTypes.SEL\n    KEYBOARD_CRSEL_PROPS = 0xA3, \"Keyboard CrSel/Props\", UsageTypes.SEL\n    KEYBOARD_EXSELL = 0xA4, \"Keyboard ExSel\", UsageTypes.SEL\n    KEYPAD_ZERO_ZERO = 0xB0, \"Keypad 00\", UsageTypes.SEL\n    KEYPAD_ZERO_ZERO_ZERO = 0xB1, \"Keypad 000\", UsageTypes.SEL\n    THOUSANDS_SEPARATOR = 0xB2, \"Thousands Separator\", UsageTypes.SEL\n    DECIMAL_SEPARATOR = 0xB3, \"Decimal Separator\", UsageTypes.SEL\n    CURRENCY_UNIT = 0xB4, \"Currency Unit\", UsageTypes.SEL\n    CURRENCY_SUBUNIT = 0xB5, \"Currency Sub-unit\", UsageTypes.SEL\n    KEYPAD_LEFT_PARENTHESIS = 0xB6, \"Keypad (\", UsageTypes.SEL\n    KEYPAD_RIGHT_PARENTHESIS = 0xB7, \"Keypad )\", UsageTypes.SEL\n    KEYPAD_LEFT_CURLY_BRACKET = 0xB8, \"Keypad {\", UsageTypes.SEL\n    KEYPAD_RIGHT_CURLY_BRACKET = 0xB9, \"Keypad }\", UsageTypes.SEL\n    KEYPAD_TAB = 0xBA, \"Keypad Tab\", UsageTypes.SEL\n    KEYPAD_BACKSPACE = 0xBB, \"Keypad Backspace\", UsageTypes.SEL\n    KEYPAD_A = 0xBC, \"Keypad A\", UsageTypes.SEL\n    KEYPAD_B = 0xBD, \"Keypad B\", UsageTypes.SEL\n    KEYPAD_C = 0xBE, \"Keypad C\", UsageTypes.SEL\n    KEYPAD_D = 0xBF, \"Keypad D\", UsageTypes.SEL\n    KEYPAD_E = 0xC0, \"Keypad E\", UsageTypes.SEL\n    KEYPAD_F = 0xC1, \"Keypad F\", UsageTypes.SEL\n    KEYPAD_XOR = 0xC2, \"Keypad XOR\", UsageTypes.SEL\n    KEYPAD_AND = 0xC3, \"Keypad ^\", UsageTypes.SEL\n    KEYPAD_PERCENTAGE = 0xC4, \"Keypad %\", UsageTypes.SEL\n    KEYPAD_LESS_THAN = 0xC5, \"Keypad <\", UsageTypes.SEL\n    KEYPAD_MORE_THAN = 0xC6, \"Keypad >\", UsageTypes.SEL\n    KEYPAD_AMPERSAND = 0xC7, \"Keypad &\", UsageTypes.SEL\n    KEYPAD_2_AMPERSAND = 0xC8, \"Keypad &&\", UsageTypes.SEL\n    KEYPAD_VERTICAL_BAR = 0xC9, \"Keypad |\", UsageTypes.SEL\n    KEYPAD_2_VERTICAL_BAR = 0xCA, \"Keypad ||\", UsageTypes.SEL\n    KEYPAD_COLON = 0xCB, \"Keypad :\", UsageTypes.SEL\n    KEYPAD_CARDINAL = 0xCC, \"Keypad #\", UsageTypes.SEL\n    KEYPAD_SPACE = 0xCD, \"Keypad Space\", UsageTypes.SEL\n    KEYPAD_AT = 0xCE, \"Keypad @\", UsageTypes.SEL\n    KEYPAD_EXCLAMATION = 0xCF, \"Keypad !\", UsageTypes.SEL\n    KEYPAD_MEMORY_STORE = 0xD0, \"Keypad Memory Store\", UsageTypes.SEL\n    KEYPAD_MEMORY_RECALL = 0xD1, \"Keypad Memory Recall\", UsageTypes.SEL\n    KEYPAD_MEMORY_CLEAR = 0xD2, \"Keypad Memory Clear\", UsageTypes.SEL\n    KEYPAD_MEMORY_ADD = 0xD3, \"Keypad Memory Add\", UsageTypes.SEL\n    KEYPAD_MEMORY_SUBTRACT = 0xD4, \"Keypad Memory Subtract\", UsageTypes.SEL\n    KEYPAD_MEMORY_MULTIPLY = 0xD5, \"Keypad Memory Multiply\", UsageTypes.SEL\n    KEYPAD_MEMORY_DIVIDE = 0xD6, \"Keypad Memory Divide\", UsageTypes.SEL\n    KEYPAD_PLUS_MINUS = 0xD7, \"Keypad +/-\", UsageTypes.SEL\n    KEYPAD_CLEAR = 0xD8, \"Keypad Clear\", UsageTypes.SEL\n    KEYPAD_CLEAR_ENTRY = 0xD9, \"Keypad Clear Entry\", UsageTypes.SEL\n    KEYPAD_BINARY = 0xDA, \"Keypad Binary\", UsageTypes.SEL\n    KEYPAD_OCTAL = 0xDB, \"Keypad Octal\", UsageTypes.SEL\n    KEYPAD_DECIMAL = 0xDC, \"Keypad Decimal\", UsageTypes.SEL\n    KEYPAD_HEXADECIMAL = 0xDD, \"Keypad Hexadecimal\", UsageTypes.DV\n    KEYBOARD_LEFT_CONTROL = 0xE0, \"Keyboard LeftControl\", UsageTypes.DV\n    KEYBOARD_LEFT_SHIFT = 0xE1, \"Keyboard LeftShift\", UsageTypes.DV\n    KEYBOARD_LEFT_ALT = 0xE2, \"Keyboard LeftAlt\", UsageTypes.DV\n    KEYBOARD_LEFT_GUI = 0xE3, \"Keyboard Left GUI\", UsageTypes.DV\n    KEYBOARD_RIGHT_CONTROL = 0xE4, \"Keyboard RightControl\", UsageTypes.DV\n    KEYBOARD_RIGHT_SHIFT = 0xE5, \"Keyboard RightShift\", UsageTypes.DV\n    KEYBOARD_RIGHT_ALT = 0xE6, \"Keyboard RightAlt\", UsageTypes.DV\n    KEYBOARD_RIGHT_GUI = 0xE7, \"Keyboard Right GUI\", UsageTypes.DV\n\n\nclass Led(_Data):\n    NUM_LOCK = 0x01, \"Num Lock\", UsageTypes.OOC\n    CAPS_LOCK = 0x02, \"Caps Lock\", UsageTypes.OOC\n    SCROLL_LOCK = 0x03, \"Scroll Lock\", UsageTypes.OOC\n    COMPOSE = 0x04, \"Compose\", UsageTypes.OOC\n    KANA = 0x05, \"Kana\", UsageTypes.OOC\n    POWER = 0x06, \"Power\", UsageTypes.OOC\n    SHIFT = 0x07, \"Shift\", UsageTypes.OOC\n    DO_NOT_DISTURB = 0x08, \"Do Not Disturb\", UsageTypes.OOC\n    MUTE = 0x09, \"Mute\", UsageTypes.OOC\n    TONE_ENABLE = 0x0A, \"Tone Enable\", UsageTypes.OOC\n    HIGH_CUT_FILTER = 0x0B, \"High Cut Filter\", UsageTypes.OOC\n    LOW_CUT_FILTER = 0x0C, \"Low Cut Filter\", UsageTypes.OOC\n    EQUALIZER_ENABLE = 0x0D, \"Equalizer Enable\", UsageTypes.OOC\n    SOUND_FIELD_ON = 0x0E, \"Sound Field On\", UsageTypes.OOC\n    SURROUND_ON = 0x0F, \"Surround On\", UsageTypes.OOC\n    REPEAR = 0x10, \"Repeat\", UsageTypes.OOC\n    STEREO = 0x11, \"Stereo\", UsageTypes.OOC\n    SAMPLING_RATE_DETECT = 0x12, \"Sampling Rate Detect\", UsageTypes.OOC\n    SPINNING = 0x13, \"Spinning\", UsageTypes.OOC\n    CAV = 0x14, \"CAV\", UsageTypes.OOC\n    CLV = 0x15, \"CLV\", UsageTypes.OOC\n    RECORDING_FORMAT_DETECT = 0x16, \"Recording Format Detect\", UsageTypes.OOC\n    OFF_HOOK = 0x17, \"Off-Hook\", UsageTypes.OOC\n    RING = 0x18, \"Ring\", UsageTypes.OOC\n    MESSAGE_WAITING = 0x19, \"Message Waiting\", UsageTypes.OOC\n    DATA_MODE = 0x1A, \"Data Mode\", UsageTypes.OOC\n    BATTERY_OPERATION = 0x1B, \"Battery Operation\", UsageTypes.OOC\n    BATTERY_OK = 0x1C, \"Battery OK\", UsageTypes.OOC\n    BATTERY_LOW = 0x1D, \"Battery Low\", UsageTypes.OOC\n    SPEAKER = 0x1E, \"Speaker\", UsageTypes.OOC\n    HEAD_SET = 0x1F, \"Head Set\", UsageTypes.OOC\n    HOLD = 0x20, \"Hold\", UsageTypes.OOC\n    MICROPHONE = 0x21, \"Microphone\", UsageTypes.OOC\n    COVERAGE = 0x22, \"Coverage\", UsageTypes.OOC\n    NIGHT_MODE = 0x23, \"Night Mode\", UsageTypes.OOC\n    SEND_CALLS = 0x24, \"Send Calls\", UsageTypes.OOC\n    CALL_PICKUP = 0x25, \"Call Pickup\", UsageTypes.OOC\n    CONFERENCE = 0x26, \"Conference\", UsageTypes.OOC\n    STAND_BY = 0x27, \"Stand-by\", UsageTypes.OOC\n    CAMERA_ON = 0x28, \"Camera On\", UsageTypes.OOC\n    CAMERA_OFF = 0x29, \"Camera Off\", UsageTypes.OOC\n    ON_LINE = 0x2A, \"On-Line\", UsageTypes.OOC\n    OFF_LINE = 0x2B, \"Off-Line\", UsageTypes.OOC\n    BUSY = 0x2C, \"Busy\", UsageTypes.OOC\n    READY = 0x2D, \"Ready\", UsageTypes.OOC\n    PAPER_OUT = 0x2E, \"Paper-Out\", UsageTypes.OOC\n    PAPER_JAM = 0x2F, \"Paper-Jam\", UsageTypes.OOC\n    REMOTE = 0x30, \"Remote\", UsageTypes.OOC\n    FORWARD = 0x31, \"Forward\", UsageTypes.OOC\n    REVERSE = 0x32, \"Reverse\", UsageTypes.OOC\n    STOP = 0x33, \"Stop\", UsageTypes.OOC\n    REWIND = 0x34, \"Rewind\", UsageTypes.OOC\n    FAST_FORWARD = 0x35, \"Fast Forward\", UsageTypes.OOC\n    PLAY = 0x36, \"Play\", UsageTypes.OOC\n    PAUSE = 0x37, \"Pause\", UsageTypes.OOC\n    RECORD = 0x38, \"Record\", UsageTypes.OOC\n    ERROR = 0x39, \"Error\", UsageTypes.OOC\n    USAGE_SELECTED_INDICATOR = 0x3A, \"Usage Selected Indicator\", UsageTypes.US\n    USAGE_IN_USE_INDICATOR = 0x3B, \"Usage In Use Indicator\", UsageTypes.US\n    USAGE_MULTI_MODE_INDICATOR = 0x3C, \"Usage Multi Mode Indicator\", UsageTypes.UM\n    INDICATOR_ON = 0x3D, \"Indicator On\", UsageTypes.SEL\n    INDICATOR_FLASH = 0x3E, \"Indicator Flash\", UsageTypes.SEL\n    INDICATOR_SLOW_BLINK = 0x3F, \"Indicator Slow Blink\", UsageTypes.SEL\n    INDICATOR_FAST_BLINK = 0x40, \"Indicator Fast Blink\", UsageTypes.SEL\n    INDICATOR_OFF = 0x41, \"Indicator Off\", UsageTypes.SEL\n    FLASH_ON_TIME = 0x42, \"Flash On Time\", UsageTypes.DV\n    SLOW_BLINK_ON_TIME = 0x43, \"Slow Blink On Time\", UsageTypes.DV\n    SLOW_BLINK_OFF_TIME = 0x44, \"Slow Blink Off Time\", UsageTypes.DV\n    FAST_BLINK_ON_TIME = 0x45, \"Fast Blink On Time\", UsageTypes.DV\n    FAST_BLINK_OFF_TIME = 0x46, \"Fast Blink Off Time\", UsageTypes.DV\n    USAGE_INDICATOR_COLOR = 0x47, \"Usage Indicator Color\", UsageTypes.UM\n    INDICATOR_RED = 0x48, \"Indicator Red\", UsageTypes.SEL\n    INDICATOR_GREEN = 0x49, \"Indicator Green\", UsageTypes.SEL\n    INDICATOR_AMBER = 0x4A, \"Indicator Amber\", UsageTypes.SEL\n    GENERIC_INDICATOR = 0x4B, \"Generic Indicator\", UsageTypes.OOC\n    SYSTEM_SUSPEND = 0x4C, \"System Suspend\", UsageTypes.OOC\n    EXTERNAL_POWER_CONNECTED = 0x4D, \"External Power Connected\", UsageTypes.OOC\n\n\nclass Button(_Data):\n    _USAGE_TYPES = (\n        UsageTypes.SEL,\n        UsageTypes.OOC,\n        UsageTypes.MC,\n        UsageTypes.OSC,\n    )\n\n    data = {\n        \"NO_BUTTON\": (0x0000, \"Button 1 (primary/trigger)\", _USAGE_TYPES),\n        \"BUTTON_1\": (0x0001, \"Button 1 (primary/trigger)\", _USAGE_TYPES),\n        \"BUTTON_2\": (0x0002, \"Button 2 (secondary)\", _USAGE_TYPES),\n        \"BUTTON_3\": (0x0003, \"Button 3 (tertiary)\", _USAGE_TYPES),\n    }\n\n    for _i in range(0x0004, 0xFFFF):\n        data[f\"BUTTON_{_i}\"] = _i, f\"Button {_i}\", _USAGE_TYPES\n\n\nclass Consumer(_Data):\n    CONSUMER_CONTROL = 0x0001, \"Consumer Control\", UsageTypes.CA\n    NUMERIC_KEY_PAD = 0x0002, \"Numeric Key Pad\", UsageTypes.NARY\n    PROGRAMMABLE_BUTTONS = 0x0003, \"Programmable Buttons\", UsageTypes.NARY\n    MICROPHONE = 0x0004, \"Microphone\", UsageTypes.CA\n    HEADPHONE = 0x0005, \"Headphone\", UsageTypes.CA\n    GRAPHIC_EQUALIZER = 0x0006, \"Graphic Equalizer\", UsageTypes.CA\n    PLUS10 = 0x0020, \"+10\", UsageTypes.OSC\n    PULS100 = 0x0021, \"+100\", UsageTypes.OSC\n    AM_PM = 0x0022, \"AM/PM\", UsageTypes.OSC\n    POWER = 0x0030, \"Power\", UsageTypes.OOC\n    REST = 0x0031, \"Reset\", UsageTypes.OSC\n    SLEEP = 0x0032, \"Sleep\", UsageTypes.OSC\n    SLEEP_AFTER = 0x0033, \"Sleep After\", UsageTypes.OSC\n    SLEEP_MODE = 0x0034, \"Sleep Mode\", UsageTypes.RTC\n    ILLUMINATION = 0x0035, \"Illumination\", UsageTypes.OOC\n    FUNCTION_BUTTONS = 0x0036, \"Function Buttons\", UsageTypes.NARY\n    MENU = 0x0040, \"Menu\", UsageTypes.OOC\n    MENU_PICK = 0x0041, \"Menu Pick\", UsageTypes.OSC\n    MENU_UP = 0x0042, \"Menu Up\", UsageTypes.OSC\n    MENU_DOWN = 0x0043, \"Menu Down\", UsageTypes.OSC\n    MENU_LEFT = 0x0044, \"Menu Left\", UsageTypes.OSC\n    MENU_RIGHT = 0x0045, \"Menu Right\", UsageTypes.OSC\n    MENU_ESCAPE = 0x0046, \"Menu Escape\", UsageTypes.OSC\n    MENU_VALUE_INCREASE = 0x0047, \"Menu Value Increase\", UsageTypes.OSC\n    MENU_VALUE_DECREASE = 0x0048, \"Menu Value Decrease\", UsageTypes.OSC\n    DATA_ON_SCREEN = 0x0060, \"Data On Screen\", UsageTypes.OOC\n    CLOSED_CAPTION = 0x0061, \"Closed Caption\", UsageTypes.OOC\n    CLOSED_CAPTION_SELECT = 0x0062, \"Closed Caption Select\", UsageTypes.OOC\n    VCR_TV = 0x0063, \"VCR/TV\", UsageTypes.OSC\n    BROADCAST_MODE = 0x0064, \"Broadcast Mode\", UsageTypes.OOC\n    SNAPSHOT = 0x0065, \"Snapshot\", UsageTypes.OOC\n    STILL = 0x0066, \"Still\", UsageTypes.OOC\n    SELECTION = 0x0080, \"Selection\", UsageTypes.NARY\n    ASSIGN_SELECTION = 0x0081, \"Assign Selection\", UsageTypes.OSC\n    MODE_STEP = 0x0082, \"Mode Step\", UsageTypes.OSC\n    RECALL_LAST = 0x0083, \"Recall Last\", UsageTypes.OSC\n    ENTER_CHANNEL = 0x0084, \"Enter Channel\", UsageTypes.OSC\n    ORDER_MOVIE = 0x0085, \"Order Movie\", UsageTypes.OSC\n    CHANNEL = 0x0086, \"Channel\", UsageTypes.LC\n    MEDIA_SELECTION = 0x0087, \"Media Selection\", UsageTypes.NARY\n    MEDIA_SELECT_COMPUTER = 0x0088, \"Media Select Computer\", UsageTypes.SEL\n    MEDIA_SELECT_TV = 0x0089, \"Media Select TV\", UsageTypes.SEL\n    MEDIA_SELECT_WWW = 0x008A, \"Media Select WWW\", UsageTypes.SEL\n    MEDIA_SELECT_DVD = 0x008B, \"Media Select DVD\", UsageTypes.SEL\n    MEDIA_SELECT_TELEPHONE = 0x008C, \"Media Select Telephone\", UsageTypes.SEL\n    MEDIA_SELECT_PROGRAM_GUIDE = 0x008D, \"Media Select Program Guide\", UsageTypes.SEL\n    MEDIA_SELECT_VIDEO_PHONE = 0x008E, \"Media Select Video Phone\", UsageTypes.SEL\n    MEDIA_SELECT_GAMES = 0x008F, \"Media Select Games\", UsageTypes.SEL\n    MEDIA_SELECT_MESSAGES = 0x0090, \"Media Select Messages\", UsageTypes.SEL\n    MEDIA_SELECT_CD = 0x0091, \"Media Select CD \", UsageTypes.SEL\n    MEDIA_SELECT_VCR = 0x0092, \"Media Select VCR\", UsageTypes.SEL\n    MEDIA_SELECT_TUNER = 0x0093, \"Media Select Tuner\", UsageTypes.SEL\n    QUIT = 0x0094, \"Quit\", UsageTypes.OSC\n    HELP = 0x0095, \"Help\", UsageTypes.OOC\n    MEDIA_SELECT_TAPE = 0x0096, \"Media Select Tape\", UsageTypes.SEL\n    MEDIA_SELECT_CABLE = 0x0097, \"Media Select Cable\", UsageTypes.SEL\n    MEDIA_SELECT_SATELLITE = 0x0098, \"Media Select Satellite\", UsageTypes.SEL\n    MEDIA_SELECT_SECURITY = 0x0099, \"Media Select Security\", UsageTypes.SEL\n    MEDIA_SELECT_HOME = 0x009A, \"Media Select Home\", UsageTypes.SEL\n    MEDIA_SELECT_CALL = 0x009B, \"Media Select Call\", UsageTypes.SEL\n    CHANNEL_INCREMENT = 0x009C, \"Channel Increment\", UsageTypes.OSC\n    CHANNEL_DECREMENT = 0x009D, \"Channel Decrement\", UsageTypes.OSC\n    MEDIA_SELECT_SAP = 0x009E, \"Media Select SAP\", UsageTypes.SEL\n    VCR_PLUS = 0x00A0, \"VCR Plus\", UsageTypes.OSC\n    ONCE = 0x00A1, \"Once\", UsageTypes.OSC\n    DAILY = 0x00A2, \"Daily\", UsageTypes.OSC\n    WEEKLY = 0x00A3, \"Weekly\", UsageTypes.OSC\n    MONTHLY = 0x00A4, \"Monthly\", UsageTypes.OSC\n    PLAY = 0x00B0, \"Play\", UsageTypes.OOC\n    PAUSE = 0x00B1, \"Pause\", UsageTypes.OOC\n    RECORD = 0x00B2, \"Record\", UsageTypes.OOC\n    FAST_FORWARD = 0x00B3, \"Fast Forward\", UsageTypes.OOC\n    REWIND = 0x00B4, \"Rewind\", UsageTypes.OOC\n    SCAN_NEXT_TRACK = 0x00B5, \"Scan Next Track\", UsageTypes.OSC\n    SCAN_PREVIOUS_TRACK = 0x00B6, \"Scan Previous Track\", UsageTypes.OSC\n    STOP = 0x00B7, \"Stop\", UsageTypes.OSC\n    EJECT = 0x00B8, \"Eject\", UsageTypes.OSC\n    RANDOM_PLAY = 0x00B9, \"Random Play\", UsageTypes.OOC\n    SELECT_DISC = 0x00BA, \"Select Disc\", UsageTypes.NARY\n    ENTER_DISC = 0x00BB, \"Enter Disc\", UsageTypes.MC\n    REPEAT = 0x00BC, \"Repeat\", UsageTypes.OSC\n    TRACKING = 0x00BD, \"Tracking\", UsageTypes.LC\n    TRACK_NORMAL = 0x00BE, \"Track Normal\", UsageTypes.OSC\n    SLOW_TRACKING = 0x00BF, \"Slow Tracking\", UsageTypes.LC\n    FRAME_FORWARD = 0x00C0, \"Frame Forward\", UsageTypes.RTC\n    FRAME_BACK = 0x00C1, \"Frame Back\", UsageTypes.RTC\n    MARK = 0x00C2, \"Mark\", UsageTypes.OSC\n    CLEAR_MARK = 0x00C3, \"Clear Mark\", UsageTypes.OSC\n    REPEAT_FROM_MARK = 0x00C4, \"Repeat From Mark\", UsageTypes.OOC\n    RETURN_TO_MARK = 0x00C5, \"Return To Mark\", UsageTypes.OSC\n    SEARCH_MARK_FORWARD = 0x00C6, \"Search Mark Forward\", UsageTypes.OSC\n    SEARCH_MARK_BACKWARDS = 0x00C7, \"Search Mark Backwards\", UsageTypes.OSC\n    COUNTER_RESET = 0x00C8, \"Counter Reset\", UsageTypes.OSC\n    SHOW_COUNTER = 0x00C9, \"Show Counter\", UsageTypes.OSC\n    TRACKING_INCREMENT = 0x00CA, \"Tracking Increment\", UsageTypes.RTC\n    TRACKING_DECREMENT = 0x00CB, \"Tracking Decrement\", UsageTypes.RTC\n    STOP_EJECT = 0x00CC, \"Stop/Eject\", UsageTypes.OSC\n    PLAY_PAUSE = 0x00CD, \"Play/Pause\", UsageTypes.OSC\n    PLAY_SKIP = 0x00CE, \"Play/Skip\", UsageTypes.OSC\n    VOLUME = 0x00E0, \"Volume\", UsageTypes.LC\n    BALANCE = 0x00E1, \"Balance\", UsageTypes.LC\n    MUTE = 0x00E2, \"Mute\", UsageTypes.OOC\n    BASS = 0x00E3, \"Bass\", UsageTypes.LC\n    TREBLE = 0x00E4, \"Treble\", UsageTypes.LC\n    BASS_BOOST = 0x00E5, \"Bass Boost\", UsageTypes.OOC\n    SURROUND_MODE = 0x00E6, \"Surround Mode\", UsageTypes.OSC\n    LOUDNESS = 0x00E7, \"Loudness\", UsageTypes.OOC\n    MPX = 0x00E8, \"MPX\", UsageTypes.OOC\n    VOLUME_INCREMENT = 0x00E9, \"Volume Increment\", UsageTypes.RTC\n    VOLUME_DECREMENT = 0x00EA, \"Volume Decrement\", UsageTypes.RTC\n    SPEED_SELECT = 0x00F0, \"Speed Select\", UsageTypes.OSC\n    PLAYBACK_SPEED = 0x00F1, \"Playback Speed\", UsageTypes.NARY\n    STANDARD_PLAY = 0x00F2, \"Standard Play\", UsageTypes.SEL\n    LONG_PLAY = 0x00F3, \"Long Play\", UsageTypes.SEL\n    EXTENDED_PLAY = 0x00F4, \"Extended Play\", UsageTypes.SEL\n    SLOW = 0x00F5, \"Slow\", UsageTypes.OSC\n    FAN_ENABLE = 0x0100, \"Fan Enable\", UsageTypes.OOC\n    FAN_SPEED = 0x0101, \"Fan Speed\", UsageTypes.LC\n    LIGHT_ENABLE = 0x0102, \"Light Enable\", UsageTypes.OOC\n    LIGHT_ILLUMINATION_LEVEL = 0x0103, \"Light Illumination Level\", UsageTypes.LC\n    CLIMATE_CONTROL_ENABLE = 0x0104, \"Climate Control Enable\", UsageTypes.OOC\n    ROOM_TEMPERATURE = 0x0105, \"Room Temperature\", UsageTypes.LC\n    SECURITY_ENABLE = 0x0106, \"Security Enable\", UsageTypes.OOC\n    FIRE_ALARM = 0x0107, \"Fire Alarm\", UsageTypes.OSC\n    POLICE_ALARM = 0x0108, \"Police Alarm\", UsageTypes.OSC\n    PROXIMITY = 0x0109, \"Proximity\", UsageTypes.LC\n    MOTION = 0x010A, \"Motion\", UsageTypes.OSC\n    DURESS_ALARM = 0x010B, \"Duress Alarm\", UsageTypes.OSC\n    HOLDUP_ALARM = 0x010C, \"Holdup Alarm\", UsageTypes.OSC\n    MEDICAL_ALARM = 0x010D, \"Medical Alarm\", UsageTypes.OSC\n    BALANCE_RIGHT = 0x0150, \"Balance Right\", UsageTypes.RTC\n    BALANCE_LEFT = 0x0151, \"Balance Left\", UsageTypes.RTC\n    BASS_INCREMENT = 0x0152, \"Bass Increment\", UsageTypes.RTC\n    BASS_DECREMENT = 0x0153, \"Bass Decrement\", UsageTypes.RTC\n    TREBLE_INCREMENT = 0x0154, \"Treble Increment\", UsageTypes.RTC\n    TREBLE_DECREMENT = 0x0155, \"Treble Decrement\", UsageTypes.RTC\n    SPEAKER_SYSTEM = 0x0160, \"Speaker System\", UsageTypes.CL\n    CHANNEL_LEFT = 0x0161, \"Channel Left\", UsageTypes.CL\n    CHANNEL_RIGHT = 0x0162, \"Channel Right\", UsageTypes.CL\n    CHANNEL_CENTER = 0x0163, \"Channel Center\", UsageTypes.CL\n    CHANNEL_FRONT = 0x0164, \"Channel Front\", UsageTypes.CL\n    CHANNEL_CENTER_FRONT = 0x0165, \"Channel Center Front\", UsageTypes.CL\n    CHANNEL_SIDE = 0x0166, \"Channel Side\", UsageTypes.CL\n    CHANNEL_SURROUND = 0x0167, \"Channel Surround\", UsageTypes.CL\n    CHANNEL_LOW_FREQUENCY_ENHANCEMENT = 0x0168, \"Channel Low Frequency Enhancement\", UsageTypes.CL\n    CHANNEL_TOP = 0x0169, \"Channel Top\", UsageTypes.CL\n    CHANNEL_UNKNOWN = 0x016A, \"Channel Unknown\", UsageTypes.CL\n    SUBCHANNEL = 0x0170, \"Sub-channel\", UsageTypes.LC\n    SUBCHANNEL_INCREMENT = 0x0171, \"Sub-channel Increment\", UsageTypes.OSC\n    SUBCHANNEL_DECREMENT = 0x0172, \"Sub-channel Decrement\", UsageTypes.OSC\n    ALTERNATE_AUDIO_INCREMENT = 0x0173, \"Alternate Audio Increment\", UsageTypes.OSC\n    ALTERNATE_AUDIO_DECREMENT = 0x0174, \"Alternate Audio Decrement\", UsageTypes.OSC\n    APPLICATION_LAUNCH_BUTTONS = 0x0180, \"Application Launch Buttons\", UsageTypes.NARY\n    AL_LAUCH_BUTTON_CONFIGURATION_TOOL = 0x0181, \"AL Launch Button Configuration Tool\", UsageTypes.SEL\n    AL_PROGRAMMABLE_BUTTON_CONFIGURATION = 0x0182, \"AL Programmable Button Configuration\", UsageTypes.SEL\n    AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183, \"AL Consumer Control Configuration\", UsageTypes.SEL\n    AL_WORD_PROCESSOR = 0x0184, \"AL Word Processor\", UsageTypes.SEL\n    AL_TEXT_EDITOR = 0x0185, \"AL Text Editor\", UsageTypes.SEL\n    AL_SPREADSHEET = 0x0186, \"AL Spreadsheet\", UsageTypes.SEL\n    AL_GRAPHICS_EDITOR = 0x0187, \"AL Graphics Editor\", UsageTypes.SEL\n    AL_PRESENTATION_APP = 0x0188, \"AL Presentation App\", UsageTypes.SEL\n    AL_DATABASE_APP = 0x0189, \"AL Database App\", UsageTypes.SEL\n    AL_EMAIL_READER = 0x018A, \"AL Email Reader\", UsageTypes.SEL\n    AL_NEWSREADER = 0x018B, \"AL Newsreader\", UsageTypes.SEL\n    AL_VOICEMAIL = 0x018C, \"AL Voicemail\", UsageTypes.SEL\n    AL_CONTACTS_ADDRESS_BOOK = 0x018D, \"AL Contacts/Address Book\", UsageTypes.SEL\n    AL_CALENDAR_SCHEDULE = 0x018E, \"AL Calendar/Schedule\", UsageTypes.SEL\n    AL_TASK_PROJECT_MANAGER = 0x018F, \"AL Task/Project Manager\", UsageTypes.SEL\n    AL_LOG_JOURNAL_TIMECARD = 0x0190, \"AL Log/Journal/Timecard\", UsageTypes.SEL\n    AL_CHECKBOOK_FINANCE = 0x0191, \"AL Checkbook/Finance\", UsageTypes.SEL\n    AL_CALCULATOR = 0x0192, \"AL Calculator\", UsageTypes.SEL\n    AL_AV_CAPTURE_PLAYBACK = 0x0193, \"AL A/V Capture/Playback\", UsageTypes.SEL\n    AL_LOCAL_MACHINE_BROWSER = 0x0194, \"AL Local Machine Browser\", UsageTypes.SEL\n    AL_LAN_WAN_BROWSER = 0x0195, \"AL LAN/WAN Browser\", UsageTypes.SEL\n    AL_INTERNET_BROWSER = 0x0196, \"AL Internet Browser\", UsageTypes.SEL\n    AL_REMOTE_NETWORKING_ISP_CONNECT = 0x0197, \"AL Remote Networking/ISP Connect\", UsageTypes.SEL\n    AL_NETWORK_CONFERENCE = 0x0198, \"AL Network Conference\", UsageTypes.SEL\n    AL_NETWORK_CHAT = 0x0199, \"AL Network Chat\", UsageTypes.SEL\n    AL_TELEPHONY_DIALER = 0x019A, \"AL Telephony/Dialer\", UsageTypes.SEL\n    AL_LOGON = 0x019B, \"AL Logon\", UsageTypes.SEL\n    AL_LOGOFF = 0x019C, \"AL Logoff\", UsageTypes.SEL\n    AL_LOGON_LOGOFF = 0x019D, \"AL Logon/Logoff\", UsageTypes.SEL\n    AL_LOCK_SCREEN_SAVER = 0x019E, \"AL Terminal Lock/Screensaver\", UsageTypes.SEL\n    AL_CONTROL_PANEL = 0x019F, \"AL Control Panel\", UsageTypes.SEL\n    AL_COMMAND_LINE_PROCESSOR_RUN = 0x01A0, \"AL Command Line Processor/Run\", UsageTypes.SEL\n    AL_PROCESS_TASK_MANAGER = 0x01A1, \"AL Process/Task Manager\", UsageTypes.SEL\n    AL_SELECT_TASK_APPLICATION = 0x01A2, \"AL Select Task/Application\", UsageTypes.SEL\n    AL_NEXT_TASK_APPLICATION = 0x01A3, \"AL Next Task/Application\", UsageTypes.SEL\n    AL_PREVIOUS_TASK_APPLICATION = 0x01A4, \"AL Previous Task/Application\", UsageTypes.SEL\n    AL_HALT_TASK_APPLICATION = 0x01A5, \"AL Preemptive Halt Task/Application\", UsageTypes.SEL\n    AL_INTEGRATED_HELP_CENTER = 0x01A6, \"AL Integrated Help Center\", UsageTypes.SEL\n    AL_DOCUMENTS = 0x01A7, \"AL Documents\", UsageTypes.SEL\n    AL_THESAURUS = 0x01A8, \"AL Thesaurus\", UsageTypes.SEL\n    AL_DICTIONARY = 0x01A9, \"AL Dictionary\", UsageTypes.SEL\n    AL_DESKTOP = 0x01AA, \"AL Desktop\", UsageTypes.SEL\n    AL_SPELL_CHECK = 0x01AB, \"AL Spell Check\", UsageTypes.SEL\n    AL_GRAMMAR_CHECK = 0x01AC, \"AL Grammar Check\", UsageTypes.SEL\n    AL_WIRELESS_STATUS = 0x01AD, \"AL Wireless Status\", UsageTypes.SEL\n    AL_KEYBOARD_LAYOUT = 0x01AE, \"AL Keyboard Layout\", UsageTypes.SEL\n    AL_VIRUS_PROTECTION = 0x01AF, \"AL Virus Protection\", UsageTypes.SEL\n    AL_ENCRYPTION = 0x01B0, \"AL Encryption\", UsageTypes.SEL\n    AL_SCREEN_SAVER = 0x01B1, \"AL Screen Saver\", UsageTypes.SEL\n    AL_ALARMS = 0x01B2, \"AL Alarms\", UsageTypes.SEL\n    AL_CLOCK = 0x01B3, \"AL Clock\", UsageTypes.SEL\n    AL_FILE_BROWSER = 0x01B4, \"AL File Browser\", UsageTypes.SEL\n    AL_POWER_STATUS = 0x01B5, \"AL Power Status\", UsageTypes.SEL\n    AL_IMAGE_BROWSER = 0x01B6, \"AL Image Browser\", UsageTypes.SEL\n    AL_AUDIO_BROWSER = 0x01B7, \"AL Audio Browser\", UsageTypes.SEL\n    AL_VIDEO_BROWSER = 0x01B8, \"AL Movie Browser\", UsageTypes.SEL\n    AL_DIGITAL_RIGHTS_MANAGER = 0x01B9, \"AL Digital Rights Manager\", UsageTypes.SEL\n    AL_DIGITAL_WALLET = 0x01BA, \"AL Digital Wallet\", UsageTypes.SEL\n    AL_INSTANT_MESSAGING = 0x01BC, \"AL Instant Messaging\", UsageTypes.SEL\n    AL_OEM_FEATURES_TIPS_TUTORIAL_BROWSER = 0x01BD, \"AL OEM Features/ Tips/Tutorial Browser\", UsageTypes.SEL\n    AL_OEM_HELP = 0x01BE, \"AL OEM Help\", UsageTypes.SEL\n    AL_ONLINE_COMMUNITY = 0x01BF, \"AL Online Community\", UsageTypes.SEL\n    AL_ENTERTAINMENT_CONTENT_BROWSER = 0x01C0, \"AL Entertainment Content Browser\", UsageTypes.SEL\n    AL_ONLINE_SHOPPING_BROWSER = 0x01C1, \"AL Online Shopping Browser\", UsageTypes.SEL\n    AL_SMARTCARD_INFORMATION_HELP = 0x01C2, \"AL SmartCard Information/Help\", UsageTypes.SEL\n    AL_MARKET_MONITOR_FINANCE_BROWSER = 0x01C3, \"AL Market Monitor/Finance Browser\", UsageTypes.SEL\n    AL_CUSTOMIZED_CORPORATE_NEWS_BROWSER = 0x01C4, \"AL Customized Corporate News Browser\", UsageTypes.SEL\n    AL_ONLINE_ACTIVITY_BROWSER = 0x01C5, \"AL Online Activity Browser\", UsageTypes.SEL\n    AL_RESEARCH_SEARCH_BROWSER = 0x01C6, \"AL Research/Search Browser\", UsageTypes.SEL\n    AL_AUDIO_PLAYER = 0x01C7, \"AL Audio Player\", UsageTypes.SEL\n    GENERIC_GUI_APPLICATION_CONTROLS = 0x0200, \"Generic GUI Application Controls\", UsageTypes.NARY\n    AC_NEW = 0x0201, \"AC New\", UsageTypes.SEL\n    AC_OPEN = 0x0202, \"AC Open\", UsageTypes.SEL\n    AC_CLOSE = 0x0203, \"AC Close\", UsageTypes.SEL\n    AC_EXIT = 0x0204, \"AC Exit\", UsageTypes.SEL\n    AC_MAXIMIZE = 0x0205, \"AC Maximize\", UsageTypes.SEL\n    AC_MINIMIZE = 0x0206, \"AC Minimize\", UsageTypes.SEL\n    AC_SAVE = 0x0207, \"AC Save\", UsageTypes.SEL\n    AC_PRINT = 0x0208, \"AC Print\", UsageTypes.SEL\n    AC_PROPERTIES = 0x0209, \"AC Properties\", UsageTypes.SEL\n    AC_UNDO = 0x021A, \"AC Undo\", UsageTypes.SEL\n    AC_COPY = 0x021B, \"AC Copy\", UsageTypes.SEL\n    AC_CUT = 0x021C, \"AC Cut\", UsageTypes.SEL\n    AC_PASTE = 0x021D, \"AC Paste\", UsageTypes.SEL\n    AC_SELECT_ALL = 0x021E, \"AC Select All\", UsageTypes.SEL\n    AC_FIND = 0x021F, \"AC Find\", UsageTypes.SEL\n    AC_FIND_AND_REPLACE = 0x0220, \"AC Find and Replace\", UsageTypes.SEL\n    AC_SEARCH = 0x0221, \"AC Search\", UsageTypes.SEL\n    AC_GO_TO = 0x0222, \"AC Go To\", UsageTypes.SEL\n    AC_HOME = 0x0223, \"AC Home\", UsageTypes.SEL\n    AC_BACK = 0x0224, \"AC Back\", UsageTypes.SEL\n    AC_FORWARD = 0x0225, \"AC Forward\", UsageTypes.SEL\n    AC_STOP = 0x0226, \"AC Stop\", UsageTypes.SEL\n    AC_REFRESH = 0x0227, \"AC Refresh\", UsageTypes.SEL\n    AC_PREVIOUS_LINK = 0x0228, \"AC Previous Link\", UsageTypes.SEL\n    AC_NEXT_LINK = 0x0229, \"AC Next Link\", UsageTypes.SEL\n    AC_BOOKMARKS = 0x022A, \"AC Bookmarks\", UsageTypes.SEL\n    AC_HISTORY = 0x022B, \"AC History\", UsageTypes.SEL\n    AC_SUBSCRIPTIONS = 0x022C, \"AC Subscriptions\", UsageTypes.SEL\n    AC_ZOOM_IN = 0x022D, \"AC Zoom In\", UsageTypes.SEL\n    AC_ZOOM_OUT = 0x022E, \"AC Zoom Out\", UsageTypes.SEL\n    AC_ZOOM = 0x022F, \"AC Zoom\", UsageTypes.LC\n    AC_FULL_SCREEN_VIEW = 0x0230, \"AC Full Screen View\", UsageTypes.SEL\n    AC_NORMAL_VIEW = 0x0231, \"AC Normal View\", UsageTypes.SEL\n    AC_VIEW_TOGGLE = 0x0232, \"AC View Toggle\", UsageTypes.SEL\n    AC_SCROLL_UP = 0x0233, \"AC Scroll Up\", UsageTypes.SEL\n    AC_SCROLL_DOWN = 0x0234, \"AC Scroll Down\", UsageTypes.SEL\n    AC_SCROLL = 0x0235, \"AC Scroll\", UsageTypes.LC\n    AC_PAN_LEFT = 0x0236, \"AC Pan Left\", UsageTypes.SEL\n    AC_PAN_RIGHT = 0x0237, \"AC Pan Right\", UsageTypes.SEL\n    AC_PAN = 0x0238, \"AC Pan\", UsageTypes.LC\n    AC_NEW_WINDOWS = 0x0239, \"AC New Window\", UsageTypes.SEL\n    AC_TILE_HORIZONTALLY = 0x023A, \"AC Tile Horizontally\", UsageTypes.SEL\n    AC_TILE_VERTICALLY = 0x023B, \"AC Tile Vertically\", UsageTypes.SEL\n    AC_FORMAT = 0x023C, \"AC Format\", UsageTypes.SEL\n    AC_EDIT = 0x023D, \"AC Edit\", UsageTypes.SEL\n    AC_BOLD = 0x023E, \"AC Bold\", UsageTypes.SEL\n    AC_ITALICS = 0x023F, \"AC Italics\", UsageTypes.SEL\n    AC_UNDERLINE = 0x0240, \"AC Underline\", UsageTypes.SEL\n    AC_STRIKETHROUGH = 0x0241, \"AC Strikethrough\", UsageTypes.SEL\n    AC_SUBSCRIPT = 0x0242, \"AC Subscript\", UsageTypes.SEL\n    AC_SUPERSCRIPT = 0x0243, \"AC Superscript\", UsageTypes.SEL\n    AC_ALL_CAPS = 0x0244, \"AC All Caps\", UsageTypes.SEL\n    AC_ROTATE = 0x0245, \"AC Rotate\", UsageTypes.SEL\n    AC_RESIZE = 0x0246, \"AC Resize\", UsageTypes.SEL\n    AC_FLIP_HORIZONTAL = 0x0247, \"AC Flip horizontal\", UsageTypes.SEL\n    AC_FLIP_VERTICAL = 0x0248, \"AC Flip Vertical\", UsageTypes.SEL\n    AC_MIRROR_HORIZONTAL = 0x0249, \"AC Mirror Horizontal\", UsageTypes.SEL\n    AC_MIRROR_VERTICAL = 0x024A, \"AC Mirror Vertical\", UsageTypes.SEL\n    AC_FONT_SELECT = 0x024B, \"AC Font Select\", UsageTypes.SEL\n    AC_FONT_COLOR = 0x024C, \"AC Font Color\", UsageTypes.SEL\n    AC_FONT_SIZE = 0x024D, \"AC Font Size\", UsageTypes.SEL\n    AC_JUSTIFY_LEFT = 0x024E, \"AC Justify Left\", UsageTypes.SEL\n    AC_JUSTIFY_CENTER_H = 0x024F, \"AC Justify Center H\", UsageTypes.SEL\n    AC_JUSTIFY_RIGHT = 0x0250, \"AC Justify Right\", UsageTypes.SEL\n    AC_JUSTIFY_BLOCK_H = 0x0251, \"AC Justify Block H\", UsageTypes.SEL\n    AC_JUSTIFY_TOP = 0x0252, \"AC Justify Top\", UsageTypes.SEL\n    AC_JUSTIFY_CENTER_V = 0x0253, \"AC Justify Center V\", UsageTypes.SEL\n    AC_JUSTIFY_BOTTOM = 0x0254, \"AC Justify Bottom\", UsageTypes.SEL\n    AC_JUSTIFY_BLOCK_V = 0x0255, \"AC Justify Block V\", UsageTypes.SEL\n    AC_INDENT_INCREASE = 0x0256, \"AC Indent Decrease\", UsageTypes.SEL\n    AC_INDENT_DECREASE = 0x0257, \"AC Indent Increase\", UsageTypes.SEL\n    AC_NUMBERED_LIST = 0x0258, \"AC Numbered List\", UsageTypes.SEL\n    AC_RESTART_NUMBERING = 0x0259, \"AC Restart Numbering\", UsageTypes.SEL\n    AC_BULLETED_LIST = 0x025A, \"AC Bulleted List\", UsageTypes.SEL\n    AC_PROMOTE = 0x025B, \"AC Promote\", UsageTypes.SEL\n    AC_DEMOTE = 0x025C, \"AC Demote\", UsageTypes.SEL\n    AC_YES = 0x025D, \"AC Yes\", UsageTypes.SEL\n    AC_NO = 0x025E, \"AC No\", UsageTypes.SEL\n    AC_CANCEL = 0x025F, \"AC Cancel\", UsageTypes.SEL\n    AC_CATALOG = 0x0260, \"AC Catalog\", UsageTypes.SEL\n    AC_BUY_CHECKOUT = 0x0261, \"AC Buy/Checkout\", UsageTypes.SEL\n    AC_ADD_TO_CART = 0x0262, \"AC Add to Cart\", UsageTypes.SEL\n    AC_EXPAND = 0x0263, \"AC Expand\", UsageTypes.SEL\n    AC_EXPAND_ALL = 0x0264, \"AC Expand All\", UsageTypes.SEL\n    AC_COLLAPSE = 0x0265, \"AC Collapse\", UsageTypes.SEL\n    AC_COLLAPSE_ALL = 0x0266, \"AC Collapse All\", UsageTypes.SEL\n    AC_PRINT_PREVIEW = 0x0267, \"AC Print Preview\", UsageTypes.SEL\n    AC_PASTE_SPECIAL = 0x0268, \"AC Paste Special\", UsageTypes.SEL\n    AC_INSER_MODE = 0x0269, \"AC Insert Mode\", UsageTypes.SEL\n    AC_DELETE = 0x026A, \"AC Delete\", UsageTypes.SEL\n    AC_LOCK = 0x026B, \"AC Lock\", UsageTypes.SEL\n    AC_UNLOCK = 0x026C, \"AC Unlock\", UsageTypes.SEL\n    AC_PROTECT = 0x026D, \"AC Protect\", UsageTypes.SEL\n    AC_UNPROTECT = 0x026E, \"AC Unprotect\", UsageTypes.SEL\n    AC_ATTACH_COMMENT = 0x026F, \"AC Attach Comment\", UsageTypes.SEL\n    AC_DELETE_COMMENT = 0x0270, \"AC Delete Comment\", UsageTypes.SEL\n    AC_VIEW_COMMENT = 0x0271, \"AC View Comment\", UsageTypes.SEL\n    AC_SELECT_WORD = 0x0272, \"AC Select Word\", UsageTypes.SEL\n    AC_SELECT_SENTENCE = 0x0273, \"AC Select Sentence\", UsageTypes.SEL\n    AC_SELECT_PARAGRAPH = 0x0274, \"AC Select Paragraph\", UsageTypes.SEL\n    AC_SELECT_COLUMN = 0x0275, \"AC Select Column\", UsageTypes.SEL\n    AC_SELECT_ROW = 0x0276, \"AC Select Row\", UsageTypes.SEL\n    AC_SELECT_TABLE = 0x0277, \"AC Select Table\", UsageTypes.SEL\n    AC_SELECT_OBJECT = 0x0278, \"AC Select Object\", UsageTypes.SEL\n    AC_REDO_REPEAT = 0x0279, \"AC Redo/Repeat\", UsageTypes.SEL\n    AC_SORT = 0x027A, \"AC Sort\", UsageTypes.SEL\n    AC_SORT_ASCENDING = 0x027B, \"AC Sort Ascending\", UsageTypes.SEL\n    AC_SORT_DESCENDING = 0x027C, \"AC Sort Descending\", UsageTypes.SEL\n    AC_FILTER = 0x027D, \"AC Filter\", UsageTypes.SEL\n    AC_SET_CLOCK = 0x027E, \"AC Set Clock\", UsageTypes.SEL\n    AC_VIEW_CLOCK = 0x027F, \"AC View Clock\", UsageTypes.SEL\n    AC_SELECT_TIME_ZONE = 0x0280, \"AC Select Time Zone\", UsageTypes.SEL\n    AC_EDIT_TIME_ZONES = 0x0281, \"AC Edit Time Zones\", UsageTypes.SEL\n    AC_SET_ALARM = 0x0282, \"AC Set Alarm\", UsageTypes.SEL\n    AC_CLEAR_ALARM = 0x0283, \"AC Clear Alarm\", UsageTypes.SEL\n    AC_SNOOZE_ALARM = 0x0284, \"AC Snooze Alarm\", UsageTypes.SEL\n    AC_RESET_ALARM = 0x0285, \"AC Reset Alarm\", UsageTypes.SEL\n    AC_SYNCHRONIZE = 0x0286, \"AC Synchronize\", UsageTypes.SEL\n    AC_SEND_RECEIVE = 0x0287, \"AC Send/Receive\", UsageTypes.SEL\n    AC_SEND_TO = 0x0288, \"AC Send To\", UsageTypes.SEL\n    AC_REPLY = 0x0289, \"AC Reply\", UsageTypes.SEL\n    AC_REPLY_ALL = 0x028A, \"AC Reply All\", UsageTypes.SEL\n    AC_FORWARD_MSG = 0x028B, \"AC Forward Msg\", UsageTypes.SEL\n    AC_SEND = 0x028C, \"AC Send\", UsageTypes.SEL\n    AC_ATTACH_FILE = 0x028D, \"AC Attach File\", UsageTypes.SEL\n    AC_UPLOAD = 0x028E, \"AC Upload\", UsageTypes.SEL\n    AC_DOWNLOAD = 0x028F, \"AC Download (Save Target As)\", UsageTypes.SEL\n    AC_SET_BORDERS = 0x0290, \"AC Set Borders\", UsageTypes.SEL\n    AC_INSERT_ROW = 0x0291, \"AC Insert Row\", UsageTypes.SEL\n    AC_INSERT_COLUMN = 0x0292, \"AC Insert Column\", UsageTypes.SEL\n    AC_INSERT_FILE = 0x0293, \"AC Insert File\", UsageTypes.SEL\n    AC_INSERT_PICTURE = 0x0294, \"AC Insert Picture\", UsageTypes.SEL\n    AC_INSERT_OBJECT = 0x0295, \"AC Insert Object\", UsageTypes.SEL\n    AC_INSERT_SYMBOL = 0x0296, \"AC Insert Symbol\", UsageTypes.SEL\n    AC_SAVE_AND_CLOSE = 0x0297, \"AC Save and Close\", UsageTypes.SEL\n    AC_RENAME = 0x0298, \"AC Rename\", UsageTypes.SEL\n    AC_MERGE = 0x0299, \"AC Merge\", UsageTypes.SEL\n    AC_SPLIT = 0x029A, \"AC Split\", UsageTypes.SEL\n    AC_DISTRIBUTE_HORIZONTICALLY = 0x029B, \"AC Disribute Horizontally\", UsageTypes.SEL\n    AC_DISTRIBUTE_VERTICALLY = 0x029C, \"AC Distribute Vertically\", UsageTypes.SEL\n\n\nclass PowerDevice(_Data):\n    INAME = 0x01, \"iName\", UsageTypes.SV\n    PRESENT_STATUS = 0x02, \"PresentStatus\", UsageTypes.CL\n    CHARGED_STATUS = 0x03, \"ChangedStatus\", UsageTypes.CL\n    UPS = 0x04, \"UPS\", UsageTypes.CA\n    POWER_SUPPLY = 0x05, \"PowerSupply\", UsageTypes.CA\n    BATTERY_SYSTEM = 0x10, \"BatterySystem\", UsageTypes.CP\n    BATTERY_SYSTEM_ID = 0x11, \"BatterySystemID\", UsageTypes.SV\n    BATTERY = 0x12, \"Battery\", UsageTypes.CP\n    BATTERY_ID = 0x13, \"BatteryID\", UsageTypes.SV\n    CHARGER = 0x14, \"Charger\", UsageTypes.CP\n    CHARGER_ID = 0x15, \"ChargerID\", UsageTypes.SV\n    POWER_CONVERTER = 0x16, \"PowerConverter\", UsageTypes.CP\n    POWER_CONVERTER_ID = 0x17, \"PowerConverterID\", UsageTypes.SV\n    OUTLET_SYSTEM = 0x18, \"OutletSystem\", UsageTypes.CP\n    OUTLET_SYSTEM_ID = 0x19, \"OutletSystemID\", UsageTypes.SV\n    INPUT = 0x1A, \"Input\", UsageTypes.CP\n    INPUT_ID = 0x1B, \"InputID\", UsageTypes.SV\n    OUTPUT = 0x1C, \"Output\", UsageTypes.CP\n    OUTPUT_ID = 0x1D, \"OutputID\", UsageTypes.SV\n    FLOW = 0x1E, \"Flow\", UsageTypes.CP\n    FLOW_ID = 0x1F, \"FlowID\", UsageTypes.SV\n    OUTLET = 0x20, \"Outlet\", UsageTypes.CP\n    OUTLET_ID = 0x21, \"OutletID\", UsageTypes.SV\n    GANG = 0x22, \"Gang\", UsageTypes.CP\n    GANG_ID = 0x23, \"GangID\", UsageTypes.SV\n    POWER_SUMMARY = 0x24, \"PowerSummary\", UsageTypes.CP\n    POWER_SUMMARY_ID = 0x25, \"PowerSummaryID\", UsageTypes.SV\n    VOLTAGE = 0x30, \"Voltage\", UsageTypes.DV\n    CURRENT = 0x31, \"Current\", UsageTypes.DV\n    FREQUENCY = 0x32, \"Frequency\", UsageTypes.DV\n    APPARENT_POWER = 0x33, \"ApparentPower\", UsageTypes.DV\n    ACTIVE_POWER = 0x34, \"ActivePower\", UsageTypes.DV\n    PERCENT_LOAD = 0x35, \"PercentLoad\", UsageTypes.DV\n    TEMPERATURE = 0x36, \"Temperature\", UsageTypes.DV\n    HUMIFITY = 0x37, \"Humidity\", UsageTypes.DV\n    BAD_COUNT = 0x38, \"BadCount\", UsageTypes.DV\n    CONFIG_VOLTAGE = 0x40, \"ConfigVoltage\", (UsageTypes.SV, UsageTypes.DV)\n    CONFIG_CURRENT = 0x41, \"ConfigCurrent\", (UsageTypes.SV, UsageTypes.DV)\n    CONFIG_FREQUENCY = 0x42, \"ConfigFrequency\", (UsageTypes.SV, UsageTypes.DV)\n    CONFIG_APPARENT_POWER = 0x43, \"ConfigApparentPower\", (UsageTypes.SV, UsageTypes.DV)\n    CONFIG_ACTIVE_POWER = 0x44, \"ConfigActivePower\", (UsageTypes.SV, UsageTypes.DV)\n    CONFIG_PERCENT_LOAD = 0x45, \"ConfigPercentLoad\", (UsageTypes.SV, UsageTypes.DV)\n    CONFIG_TEMPERATURE = 0x46, \"ConfigTemperature\", (UsageTypes.SV, UsageTypes.DV)\n    CONFIG_HUMIFITY = 0x47, \"ConfigHumidity\", (UsageTypes.SV, UsageTypes.DV)\n    SWITCH_ON_CONTROL = 0x50, \"SwitchOnControl\", UsageTypes.DV\n    SWITCH_OFF_CONTROL = 0x51, \"SwitchOffControl\", UsageTypes.DV\n    TOGGLE_CONTROL = 0x52, \"ToggleControl\", UsageTypes.DV\n    LOW_VOLTAGE_TRANSFER = 0x53, \"LowVoltageTransfer\", UsageTypes.DV\n    HIGH_VOLTAGE_TRANSFER = 0x54, \"HighVoltageTransfer\", UsageTypes.DV\n    DELAY_BEFORE_REBOOT = 0x55, \"DelayBeforeReboot\", UsageTypes.DV\n    DELAY_BEFORE_STARTUP = 0x56, \"DelayBeforeStartup\", UsageTypes.DV\n    DELAY_BEFORE_SHUTDOWN = 0x57, \"DelayBeforeShutdown\", UsageTypes.DV\n    TEST = 0x58, \"Test\", UsageTypes.DV\n    MODULE_RESET = 0x59, \"ModuleReset\", UsageTypes.DV\n    AUDIBLE_ALARM_CONTROL = 0x5A, \"AudibleAlarmControl\", UsageTypes.DV\n    PRESENT = 0x60, \"Present\", UsageTypes.DF\n    GOOD = 0x61, \"Good\", UsageTypes.DF\n    INTERNAL_FAILURE = 0x62, \"InternalFailure\", UsageTypes.DF\n    VOLTAGE_OUT_OF_RANGE = 0x63, \"VoltageOutOfRange\", UsageTypes.DF\n    FREQUENCY_OUT_OF_RANGE = 0x64, \"FrequencyOutOfRange\", UsageTypes.DF\n    OVERLOAD = 0x65, \"Overload\", UsageTypes.DF\n    OVERCHARGED = 0x66, \"OverCharged\", UsageTypes.DF\n    OVER_TEMPERATURE = 0x67, \"OverTemperature\", UsageTypes.DF\n    SHUTDOWN_REQUESTED = 0x68, \"ShutdownRequested\", UsageTypes.DF\n    SHUTDOWN_IMMINEBT = 0x69, \"ShutdownImminent\", UsageTypes.DF\n    SWITCH_ON_OFF = 0x6B, \"SwitchOn/Off\", UsageTypes.DF\n    SWITCHABLE = 0x6C, \"Switchable\", UsageTypes.DF\n    USED = 0x6D, \"Used\", UsageTypes.DF\n    BOOST = 0x6E, \"Boost\", UsageTypes.DF\n    BUCK = 0x6F, \"Buck\", UsageTypes.DF\n    INITIALIZED = 0x70, \"Initialized\", UsageTypes.DF\n    TESTED = 0x71, \"Tested\", UsageTypes.DF\n    AWAITING_POWER = 0x72, \"AwaitingPower\", UsageTypes.DF\n    COMMUNICATION_LOST = 0x73, \"CommunicationLost\", UsageTypes.DF\n    IMANUFACTURER = 0xFD, \"iManufacturer\", UsageTypes.SV\n    IPRODUCT = 0xFE, \"iProduct\", UsageTypes.SV\n    ISERIALNUMBER = 0xFF, \"iSerialNumber\", UsageTypes.SV\n\n\nclass FIDO(_Data):\n    U2F_AUTHENTICATOR_DEVICEM = 0x01, \"U2F Authenticator Device\"\n    INPUT_REPORT_DATA = 0x20, \"Input Report Data\"\n    OUTPUT_REPORT_DATA = 0x21, \"Output Report Data\"\n\n\nclass UsagePages(_Data):\n    GENERIC_DESKTOP_CONTROLS_PAGE = 0x01, \"Generic Desktop Controls\", GenericDesktopControls\n    SIMULATION_CONTROLS_PAGE = 0x02, \"Simulation Controls\"\n    VR_CONTROLS_PAGE = 0x03, \"VR Controls\"\n    SPORT_CONTROLS_PAGE = 0x04, \"Sport Controls\"\n    GAME_CONTROLS_PAGE = 0x05, \"Game Controls\"\n    GENERIC_DEVICE_CONTROLS_PAGE = 0x06, \"Generic Device Controls\"\n    KEYBOARD_KEYPAD_PAGE = 0x07, \"Keyboard/Keypad\", KeyboardKeypad\n    LED_PAGE = 0x08, \"LED\", Led\n    BUTTON_PAGE = 0x09, \"Button\", Button\n    ORDINAL_PAGE = 0x0A, \"Ordinal\"\n    TELEPHONY_PAGE = 0x0B, \"Telephony\"\n    CONSUMER_PAGE = 0x0C, \"Consumer\", Consumer\n    DIGITIZER_PAGE = 0x0D, \"Digitizer\"\n    HAPTICS_PAGE = 0x0E, \"Haptics\"\n    PID_PAGE = 0x0F, \"PID\"\n    UNICODE_PAGE = 0x10, \"Unicode\"\n    EYE_AND_HEAD_TRACKER_PAGE = 0x12, \"Eye and Head Tracker\"\n    ALPHANUMERIC_DISPLAY_PAGE = 0x14, \"Alphanumeric Display\"\n    SENSOR_PAGE = 0x20, \"Sensor\"\n    MEDICAL_INSTRUMENTS_PAGE = 0x40, \"Medical Instruments\"\n    BRAILLE_DISPLAY_PAGE = 0x41, \"Braillie\"\n    LIGHTING_AND_ILLUMINATION_PAGE = 0x59, \"Lighting and Illumination\"\n    USB_MONITOR_PAGE = 0x80, \"USB Monitor\"\n    USB_ENUMERATED_VALUES_PAGE = 0x81, \"USB Enumerated Values\"\n    VESA_VIRTUAL_CONTROLS_PAGE = 0x82, \"VESA Virtual Controls\"\n    POWER_DEVICE_PAGE = 0x84, \"Power Device\", PowerDevice\n    BATTERY_SYSTEM_PAGE = 0x85, \"Battery System\"\n    BARCODE_SCANNER_PAGE = 0x8C, \"Barcode Scanner\"\n    WEIGHING_PAGE = 0x8D, \"Weighing\"\n    MSR_PAGE = 0x8E, \"MSR\"\n    RESERVED_POS_PAGE = 0x8F, \"Reserved POS\"\n    CAMERA_CONTROL_PAGE = 0x90, \"Camera Control\"\n    ARCADE_PAGE = 0x91, \"Arcade\"\n    GAMING_DEVICE_PAGE = 0x92, \"Gaming Device\"\n    FIDO_ALLIANCE_PAGE = 0xF1D0, \"FIDO Alliance\", FIDO\n    VENDOR_PAGE = 0xFF00, ..., 0xFFFF, \"Vendor Page\"\n"
  },
  {
    "path": "lib/hidapi/__init__.py",
    "content": ""
  },
  {
    "path": "lib/hidapi/common.py",
    "content": "from __future__ import annotations\n\nimport dataclasses\n\n\n@dataclasses.dataclass\nclass DeviceInfo:\n    path: str\n    bus_id: str | None\n    vendor_id: str\n    product_id: str\n    interface: str | None\n    driver: str | None\n    manufacturer: str | None\n    product: str | None\n    serial: str | None\n    release: str | None\n    isDevice: bool\n    hidpp_short: str | None\n    hidpp_long: str | None\n"
  },
  {
    "path": "lib/hidapi/hidapi_impl.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\"\"\"Generic Human Interface Device API.\n\nThis provides a python interface to libusb's hidapi library which,\nunlike udev, is available for non-linux platforms.\nSee https://github.com/libusb/hidapi for how to obtain binaries.\n\nParts of this code are adapted from https://github.com/apmorton/pyhidapi\nwhich is MIT licensed.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport atexit\nimport ctypes\nimport logging\nimport platform\nimport typing\n\nfrom threading import Thread\nfrom time import sleep\nfrom typing import Any\nfrom typing import Callable\n\nfrom hidapi.common import DeviceInfo\n\nLOGITECH_VENDOR_ID = 0x046D\n\nif typing.TYPE_CHECKING:\n    import gi\n\n    gi.require_version(\"Gdk\", \"3.0\")\n    from gi.repository import GLib  # NOQA: E402\n\nlogger = logging.getLogger(__name__)\n\nACTION_ADD = \"add\"\nACTION_REMOVE = \"remove\"\n\n# Global handle to hidapi\n_hidapi = None\n\n# hidapi binary names for various platforms\n_library_paths = (\n    \"libhidapi-hidraw.so\",\n    \"libhidapi-hidraw.so.0\",\n    \"libhidapi-libusb.so\",\n    \"libhidapi-libusb.so.0\",\n    \"libhidapi-iohidmanager.so\",\n    \"libhidapi-iohidmanager.so.0\",\n    \"libhidapi.dylib\",\n    \"hidapi.dll\",\n    \"libhidapi-0.dll\",\n)\n\nfor lib in _library_paths:\n    try:\n        _hidapi = ctypes.cdll.LoadLibrary(lib)\n        break\n    except OSError:\n        pass\nelse:\n    raise ImportError(f\"Unable to load hidapi library, tried: {' '.join(_library_paths)}\")\n\n\n# Retrieve version of hdiapi library\nclass _cHidApiVersion(ctypes.Structure):\n    _fields_ = [\n        (\"major\", ctypes.c_int),\n        (\"minor\", ctypes.c_int),\n        (\"patch\", ctypes.c_int),\n    ]\n\n\n_hidapi.hid_version.argtypes = []\n_hidapi.hid_version.restype = ctypes.POINTER(_cHidApiVersion)\n_hid_version = _hidapi.hid_version()\n\n\n# Construct device info struct based on API version\nclass _cDeviceInfo(ctypes.Structure):\n    def as_dict(self):\n        return {name: getattr(self, name) for name, _t in self._fields_ if name != \"next\"}\n\n\n# Low level hdiapi device info struct\n# See https://github.com/libusb/hidapi/blob/master/hidapi/hidapi.h#L143\n_cDeviceInfo_fields = [\n    (\"path\", ctypes.c_char_p),\n    (\"vendor_id\", ctypes.c_ushort),\n    (\"product_id\", ctypes.c_ushort),\n    (\"serial_number\", ctypes.c_wchar_p),\n    (\"release_number\", ctypes.c_ushort),\n    (\"manufacturer_string\", ctypes.c_wchar_p),\n    (\"product_string\", ctypes.c_wchar_p),\n    (\"usage_page\", ctypes.c_ushort),\n    (\"usage\", ctypes.c_ushort),\n    (\"interface_number\", ctypes.c_int),\n    (\"next\", ctypes.POINTER(_cDeviceInfo)),\n]\nif _hid_version.contents.major >= 0 and _hid_version.contents.minor >= 13:\n    _cDeviceInfo_fields.append((\"bus_type\", ctypes.c_int))\n_cDeviceInfo._fields_ = _cDeviceInfo_fields\n\n# Set up hidapi functions\n_hidapi.hid_init.argtypes = []\n_hidapi.hid_init.restype = ctypes.c_int\n_hidapi.hid_exit.argtypes = []\n_hidapi.hid_exit.restype = ctypes.c_int\n_hidapi.hid_enumerate.argtypes = [ctypes.c_ushort, ctypes.c_ushort]\n_hidapi.hid_enumerate.restype = ctypes.POINTER(_cDeviceInfo)\n_hidapi.hid_free_enumeration.argtypes = [ctypes.POINTER(_cDeviceInfo)]\n_hidapi.hid_free_enumeration.restype = None\n_hidapi.hid_open.argtypes = [ctypes.c_ushort, ctypes.c_ushort, ctypes.c_wchar_p]\n_hidapi.hid_open.restype = ctypes.c_void_p\n_hidapi.hid_open_path.argtypes = [ctypes.c_char_p]\n_hidapi.hid_open_path.restype = ctypes.c_void_p\n_hidapi.hid_write.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]\n_hidapi.hid_write.restype = ctypes.c_int\n_hidapi.hid_read_timeout.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t, ctypes.c_int]\n_hidapi.hid_read_timeout.restype = ctypes.c_int\n_hidapi.hid_read.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]\n_hidapi.hid_read.restype = ctypes.c_int\n_hidapi.hid_get_input_report.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]\n_hidapi.hid_get_input_report.restype = ctypes.c_int\n_hidapi.hid_set_nonblocking.argtypes = [ctypes.c_void_p, ctypes.c_int]\n_hidapi.hid_set_nonblocking.restype = ctypes.c_int\n_hidapi.hid_send_feature_report.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int]\n_hidapi.hid_send_feature_report.restype = ctypes.c_int\n_hidapi.hid_get_feature_report.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t]\n_hidapi.hid_get_feature_report.restype = ctypes.c_int\n_hidapi.hid_close.argtypes = [ctypes.c_void_p]\n_hidapi.hid_close.restype = None\n_hidapi.hid_get_manufacturer_string.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_size_t]\n_hidapi.hid_get_manufacturer_string.restype = ctypes.c_int\n_hidapi.hid_get_product_string.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_size_t]\n_hidapi.hid_get_product_string.restype = ctypes.c_int\n_hidapi.hid_get_serial_number_string.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_size_t]\n_hidapi.hid_get_serial_number_string.restype = ctypes.c_int\n_hidapi.hid_get_indexed_string.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_wchar_p, ctypes.c_size_t]\n_hidapi.hid_get_indexed_string.restype = ctypes.c_int\n_hidapi.hid_error.argtypes = [ctypes.c_void_p]\n_hidapi.hid_error.restype = ctypes.c_wchar_p\n\n# Initialize hidapi\n_hidapi.hid_init()\natexit.register(_hidapi.hid_exit)\n\n# Solaar opens the same device more than once which will fail unless we\n# allow non-exclusive opening. On windows opening with shared access is\n# the default, for macOS we need to set it explicitly.\nif platform.system() == \"Darwin\":\n    _hidapi.hid_darwin_set_open_exclusive.argtypes = [ctypes.c_int]\n    _hidapi.hid_darwin_set_open_exclusive.restype = None\n    _hidapi.hid_darwin_set_open_exclusive(0)\n\n\nclass HIDError(Exception):\n    pass\n\n\ndef _enumerate_devices():\n    \"\"\"Returns all HID devices which are potentially useful to us\"\"\"\n    devices = []\n    c_devices = _hidapi.hid_enumerate(0, 0)\n    p = c_devices\n    while p:\n        devices.append(p.contents.as_dict())\n        p = p.contents.next\n    _hidapi.hid_free_enumeration(c_devices)\n\n    unique_devices = {}\n    for device in devices:\n        # hidapi returns separate entries for each usage page of a device.\n        # Deduplicate by path to only keep one device entry.\n        if device[\"path\"] not in unique_devices:\n            unique_devices[device[\"path\"]] = device\n\n    unique_devices = unique_devices.values()\n    # print(\"Unique devices:\\n\" + '\\n'.join([f\"{dev}\" for dev in unique_devices]))\n    return unique_devices\n\n\n# Use a separate thread to check if devices have been removed or connected\nclass _DeviceMonitor(Thread):\n    def __init__(self, device_callback, polling_delay=5.0):\n        self.device_callback = device_callback\n        self.polling_delay = polling_delay\n        self.prev_devices = None\n        # daemon threads are automatically killed when main thread exits\n        super().__init__(daemon=True)\n\n    def run(self):\n        # Populate initial set of devices so startup doesn't cause any callbacks\n        self.prev_devices = {tuple(dev.items()): dev for dev in _enumerate_devices()}\n\n        # Continously enumerate devices and raise callback for changes\n        while True:\n            current_devices = {tuple(dev.items()): dev for dev in _enumerate_devices()}\n            for key, device in self.prev_devices.items():\n                if key not in current_devices:\n                    self.device_callback(ACTION_REMOVE, device)\n            for key, device in current_devices.items():\n                if key not in self.prev_devices:\n                    self.device_callback(ACTION_ADD, device)\n            self.prev_devices = current_devices\n            sleep(self.polling_delay)\n\n\ndef _match(\n    action: str,\n    device: dict[str, Any],\n    filter_func: Callable[[int, int, int, bool, bool], dict[str, Any]],\n):\n    \"\"\"\n    The filter_func is used to determine whether this is a device of\n    interest to Solaar. It is given the bus id, vendor id, and product\n    id and returns a dictionary with the required hid_driver and\n    usb_interface and whether this is a receiver or device.\n    \"\"\"\n\n    vid = device[\"vendor_id\"]\n    pid = device[\"product_id\"]\n    hid_bus_type = device[\"bus_type\"]\n\n    # Translate hidapi bus_type to the bus_id values Solaar expects\n    if device.get(\"bus_type\") == 0x01:\n        bus_id = 0x03  # USB\n    elif device.get(\"bus_type\") == 0x02:\n        bus_id = 0x05  # Bluetooth\n    else:\n        bus_id = None\n        logger.info(f\"Device {device['path']} has an unsupported bus type {hid_bus_type:02X}\")\n        return None\n\n    # Skip unlikely devices with all-zero VID PID or unsupported bus IDs\n    if vid == 0 and pid == 0:\n        logger.info(f\"Device {device['path']} has all-zero VID and PID\")\n        logger.info(f\"Skipping unlikely device {device['path']} ({bus_id}/{vid:04X}/{pid:04X})\")\n        return None\n\n    # Skip Logitech webcams to prevent them from locking up during hidpp checks\n    # (product IDs range for webcams from docs/usb.ids.txt)\n    if vid == LOGITECH_VENDOR_ID and 0x0800 <= pid <= 0x09FF:\n        logger.info(f\"Skipping Logitech webcam {device['path']} ({bus_id}/{vid:04X}/{pid:04X})\")\n        return None\n\n    # Check for hidpp support\n    device[\"hidpp_short\"] = False\n    device[\"hidpp_long\"] = False\n    device_handle = None\n\n    def check_hidpp_short():\n        report = _get_input_report(device_handle, 0x10, 32)\n        if len(report) == 1 + 6 and report[0] == 0x10:\n            device[\"hidpp_short\"] = True\n\n    def check_hidpp_long():\n        report = _get_input_report(device_handle, 0x11, 32)\n        if len(report) == 1 + 19 and report[0] == 0x11:\n            device[\"hidpp_long\"] = True\n\n    try:\n        device_handle = open_path(device[\"path\"])\n\n        for check_func in (check_hidpp_short, check_hidpp_long):\n            try:\n                check_func()\n            except HIDError as e:\n                logger.info(\n                    f\"Error while {check_func.__name__}\"\n                    f\"on device {device['path']} ({bus_id}/{vid:04X}/{pid:04X}) for hidpp check: {e}\"\n                )\n    except HIDError as e:\n        logger.info(f\"Error opening device {device['path']} ({bus_id}/{vid:04X}/{pid:04X}) for hidpp check: {e}\")\n    finally:\n        if device_handle:\n            close(device_handle)\n\n    logger.info(\n        \"Found device BID %s VID %04X PID %04X HID++ SHORT %s LONG %s\",\n        bus_id,\n        vid,\n        pid,\n        device[\"hidpp_short\"],\n        device[\"hidpp_long\"],\n    )\n\n    if not device[\"hidpp_short\"] and not device[\"hidpp_long\"]:\n        return None\n\n    filtered_result = filter_func(bus_id, vid, pid, device[\"hidpp_short\"], device[\"hidpp_long\"])\n    if not filtered_result:\n        return\n    is_device = filtered_result.get(\"isDevice\")\n\n    if action == ACTION_ADD:\n        d_info = DeviceInfo(\n            path=device[\"path\"].decode(),\n            bus_id=bus_id,\n            vendor_id=f\"{vid:04X}\",  # noqa\n            product_id=f\"{pid:04X}\",  # noqa\n            interface=None,\n            driver=None,\n            manufacturer=device[\"manufacturer_string\"],\n            product=device[\"product_string\"],\n            serial=device[\"serial_number\"],\n            release=device[\"release_number\"],\n            isDevice=is_device,\n            hidpp_short=device[\"hidpp_short\"],\n            hidpp_long=device[\"hidpp_long\"],\n        )\n        return d_info\n\n    elif action == ACTION_REMOVE:\n        d_info = DeviceInfo(\n            path=device[\"path\"].decode(),\n            bus_id=None,\n            vendor_id=f\"{vid:04X}\",  # noqa\n            product_id=f\"{pid:04X}\",  # noqa\n            interface=None,\n            driver=None,\n            manufacturer=None,\n            product=None,\n            serial=None,\n            release=None,\n            isDevice=is_device,\n            hidpp_short=None,\n            hidpp_long=None,\n        )\n        return d_info\n\n    logger.info(f\"Finished checking HIDPP support for device {device['path']} ({bus_id}/{vid:04X}/{pid:04X})\")\n\n\ndef find_paired_node(receiver_path: str, index: int, timeout: int):\n    \"\"\"Find the node of a device paired with a receiver\"\"\"\n    return None\n\n\ndef find_paired_node_wpid(receiver_path: str, index: int):\n    \"\"\"Find the node of a device paired with a receiver, get wpid from udev\"\"\"\n    return None\n\n\ndef monitor_glib(\n    glib: GLib,\n    callback: Callable,\n    filter_func: Callable[[int, int, int, bool, bool], dict[str, Any]],\n) -> None:\n    \"\"\"Monitor GLib.\n\n    Parameters\n    ----------\n    glib\n        GLib instance.\n    callback\n        Called when device found.\n    filter_func\n        Filter devices callback.\n    \"\"\"\n\n    def device_callback(action: str, device):\n        if action == ACTION_ADD:\n            d_info = _match(action, device, filter_func)\n            if d_info:\n                glib.idle_add(callback, action, d_info)\n        elif action == ACTION_REMOVE:\n            # Removed devices will be detected by Solaar directly\n            pass\n\n    monitor = _DeviceMonitor(device_callback=device_callback)\n    monitor.start()\n\n\ndef enumerate(filter_func) -> DeviceInfo:\n    \"\"\"Enumerate the HID Devices.\n\n    List all the HID devices attached to the system, optionally filtering by\n    vendor_id, product_id, and/or interface_number.\n\n    :returns: a list of matching ``DeviceInfo`` tuples.\n    \"\"\"\n    for device in _enumerate_devices():\n        d_info = _match(ACTION_ADD, device, filter_func)\n        if d_info:\n            yield d_info\n\n\ndef open(vendor_id, product_id, serial=None):\n    \"\"\"Open a HID device by its Vendor ID, Product ID and optional serial number.\n\n    If no serial is provided, the first device with the specified IDs is opened.\n\n    :returns: an opaque device handle, or ``None``.\n    \"\"\"\n    if serial is not None:\n        serial = ctypes.create_unicode_buffer(serial)\n\n    device_handle = _hidapi.hid_open(vendor_id, product_id, serial)\n    if device_handle is None:\n        raise HIDError(_hidapi.hid_error(None))\n    return device_handle\n\n\ndef open_path(device_path: str) -> int:\n    \"\"\"Open a HID device by its path name.\n\n    :param device_path: the path of a ``DeviceInfo`` tuple returned by enumerate().\n\n    :returns: an opaque device handle, or ``None``.\n    \"\"\"\n    if not isinstance(device_path, bytes):\n        device_path = device_path.encode()\n\n    device_handle = _hidapi.hid_open_path(device_path)\n    if device_handle is None:\n        raise HIDError(_hidapi.hid_error(None))\n    return device_handle\n\n\ndef close(device_handle) -> None:\n    \"\"\"Close a HID device.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    \"\"\"\n    assert device_handle\n    _hidapi.hid_close(device_handle)\n\n\ndef write(device_handle: int, data: bytes) -> int:\n    \"\"\"Write an Output report to a HID device.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    :param data: the data bytes to send including the report number as the\n    first byte.\n\n    The first byte of data[] must contain the Report ID. For\n    devices which only support a single report, this must be set\n    to 0x0. The remaining bytes contain the report data. Since\n    the Report ID is mandatory, calls to hid_write() will always\n    contain one more byte than the report contains. For example,\n    if a hid report is 16 bytes long, 17 bytes must be passed to\n    hid_write(), the Report ID (or 0x0, for devices with a\n    single report), followed by the report data (16 bytes). In\n    this example, the length passed in would be 17.\n\n    write() will send the data on the first OUT endpoint, if\n    one exists. If it does not, it will send the data through\n    the Control Endpoint (Endpoint 0).\n    \"\"\"\n    assert device_handle\n    assert data\n    assert isinstance(data, bytes), (repr(data), type(data))\n\n    bytes_written = _hidapi.hid_write(device_handle, data, len(data))\n    if bytes_written < 0:\n        raise HIDError(_hidapi.hid_error(device_handle))\n    return bytes_written\n\n\ndef read(device_handle, bytes_count, timeout_ms=None):\n    \"\"\"Read an Input report from a HID device.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    :param bytes_count: maximum number of bytes to read.\n    :param timeout_ms: can be -1 (default) to wait for data indefinitely, 0 to\n    read whatever is in the device's input buffer, or a positive integer to\n    wait that many milliseconds.\n\n    Input reports are returned to the host through the INTERRUPT IN endpoint.\n    The first byte will contain the Report number if the device uses numbered\n    reports.\n\n    :returns: the data packet read, an empty bytes string if a timeout was\n    reached, or None if there was an error while reading.\n    \"\"\"\n    assert device_handle\n\n    data = ctypes.create_string_buffer(bytes_count)\n    if timeout_ms is None or timeout_ms < 0:\n        bytes_read = _hidapi.hid_read(device_handle, data, bytes_count)\n    else:\n        bytes_read = _hidapi.hid_read_timeout(device_handle, data, bytes_count, timeout_ms)\n\n    if bytes_read < 0:\n        raise HIDError(_hidapi.hid_error(device_handle))\n\n    return data.raw[:bytes_read]\n\n\ndef _get_input_report(device_handle, report_id, size):\n    assert device_handle\n    data = ctypes.create_string_buffer(size)\n    data[0] = bytearray((report_id,))\n    size = _hidapi.hid_get_input_report(device_handle, data, size)\n    if size < 0:\n        raise HIDError(_hidapi.hid_error(device_handle))\n    return data.raw[:size]\n\n\ndef _readstring(device_handle, func, max_length=255):\n    assert device_handle\n    buf = ctypes.create_unicode_buffer(max_length)\n    ret = func(device_handle, buf, max_length)\n    if ret < 0:\n        raise HIDError(\"Error reading device property\")\n    return buf.value\n\n\ndef get_manufacturer(device_handle):\n    \"\"\"Get the Manufacturer String from a HID device.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    \"\"\"\n    return _readstring(device_handle, _hidapi.get_manufacturer_string)\n\n\ndef get_product(device_handle):\n    \"\"\"Get the Product String from a HID device.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    \"\"\"\n    return _readstring(device_handle, _hidapi.get_product_string)\n\n\ndef get_serial(device_handle):\n    \"\"\"Get the serial number from a HID device.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    \"\"\"\n    return _readstring(device_handle, _hidapi.get_serial_number_string)\n"
  },
  {
    "path": "lib/hidapi/hidconsole.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport argparse\nimport os\nimport os.path\nimport platform\nimport readline\nimport sys\nimport time\n\nfrom binascii import hexlify\nfrom binascii import unhexlify\nfrom select import select\nfrom threading import Lock\nfrom threading import Thread\n\nif platform.system() == \"Linux\":\n    import hidapi.udev_impl as hidapi\nelse:\n    import hidapi.hidapi_impl as hidapi\n\nLOGITECH_VENDOR_ID = 0x046D\n\ninteractive = os.isatty(0)\nprompt = \"?? Input: \" if interactive else \"\"\nstart_time = time.time()\n\n\ndef strhex(d):\n    return hexlify(d).decode(\"ascii\").upper()\n\n\nprint_lock = Lock()\n\n\ndef _print(marker, data, scroll=False):\n    t = time.time() - start_time\n    if isinstance(data, str):\n        s = f\"{marker} {data}\"\n    else:\n        hexs = strhex(data)\n        s = \"%s (% 8.3f) [%s %s %s %s] %s\" % (marker, t, hexs[0:2], hexs[2:4], hexs[4:8], hexs[8:], repr(data))\n\n    with print_lock:\n        # allow only one thread at a time to write to the console, otherwise\n        # the output gets garbled, especially with ANSI codes.\n\n        if interactive and scroll:\n            # scroll the entire screen above the current line up by 1 line\n            sys.stdout.write(\n                \"\\033[s\"  # save cursor position\n                \"\\033[S\"  # scroll up\n                \"\\033[A\"  # cursor up\n                \"\\033[L\"  # insert 1 line\n                \"\\033[G\"\n            )  # move cursor to column 1\n        sys.stdout.write(s)\n        if interactive and scroll:\n            # restore cursor position\n            sys.stdout.write(\"\\033[u\")\n        else:\n            sys.stdout.write(\"\\n\")\n\n        # flush stdout manually...\n        # because trying to open stdin/out unbuffered programmatically\n        # works much too differently in Python 2/3\n        sys.stdout.flush()\n\n\ndef _error(text, scroll=False):\n    _print(\"!!\", text, scroll)\n\n\ndef _continuous_read(handle, timeout=2000):\n    while True:\n        try:\n            reply = hidapi.read(handle, 128, timeout)\n        except OSError as e:\n            _error(f\"Read failed, aborting: {str(e)}\", True)\n            break\n        assert reply is not None\n        if reply:\n            _print(\">>\", reply, True)\n\n\ndef _validate_input(line, hidpp=False):\n    try:\n        data = unhexlify(line.encode(\"ascii\"))\n    except Exception as e:\n        _error(f\"Invalid input: {str(e)}\")\n        return None\n\n    if hidpp:\n        if len(data) < 4:\n            _error(\"Invalid HID++ request: need at least 4 bytes\")\n            return None\n        if data[:1] not in b\"\\x10\\x11\":\n            _error(\"Invalid HID++ request: first byte must be 0x10 or 0x11\")\n            return None\n        if data[1:2] not in b\"\\xff\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\":\n            _error(\"Invalid HID++ request: second byte must be 0xFF or one of 0x00..0x07\")\n            return None\n        if data[:1] == b\"\\x10\":\n            if len(data) > 7:\n                _error(\"Invalid HID++ request: maximum length of a 0x10 request is 7 bytes\")\n                return None\n            while len(data) < 7:\n                data = (data + b\"\\x00\" * 7)[:7]\n        elif data[:1] == b\"\\x11\":\n            if len(data) > 20:\n                _error(\"Invalid HID++ request: maximum length of a 0x11 request is 20 bytes\")\n                return None\n            while len(data) < 20:\n                data = (data + b\"\\x00\" * 20)[:20]\n\n    return data\n\n\ndef _open(args):\n    def matchfn(bid, vid, pid, _a, _b):\n        if vid == LOGITECH_VENDOR_ID:\n            return {\"vid\": vid}\n\n    device = args.path\n    d = None\n    if not device:\n        for d in hidapi.enumerate(matchfn):\n            if (d.hidpp_short or d.hidpp_long) and (args.id is None or args.id.lower() == d.product_id.lower()):\n                device = d.path\n                break\n        if not device:\n            sys.exit(\"!! No HID++ receiver found.\")\n    if not device:\n        sys.exit(\"!! Device path required.\")\n\n    handle = hidapi.open_path(device)\n    if not handle:\n        sys.exit(f\"!! Failed to open {device}, aborting.\")\n    print(\n        \".. Opened device %r, vendor %r product %r serial %r.\"\n        % (\n            device,\n            hidapi.get_manufacturer(handle) or d.vendor_id if d else None,\n            hidapi.get_product(handle) or d.product_id if d else None,\n            hidapi.get_serial(handle),\n        )\n    )\n    if args.hidpp:\n        if hidapi.get_manufacturer(handle) is not None and hidapi.get_manufacturer(handle) != b\"Logitech\":\n            sys.exit(\"!! Only Logitech devices support the HID++ protocol.\")\n        print(\".. HID++ validation enabled.\")\n    else:\n        if hidapi.get_manufacturer(handle) == b\"Logitech\" and b\"Receiver\" in hidapi.get_product(handle):\n            args.hidpp = True\n            print(\".. Logitech receiver detected, HID++ validation enabled.\")\n\n    return handle\n\n\ndef _parse_arguments():\n    arg_parser = argparse.ArgumentParser()\n    arg_parser.add_argument(\"--history\", help=\"history file (default ~/.hidconsole-history)\")\n    arg_parser.add_argument(\"--hidpp\", action=\"store_true\", help=\"ensure input data is a valid HID++ request\")\n    arg_parser.add_argument(\"command\", nargs=\"?\", help=\"command to send (otherwise get commands from input)\")\n    group = arg_parser.add_mutually_exclusive_group()\n    group.add_argument(\"-p\", \"--path\", help=\"HID raw device to connect to (/dev/hidrawX); \")\n    group.add_argument(\"-i\", \"--id\", help=\"product ID of device to connect to (XXXX)\")\n    return arg_parser.parse_args()\n\n\ndef main():\n    args = _parse_arguments()\n    handle = _open(args)\n\n    if args.command:  # send a command\n        data = _validate_input(args.command, args.hidpp)\n        if data:\n            hidapi.write(handle, data)\n            reply = hidapi.read(handle, 128, 1)\n            if reply:\n                hexs = strhex(reply)\n                s = \"[%s %s %s %s] %s\" % (hexs[0:2], hexs[2:4], hexs[4:8], hexs[8:], repr(data))\n                print(s)\n        exit()\n\n    if interactive:\n        print(\".. Press ^C/^D to exit, or type hex bytes to write to the device.\")\n\n        if args.history is None:\n            args.history = os.path.join(os.path.expanduser(\"~\"), \".hidconsole-history\")\n        try:\n            readline.read_history_file(args.history)\n        except Exception:\n            # file may not exist yet\n            pass\n\n    try:\n        t = Thread(target=_continuous_read, args=(handle,))\n        t.daemon = True\n        t.start()\n\n        if interactive:\n            # move the cursor at the bottom of the screen\n            sys.stdout.write(\"\\033[300B\")  # move cusor at most 300 lines down, don't scroll\n\n        while t.is_alive():\n            line = input(prompt)\n            line = line.strip().replace(\" \", \"\")\n            # print (\"line\", line)\n            if not line:\n                continue\n\n            data = _validate_input(line, args.hidpp)\n            if data is None:\n                continue\n\n            _print(\"<<\", data)\n            hidapi.write(handle, data)\n            # wait for some kind of reply\n            if args.hidpp and not interactive:\n                rlist, wlist, xlist = select([handle], [], [], 1)\n                if data[1:2] == b\"\\xff\":\n                    # the receiver will reply very fast, in a few milliseconds\n                    time.sleep(0.010)\n                else:\n                    # the devices might reply quite slow\n                    time.sleep(0.700)\n    except EOFError:\n        if interactive:\n            print(\"\")\n        else:\n            time.sleep(1)\n\n    finally:\n        hidapi.close(handle)\n        if interactive:\n            readline.write_history_file(args.history)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "lib/hidapi/udev_impl.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n\"\"\"Generic Human Interface Device API.\n\nIt is currently a partial pure-Python implementation of the native HID API\nimplemented by signal11 (https://github.com/signal11/hidapi), and requires\n``pyudev``.\nThe docstrings are mostly copied from the hidapi API header, with changes where\nnecessary.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport errno\nimport logging\nimport os\nimport typing\nimport warnings\n\n\n# the tuple object we'll expose when enumerating devices\nfrom select import select\nfrom time import sleep\nfrom time import time\nfrom typing import Callable\n\nimport pyudev\n\nfrom hidapi.common import DeviceInfo\n\nif typing.TYPE_CHECKING:\n    import gi\n\n    gi.require_version(\"Gdk\", \"3.0\")\n    from gi.repository import GLib  # NOQA: E402\n\nlogger = logging.getLogger(__name__)\n\nfileopen = open\n\nACTION_ADD = \"add\"\nACTION_REMOVE = \"remove\"\n\n#\n# exposed API\n# docstrings mostly copied from hidapi.h\n#\n\n\ndef init():\n    \"\"\"This function is a no-op, and exists only to match the native hidapi\n    implementation.\n\n    :returns: ``True``.\n    \"\"\"\n    return True\n\n\ndef exit():\n    \"\"\"This function is a no-op, and exists only to match the native hidapi\n    implementation.\n\n    :returns: ``True``.\n    \"\"\"\n    return True\n\n\ndef _match(action: str, device, filter_func: typing.Callable[[int, int, int, bool, bool], dict[str, typing.Any]]):\n    \"\"\"\n\n    The filter_func is used to determine whether this is a device of\n    interest to Solaar. It is given the bus id, vendor id, and product\n    id and returns a dictionary with the required hid_driver and\n    usb_interface and whether this is a receiver or device.\"\"\"\n    logger.debug(f\"Dbus event {action} {device}\")\n    hid_device = device.find_parent(\"hid\")\n    if hid_device is None:  # only HID devices are of interest to Solaar\n        return\n    hid_id = hid_device.properties.get(\"HID_ID\")\n    if not hid_id:\n        return  # there are reports that sometimes the id isn't set up right so be defensive\n    bid, vid, pid = hid_id.split(\":\")\n    hid_hid_device = hid_device.find_parent(\"hid\")\n    if hid_hid_device is not None:\n        return  # these are devices connected through a receiver so don't pick them up here\n\n    try:  # if report descriptor does not indicate HID++ capabilities then this device is not of interest to Solaar\n        from hid_parser import ReportDescriptor\n\n        hidpp_short = hidpp_long = False\n        devfile = \"/sys\" + hid_device.properties.get(\"DEVPATH\") + \"/report_descriptor\"\n        with fileopen(devfile, \"rb\") as fd:\n            with warnings.catch_warnings():\n                warnings.simplefilter(\"ignore\")\n                rd = ReportDescriptor(fd.read())\n            hidpp_short = 0x10 in rd.input_report_ids and 6 * 8 == int(rd.get_input_report_size(0x10))\n            # and _Usage(0xFF00, 0x0001) in rd.get_input_items(0x10)[0].usages  # be more permissive\n            hidpp_long = 0x11 in rd.input_report_ids and 19 * 8 == int(rd.get_input_report_size(0x11))\n            # and _Usage(0xFF00, 0x0002) in rd.get_input_items(0x11)[0].usages  # be more permissive\n        if not hidpp_short and not hidpp_long:\n            return\n    except Exception as e:  # if can't process report descriptor fall back to old scheme\n        hidpp_short = None\n        hidpp_long = None\n        logger.info(\n            \"Report Descriptor not processed for DEVICE %s BID %s VID %s PID %s: %s\",\n            device.device_node,\n            bid,\n            vid,\n            pid,\n            e,\n        )\n\n    filtered_result = filter_func(int(bid, 16), int(vid, 16), int(pid, 16), hidpp_short, hidpp_long)\n    if not filtered_result:\n        return\n    interface_number = filtered_result.get(\"usb_interface\")\n    isDevice = filtered_result.get(\"isDevice\")\n\n    if action == ACTION_ADD:\n        hid_driver_name = hid_device.properties.get(\"DRIVER\")\n        intf_device = device.find_parent(\"usb\", \"usb_interface\")\n        usb_interface = None if intf_device is None else intf_device.attributes.asint(\"bInterfaceNumber\")\n        # print('*** usb interface', action, device, 'usb_interface:', intf_device, usb_interface, interface_number)\n        logger.info(\n            \"Found device %s BID %s VID %s PID %s HID++ %s %s USB %s %s\",\n            device.device_node,\n            bid,\n            vid,\n            pid,\n            hidpp_short,\n            hidpp_long,\n            usb_interface,\n            interface_number,\n        )\n        if not (hidpp_short or hidpp_long or interface_number is None or interface_number == usb_interface):\n            return\n        attrs = intf_device.attributes if intf_device is not None else None\n\n        d_info = DeviceInfo(\n            path=device.device_node,\n            bus_id=int(bid, 16),\n            vendor_id=vid[-4:],\n            product_id=pid[-4:],\n            interface=usb_interface,\n            driver=hid_driver_name,\n            manufacturer=attrs.get(\"manufacturer\") if attrs else None,\n            product=attrs.get(\"product\") if attrs else None,\n            serial=hid_device.properties.get(\"HID_UNIQ\"),\n            release=attrs.get(\"bcdDevice\") if attrs else None,\n            isDevice=isDevice,\n            hidpp_short=hidpp_short,\n            hidpp_long=hidpp_long,\n        )\n        return d_info\n\n    elif action == ACTION_REMOVE:\n        d_info = DeviceInfo(\n            path=device.device_node,\n            bus_id=None,\n            vendor_id=vid[-4:],\n            product_id=pid[-4:],\n            interface=None,\n            driver=None,\n            manufacturer=None,\n            product=None,\n            serial=None,\n            release=None,\n            isDevice=isDevice,\n            hidpp_short=None,\n            hidpp_long=None,\n        )\n        return d_info\n\n\ndef find_paired_node(receiver_path: str, index: int, timeout: int):\n    \"\"\"Find the node of a device paired with a receiver\"\"\"\n    context = pyudev.Context()\n    receiver_phys = pyudev.Devices.from_device_file(context, receiver_path).find_parent(\"hid\").get(\"HID_PHYS\")\n\n    if not receiver_phys:\n        return None\n\n    phys = f\"{receiver_phys}:{index}\"  # noqa: E231\n    timeout += time()\n    delta = time()\n    while delta < timeout:\n        for dev in context.list_devices(subsystem=\"hidraw\"):\n            dev_phys = dev.find_parent(\"hid\").get(\"HID_PHYS\")\n            if dev_phys and dev_phys == phys:\n                return dev.device_node\n        delta = time()\n\n    return None\n\n\ndef find_paired_node_wpid(receiver_path: str, index: int):\n    \"\"\"Find the node of a device paired with a receiver, get wpid from udev\"\"\"\n    context = pyudev.Context()\n    receiver_phys = pyudev.Devices.from_device_file(context, receiver_path).find_parent(\"hid\").get(\"HID_PHYS\")\n\n    if not receiver_phys:\n        return None\n\n    phys = f\"{receiver_phys}:{index}\"  # noqa: E231\n    for dev in context.list_devices(subsystem=\"hidraw\"):\n        dev_phys = dev.find_parent(\"hid\").get(\"HID_PHYS\")\n        if dev_phys and dev_phys == phys:\n            # get hid id like 0003:0000046D:00000065\n            hid_id = dev.find_parent(\"hid\").get(\"HID_ID\")\n            # get wpid - last 4 symbols\n            udev_wpid = hid_id[-4:]\n            return udev_wpid\n\n    return None\n\n\ndef monitor_glib(glib: GLib, callback: Callable, filter_func: Callable):\n    \"\"\"Monitor GLib.\n\n    Parameters\n    ----------\n    glib\n        GLib instance.\n    \"\"\"\n    c = pyudev.Context()\n    m = pyudev.Monitor.from_netlink(c)\n    m.filter_by(subsystem=\"hidraw\")\n\n    def _process_udev_event(monitor, condition, cb, filter_func):\n        if condition == glib.IO_IN:\n            event = monitor.receive_device()\n            if event:\n                action, device = event\n                # print (\"***\", action, device)\n                if action == ACTION_ADD:\n                    d_info = _match(action, device, filter_func)\n                    if d_info:\n                        glib.idle_add(cb, action, d_info)\n                elif action == ACTION_REMOVE:\n                    # the GLib notification does _not_ match!\n                    pass\n        return True\n\n    try:\n        # io_add_watch_full may not be available...\n        glib.io_add_watch_full(m, glib.PRIORITY_LOW, glib.IO_IN, _process_udev_event, callback, filter_func)\n    except AttributeError:\n        try:\n            # and the priority parameter appeared later in the API\n            glib.io_add_watch(m, glib.PRIORITY_LOW, glib.IO_IN, _process_udev_event, callback, filter_func)\n        except Exception:\n            glib.io_add_watch(m, glib.IO_IN, _process_udev_event, callback, filter_func)\n\n    logger.debug(\"Starting dbus monitoring\")\n    m.start()\n\n\ndef enumerate(filter_func: typing.Callable[[int, int, int, bool, bool], dict[str, typing.Any]]):\n    \"\"\"Enumerate the HID Devices.\n\n    List all the HID devices attached to the system, optionally filtering by\n    vendor_id, product_id, and/or interface_number.\n\n    :returns: a list of matching ``DeviceInfo`` tuples.\n    \"\"\"\n\n    logger.debug(\"Starting dbus enumeration\")\n    for dev in pyudev.Context().list_devices(subsystem=\"hidraw\"):\n        dev_info = _match(ACTION_ADD, dev, filter_func)\n        if dev_info:\n            yield dev_info\n\n\ndef open(vendor_id, product_id, serial=None):\n    \"\"\"Open a HID device by its Vendor ID, Product ID and optional serial number.\n\n    If no serial is provided, the first device with the specified IDs is opened.\n\n    :returns: an opaque device handle, or ``None``.\n    \"\"\"\n\n    def matchfn(bid, vid, pid):\n        return vid == vendor_id and pid == product_id\n\n    for device in enumerate(matchfn):\n        if serial is None or serial == device.serial:\n            return open_path(device.path)\n\n\ndef open_path(device_path):\n    \"\"\"Open a HID device by its path name.\n\n    :param device_path: the path of a ``DeviceInfo`` tuple returned by enumerate().\n\n    :returns: an opaque device handle, or ``None``.\n    \"\"\"\n    assert device_path\n    assert device_path.startswith(\"/dev/hidraw\")\n\n    logger.info(\"OPEN PATH %s\", device_path)\n    retrycount = 0\n    while retrycount < 3:\n        retrycount += 1\n        try:\n            return os.open(device_path, os.O_RDWR | os.O_SYNC)\n        except OSError as e:\n            logger.info(\"OPEN PATH FAILED %s ERROR %s %s\", device_path, e.errno, e)\n            if e.errno == errno.EACCES:\n                sleep(0.1)\n            else:\n                raise e\n\n\ndef close(device_handle) -> None:\n    \"\"\"Close a HID device.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    \"\"\"\n    assert device_handle\n    os.close(device_handle)\n\n\ndef write(device_handle, data):\n    \"\"\"Write an Output report to a HID device.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    :param data: the data bytes to send including the report number as the\n    first byte.\n\n    The first byte of data[] must contain the Report ID. For\n    devices which only support a single report, this must be set\n    to 0x0. The remaining bytes contain the report data. Since\n    the Report ID is mandatory, calls to hid_write() will always\n    contain one more byte than the report contains. For example,\n    if a hid report is 16 bytes long, 17 bytes must be passed to\n    hid_write(), the Report ID (or 0x0, for devices with a\n    single report), followed by the report data (16 bytes). In\n    this example, the length passed in would be 17.\n\n    write() will send the data on the first OUT endpoint, if\n    one exists. If it does not, it will send the data through\n    the Control Endpoint (Endpoint 0).\n    \"\"\"\n    assert device_handle\n    assert data\n    assert isinstance(data, bytes), (repr(data), type(data))\n    retrycount = 0\n    bytes_written = 0\n    while retrycount < 3:\n        try:\n            retrycount += 1\n            bytes_written = os.write(device_handle, data)\n        except OSError as e:\n            if e.errno == errno.EPIPE:\n                sleep(0.1)\n        else:\n            break\n    if bytes_written != len(data):\n        raise OSError(errno.EIO, f\"written {int(bytes_written)} bytes out of expected {len(data)}\")\n\n\ndef read(device_handle, bytes_count, timeout_ms=-1):\n    \"\"\"Read an Input report from a HID device.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    :param bytes_count: maximum number of bytes to read.\n    :param timeout_ms: can be -1 (default) to wait for data indefinitely, 0 to\n    read whatever is in the device's input buffer, or a positive integer to\n    wait that many milliseconds.\n\n    Input reports are returned to the host through the INTERRUPT IN endpoint.\n    The first byte will contain the Report number if the device uses numbered\n    reports.\n\n    :returns: the data packet read, an empty bytes string if a timeout was\n    reached, or None if there was an error while reading.\n    \"\"\"\n    assert device_handle\n    timeout = None if timeout_ms < 0 else timeout_ms / 1000.0\n    rlist, wlist, xlist = select([device_handle], [], [device_handle], timeout)\n\n    if xlist:\n        assert xlist == [device_handle]\n        raise OSError(errno.EIO, f\"exception on file descriptor {int(device_handle)}\")\n\n    if rlist:\n        assert rlist == [device_handle]\n        data = os.read(device_handle, bytes_count)\n        assert data is not None\n        assert isinstance(data, bytes), (repr(data), type(data))\n        return data\n    else:\n        return b\"\"\n\n\n_DEVICE_STRINGS = {\n    0: \"manufacturer\",\n    1: \"product\",\n    2: \"serial\",\n}\n\n\ndef get_manufacturer(device_handle):\n    \"\"\"Get the Manufacturer String from a HID device.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    \"\"\"\n    return get_indexed_string(device_handle, 0)\n\n\ndef get_product(device_handle):\n    \"\"\"Get the Product String from a HID device.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    \"\"\"\n    return get_indexed_string(device_handle, 1)\n\n\ndef get_serial(device_handle):\n    \"\"\"Get the serial number from a HID device.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    \"\"\"\n    serial = get_indexed_string(device_handle, 2)\n    return serial\n\n\ndef get_indexed_string(device_handle, index):\n    \"\"\"Get a string from a HID device, based on its string index.\n\n    Note: currently not working in the ``hidraw`` native implementation.\n\n    :param device_handle: a device handle returned by open() or open_path().\n    :param index: the index of the string to get.\n    :returns: the value corresponding to index, or None if no value found\n    :rtype: bytes or NoneType\n    \"\"\"\n    try:\n        key = _DEVICE_STRINGS[index]\n    except KeyError:\n        return None\n\n    assert device_handle\n    stat = os.fstat(device_handle)\n    try:\n        dev = pyudev.Devices.from_device_number(pyudev.Context(), \"char\", stat.st_rdev)\n    except (pyudev.DeviceNotFoundError, ValueError):\n        return None\n\n    hid_dev = dev.find_parent(\"hid\")\n    if hid_dev:\n        assert \"HID_ID\" in hid_dev\n        bus, _ignore, _ignore = hid_dev[\"HID_ID\"].split(\":\")\n\n        if bus == \"0003\":  # USB\n            usb_dev = dev.find_parent(\"usb\", \"usb_device\")\n            assert usb_dev\n            return usb_dev.attributes.get(key)\n\n        elif bus == \"0005\":  # BLUETOOTH\n            # TODO\n            pass\n"
  },
  {
    "path": "lib/keysyms/__init__.py",
    "content": ""
  },
  {
    "path": "lib/keysyms/generate.py",
    "content": "#!/usr/bin/env python3\n\"\"\"Extract key symbol encodings from X11 header files.\"\"\"\n\nfrom pathlib import Path\nfrom pprint import pprint\nfrom re import findall\nfrom subprocess import run\nfrom tempfile import TemporaryDirectory\n\nrepo = \"https://gitlab.freedesktop.org/xorg/proto/xorgproto.git\"\npattern = r\"#define XK_(\\w+)\\s+0x(\\w+)(?:\\s+/\\*\\s+U\\+(\\w+))?\"\nxf86pattern = r\"#define XF86XK_(\\w+)\\s+0x(\\w+)(?:\\s+/\\*\\s+U\\+(\\w+))?\"\n\n\ndef main():\n    keysymdef = {}\n    keysym_files = [\n        (\"include/X11/keysymdef.h\", pattern, \"\"),\n        (\"include/X11/XF86keysym.h\", xf86pattern, \"XF86_\"),\n    ]\n\n    with TemporaryDirectory() as temp:\n        run([\"git\", \"clone\", repo, \".\"], cwd=temp)\n\n        for filename, extraction_pattern, prefix in keysym_files:\n            text = Path(temp, filename).read_text()\n            for name, sym, _ in findall(extraction_pattern, text):\n                sym = int(sym, 16)\n                if keysymdef.get(f\"{prefix}{name}\", None):\n                    print(f\"KEY DUP {prefix}{name}\")\n                keysymdef[f\"{prefix}{name}\"] = sym\n\n    with open(\"keysymdef.py\", \"w\") as f:\n        f.write(\"# flake8: noqa\\nkey_symbols = \\\\\\n\")\n        pprint(keysymdef, f)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "lib/keysyms/keysymdef.py",
    "content": "# flake8: noqa\nkey_symbols = {\n    \"0\": 48,\n    \"1\": 49,\n    \"2\": 50,\n    \"3\": 51,\n    \"3270_AltCursor\": 64784,\n    \"3270_Attn\": 64782,\n    \"3270_BackTab\": 64773,\n    \"3270_ChangeScreen\": 64793,\n    \"3270_Copy\": 64789,\n    \"3270_CursorBlink\": 64783,\n    \"3270_CursorSelect\": 64796,\n    \"3270_DeleteWord\": 64794,\n    \"3270_Duplicate\": 64769,\n    \"3270_Enter\": 64798,\n    \"3270_EraseEOF\": 64774,\n    \"3270_EraseInput\": 64775,\n    \"3270_ExSelect\": 64795,\n    \"3270_FieldMark\": 64770,\n    \"3270_Ident\": 64787,\n    \"3270_Jump\": 64786,\n    \"3270_KeyClick\": 64785,\n    \"3270_Left2\": 64772,\n    \"3270_PA1\": 64778,\n    \"3270_PA2\": 64779,\n    \"3270_PA3\": 64780,\n    \"3270_Play\": 64790,\n    \"3270_PrintScreen\": 64797,\n    \"3270_Quit\": 64777,\n    \"3270_Record\": 64792,\n    \"3270_Reset\": 64776,\n    \"3270_Right2\": 64771,\n    \"3270_Rule\": 64788,\n    \"3270_Setup\": 64791,\n    \"3270_Test\": 64781,\n    \"4\": 52,\n    \"5\": 53,\n    \"6\": 54,\n    \"7\": 55,\n    \"8\": 56,\n    \"9\": 57,\n    \"A\": 65,\n    \"AE\": 198,\n    \"Aacute\": 193,\n    \"Abelowdot\": 16785056,\n    \"Abreve\": 451,\n    \"Abreveacute\": 16785070,\n    \"Abrevebelowdot\": 16785078,\n    \"Abrevegrave\": 16785072,\n    \"Abrevehook\": 16785074,\n    \"Abrevetilde\": 16785076,\n    \"AccessX_Enable\": 65136,\n    \"AccessX_Feedback_Enable\": 65137,\n    \"Acircumflex\": 194,\n    \"Acircumflexacute\": 16785060,\n    \"Acircumflexbelowdot\": 16785068,\n    \"Acircumflexgrave\": 16785062,\n    \"Acircumflexhook\": 16785064,\n    \"Acircumflextilde\": 16785066,\n    \"Adiaeresis\": 196,\n    \"Agrave\": 192,\n    \"Ahook\": 16785058,\n    \"Alt_L\": 65513,\n    \"Alt_R\": 65514,\n    \"Amacron\": 960,\n    \"Aogonek\": 417,\n    \"Arabic_0\": 16778848,\n    \"Arabic_1\": 16778849,\n    \"Arabic_2\": 16778850,\n    \"Arabic_3\": 16778851,\n    \"Arabic_4\": 16778852,\n    \"Arabic_5\": 16778853,\n    \"Arabic_6\": 16778854,\n    \"Arabic_7\": 16778855,\n    \"Arabic_8\": 16778856,\n    \"Arabic_9\": 16778857,\n    \"Arabic_ain\": 1497,\n    \"Arabic_alef\": 1479,\n    \"Arabic_alefmaksura\": 1513,\n    \"Arabic_beh\": 1480,\n    \"Arabic_comma\": 1452,\n    \"Arabic_dad\": 1494,\n    \"Arabic_dal\": 1487,\n    \"Arabic_damma\": 1519,\n    \"Arabic_dammatan\": 1516,\n    \"Arabic_ddal\": 16778888,\n    \"Arabic_farsi_yeh\": 16778956,\n    \"Arabic_fatha\": 1518,\n    \"Arabic_fathatan\": 1515,\n    \"Arabic_feh\": 1505,\n    \"Arabic_fullstop\": 16778964,\n    \"Arabic_gaf\": 16778927,\n    \"Arabic_ghain\": 1498,\n    \"Arabic_ha\": 1511,\n    \"Arabic_hah\": 1485,\n    \"Arabic_hamza\": 1473,\n    \"Arabic_hamza_above\": 16778836,\n    \"Arabic_hamza_below\": 16778837,\n    \"Arabic_hamzaonalef\": 1475,\n    \"Arabic_hamzaonwaw\": 1476,\n    \"Arabic_hamzaonyeh\": 1478,\n    \"Arabic_hamzaunderalef\": 1477,\n    \"Arabic_heh\": 1511,\n    \"Arabic_heh_doachashmee\": 16778942,\n    \"Arabic_heh_goal\": 16778945,\n    \"Arabic_jeem\": 1484,\n    \"Arabic_jeh\": 16778904,\n    \"Arabic_kaf\": 1507,\n    \"Arabic_kasra\": 1520,\n    \"Arabic_kasratan\": 1517,\n    \"Arabic_keheh\": 16778921,\n    \"Arabic_khah\": 1486,\n    \"Arabic_lam\": 1508,\n    \"Arabic_madda_above\": 16778835,\n    \"Arabic_maddaonalef\": 1474,\n    \"Arabic_meem\": 1509,\n    \"Arabic_noon\": 1510,\n    \"Arabic_noon_ghunna\": 16778938,\n    \"Arabic_peh\": 16778878,\n    \"Arabic_percent\": 16778858,\n    \"Arabic_qaf\": 1506,\n    \"Arabic_question_mark\": 1471,\n    \"Arabic_ra\": 1489,\n    \"Arabic_rreh\": 16778897,\n    \"Arabic_sad\": 1493,\n    \"Arabic_seen\": 1491,\n    \"Arabic_semicolon\": 1467,\n    \"Arabic_shadda\": 1521,\n    \"Arabic_sheen\": 1492,\n    \"Arabic_sukun\": 1522,\n    \"Arabic_superscript_alef\": 16778864,\n    \"Arabic_switch\": 65406,\n    \"Arabic_tah\": 1495,\n    \"Arabic_tatweel\": 1504,\n    \"Arabic_tcheh\": 16778886,\n    \"Arabic_teh\": 1482,\n    \"Arabic_tehmarbuta\": 1481,\n    \"Arabic_thal\": 1488,\n    \"Arabic_theh\": 1483,\n    \"Arabic_tteh\": 16778873,\n    \"Arabic_veh\": 16778916,\n    \"Arabic_waw\": 1512,\n    \"Arabic_yeh\": 1514,\n    \"Arabic_yeh_baree\": 16778962,\n    \"Arabic_zah\": 1496,\n    \"Arabic_zain\": 1490,\n    \"Aring\": 197,\n    \"Armenian_AT\": 16778552,\n    \"Armenian_AYB\": 16778545,\n    \"Armenian_BEN\": 16778546,\n    \"Armenian_CHA\": 16778569,\n    \"Armenian_DA\": 16778548,\n    \"Armenian_DZA\": 16778561,\n    \"Armenian_E\": 16778551,\n    \"Armenian_FE\": 16778582,\n    \"Armenian_GHAT\": 16778562,\n    \"Armenian_GIM\": 16778547,\n    \"Armenian_HI\": 16778565,\n    \"Armenian_HO\": 16778560,\n    \"Armenian_INI\": 16778555,\n    \"Armenian_JE\": 16778571,\n    \"Armenian_KE\": 16778580,\n    \"Armenian_KEN\": 16778559,\n    \"Armenian_KHE\": 16778557,\n    \"Armenian_LYUN\": 16778556,\n    \"Armenian_MEN\": 16778564,\n    \"Armenian_NU\": 16778566,\n    \"Armenian_O\": 16778581,\n    \"Armenian_PE\": 16778570,\n    \"Armenian_PYUR\": 16778579,\n    \"Armenian_RA\": 16778572,\n    \"Armenian_RE\": 16778576,\n    \"Armenian_SE\": 16778573,\n    \"Armenian_SHA\": 16778567,\n    \"Armenian_TCHE\": 16778563,\n    \"Armenian_TO\": 16778553,\n    \"Armenian_TSA\": 16778558,\n    \"Armenian_TSO\": 16778577,\n    \"Armenian_TYUN\": 16778575,\n    \"Armenian_VEV\": 16778574,\n    \"Armenian_VO\": 16778568,\n    \"Armenian_VYUN\": 16778578,\n    \"Armenian_YECH\": 16778549,\n    \"Armenian_ZA\": 16778550,\n    \"Armenian_ZHE\": 16778554,\n    \"Armenian_accent\": 16778587,\n    \"Armenian_amanak\": 16778588,\n    \"Armenian_apostrophe\": 16778586,\n    \"Armenian_at\": 16778600,\n    \"Armenian_ayb\": 16778593,\n    \"Armenian_ben\": 16778594,\n    \"Armenian_but\": 16778589,\n    \"Armenian_cha\": 16778617,\n    \"Armenian_da\": 16778596,\n    \"Armenian_dza\": 16778609,\n    \"Armenian_e\": 16778599,\n    \"Armenian_exclam\": 16778588,\n    \"Armenian_fe\": 16778630,\n    \"Armenian_full_stop\": 16778633,\n    \"Armenian_ghat\": 16778610,\n    \"Armenian_gim\": 16778595,\n    \"Armenian_hi\": 16778613,\n    \"Armenian_ho\": 16778608,\n    \"Armenian_hyphen\": 16778634,\n    \"Armenian_ini\": 16778603,\n    \"Armenian_je\": 16778619,\n    \"Armenian_ke\": 16778628,\n    \"Armenian_ken\": 16778607,\n    \"Armenian_khe\": 16778605,\n    \"Armenian_ligature_ew\": 16778631,\n    \"Armenian_lyun\": 16778604,\n    \"Armenian_men\": 16778612,\n    \"Armenian_nu\": 16778614,\n    \"Armenian_o\": 16778629,\n    \"Armenian_paruyk\": 16778590,\n    \"Armenian_pe\": 16778618,\n    \"Armenian_pyur\": 16778627,\n    \"Armenian_question\": 16778590,\n    \"Armenian_ra\": 16778620,\n    \"Armenian_re\": 16778624,\n    \"Armenian_se\": 16778621,\n    \"Armenian_separation_mark\": 16778589,\n    \"Armenian_sha\": 16778615,\n    \"Armenian_shesht\": 16778587,\n    \"Armenian_tche\": 16778611,\n    \"Armenian_to\": 16778601,\n    \"Armenian_tsa\": 16778606,\n    \"Armenian_tso\": 16778625,\n    \"Armenian_tyun\": 16778623,\n    \"Armenian_verjaket\": 16778633,\n    \"Armenian_vev\": 16778622,\n    \"Armenian_vo\": 16778616,\n    \"Armenian_vyun\": 16778626,\n    \"Armenian_yech\": 16778597,\n    \"Armenian_yentamna\": 16778634,\n    \"Armenian_za\": 16778598,\n    \"Armenian_zhe\": 16778602,\n    \"Atilde\": 195,\n    \"AudibleBell_Enable\": 65146,\n    \"B\": 66,\n    \"Babovedot\": 16784898,\n    \"BackSpace\": 65288,\n    \"Begin\": 65368,\n    \"BounceKeys_Enable\": 65140,\n    \"Break\": 65387,\n    \"Byelorussian_SHORTU\": 1726,\n    \"Byelorussian_shortu\": 1710,\n    \"C\": 67,\n    \"CH\": 65186,\n    \"C_H\": 65189,\n    \"C_h\": 65188,\n    \"Cabovedot\": 709,\n    \"Cacute\": 454,\n    \"Cancel\": 65385,\n    \"Caps_Lock\": 65509,\n    \"Ccaron\": 456,\n    \"Ccedilla\": 199,\n    \"Ccircumflex\": 710,\n    \"Ch\": 65185,\n    \"Clear\": 65291,\n    \"Codeinput\": 65335,\n    \"ColonSign\": 16785569,\n    \"Control_L\": 65507,\n    \"Control_R\": 65508,\n    \"CruzeiroSign\": 16785570,\n    \"Cyrillic_A\": 1761,\n    \"Cyrillic_BE\": 1762,\n    \"Cyrillic_CHE\": 1790,\n    \"Cyrillic_CHE_descender\": 16778422,\n    \"Cyrillic_CHE_vertstroke\": 16778424,\n    \"Cyrillic_DE\": 1764,\n    \"Cyrillic_DZHE\": 1727,\n    \"Cyrillic_E\": 1788,\n    \"Cyrillic_EF\": 1766,\n    \"Cyrillic_EL\": 1772,\n    \"Cyrillic_EM\": 1773,\n    \"Cyrillic_EN\": 1774,\n    \"Cyrillic_EN_descender\": 16778402,\n    \"Cyrillic_ER\": 1778,\n    \"Cyrillic_ES\": 1779,\n    \"Cyrillic_GHE\": 1767,\n    \"Cyrillic_GHE_bar\": 16778386,\n    \"Cyrillic_HA\": 1768,\n    \"Cyrillic_HARDSIGN\": 1791,\n    \"Cyrillic_HA_descender\": 16778418,\n    \"Cyrillic_I\": 1769,\n    \"Cyrillic_IE\": 1765,\n    \"Cyrillic_IO\": 1715,\n    \"Cyrillic_I_macron\": 16778466,\n    \"Cyrillic_JE\": 1720,\n    \"Cyrillic_KA\": 1771,\n    \"Cyrillic_KA_descender\": 16778394,\n    \"Cyrillic_KA_vertstroke\": 16778396,\n    \"Cyrillic_LJE\": 1721,\n    \"Cyrillic_NJE\": 1722,\n    \"Cyrillic_O\": 1775,\n    \"Cyrillic_O_bar\": 16778472,\n    \"Cyrillic_PE\": 1776,\n    \"Cyrillic_SCHWA\": 16778456,\n    \"Cyrillic_SHA\": 1787,\n    \"Cyrillic_SHCHA\": 1789,\n    \"Cyrillic_SHHA\": 16778426,\n    \"Cyrillic_SHORTI\": 1770,\n    \"Cyrillic_SOFTSIGN\": 1784,\n    \"Cyrillic_TE\": 1780,\n    \"Cyrillic_TSE\": 1763,\n    \"Cyrillic_U\": 1781,\n    \"Cyrillic_U_macron\": 16778478,\n    \"Cyrillic_U_straight\": 16778414,\n    \"Cyrillic_U_straight_bar\": 16778416,\n    \"Cyrillic_VE\": 1783,\n    \"Cyrillic_YA\": 1777,\n    \"Cyrillic_YERU\": 1785,\n    \"Cyrillic_YU\": 1760,\n    \"Cyrillic_ZE\": 1786,\n    \"Cyrillic_ZHE\": 1782,\n    \"Cyrillic_ZHE_descender\": 16778390,\n    \"Cyrillic_a\": 1729,\n    \"Cyrillic_be\": 1730,\n    \"Cyrillic_che\": 1758,\n    \"Cyrillic_che_descender\": 16778423,\n    \"Cyrillic_che_vertstroke\": 16778425,\n    \"Cyrillic_de\": 1732,\n    \"Cyrillic_dzhe\": 1711,\n    \"Cyrillic_e\": 1756,\n    \"Cyrillic_ef\": 1734,\n    \"Cyrillic_el\": 1740,\n    \"Cyrillic_em\": 1741,\n    \"Cyrillic_en\": 1742,\n    \"Cyrillic_en_descender\": 16778403,\n    \"Cyrillic_er\": 1746,\n    \"Cyrillic_es\": 1747,\n    \"Cyrillic_ghe\": 1735,\n    \"Cyrillic_ghe_bar\": 16778387,\n    \"Cyrillic_ha\": 1736,\n    \"Cyrillic_ha_descender\": 16778419,\n    \"Cyrillic_hardsign\": 1759,\n    \"Cyrillic_i\": 1737,\n    \"Cyrillic_i_macron\": 16778467,\n    \"Cyrillic_ie\": 1733,\n    \"Cyrillic_io\": 1699,\n    \"Cyrillic_je\": 1704,\n    \"Cyrillic_ka\": 1739,\n    \"Cyrillic_ka_descender\": 16778395,\n    \"Cyrillic_ka_vertstroke\": 16778397,\n    \"Cyrillic_lje\": 1705,\n    \"Cyrillic_nje\": 1706,\n    \"Cyrillic_o\": 1743,\n    \"Cyrillic_o_bar\": 16778473,\n    \"Cyrillic_pe\": 1744,\n    \"Cyrillic_schwa\": 16778457,\n    \"Cyrillic_sha\": 1755,\n    \"Cyrillic_shcha\": 1757,\n    \"Cyrillic_shha\": 16778427,\n    \"Cyrillic_shorti\": 1738,\n    \"Cyrillic_softsign\": 1752,\n    \"Cyrillic_te\": 1748,\n    \"Cyrillic_tse\": 1731,\n    \"Cyrillic_u\": 1749,\n    \"Cyrillic_u_macron\": 16778479,\n    \"Cyrillic_u_straight\": 16778415,\n    \"Cyrillic_u_straight_bar\": 16778417,\n    \"Cyrillic_ve\": 1751,\n    \"Cyrillic_ya\": 1745,\n    \"Cyrillic_yeru\": 1753,\n    \"Cyrillic_yu\": 1728,\n    \"Cyrillic_ze\": 1754,\n    \"Cyrillic_zhe\": 1750,\n    \"Cyrillic_zhe_descender\": 16778391,\n    \"D\": 68,\n    \"Dabovedot\": 16784906,\n    \"Dcaron\": 463,\n    \"Delete\": 65535,\n    \"DongSign\": 16785579,\n    \"Down\": 65364,\n    \"Dstroke\": 464,\n    \"E\": 69,\n    \"ENG\": 957,\n    \"ETH\": 208,\n    \"EZH\": 16777655,\n    \"Eabovedot\": 972,\n    \"Eacute\": 201,\n    \"Ebelowdot\": 16785080,\n    \"Ecaron\": 460,\n    \"Ecircumflex\": 202,\n    \"Ecircumflexacute\": 16785086,\n    \"Ecircumflexbelowdot\": 16785094,\n    \"Ecircumflexgrave\": 16785088,\n    \"Ecircumflexhook\": 16785090,\n    \"Ecircumflextilde\": 16785092,\n    \"EcuSign\": 16785568,\n    \"Ediaeresis\": 203,\n    \"Egrave\": 200,\n    \"Ehook\": 16785082,\n    \"Eisu_Shift\": 65327,\n    \"Eisu_toggle\": 65328,\n    \"Emacron\": 938,\n    \"End\": 65367,\n    \"Eogonek\": 458,\n    \"Escape\": 65307,\n    \"Eth\": 208,\n    \"Etilde\": 16785084,\n    \"EuroSign\": 8364,\n    \"Execute\": 65378,\n    \"F\": 70,\n    \"F1\": 65470,\n    \"F10\": 65479,\n    \"F11\": 65480,\n    \"F12\": 65481,\n    \"F13\": 65482,\n    \"F14\": 65483,\n    \"F15\": 65484,\n    \"F16\": 65485,\n    \"F17\": 65486,\n    \"F18\": 65487,\n    \"F19\": 65488,\n    \"F2\": 65471,\n    \"F20\": 65489,\n    \"F21\": 65490,\n    \"F22\": 65491,\n    \"F23\": 65492,\n    \"F24\": 65493,\n    \"F25\": 65494,\n    \"F26\": 65495,\n    \"F27\": 65496,\n    \"F28\": 65497,\n    \"F29\": 65498,\n    \"F3\": 65472,\n    \"F30\": 65499,\n    \"F31\": 65500,\n    \"F32\": 65501,\n    \"F33\": 65502,\n    \"F34\": 65503,\n    \"F35\": 65504,\n    \"F4\": 65473,\n    \"F5\": 65474,\n    \"F6\": 65475,\n    \"F7\": 65476,\n    \"F8\": 65477,\n    \"F9\": 65478,\n    \"FFrancSign\": 16785571,\n    \"Fabovedot\": 16784926,\n    \"Farsi_0\": 16778992,\n    \"Farsi_1\": 16778993,\n    \"Farsi_2\": 16778994,\n    \"Farsi_3\": 16778995,\n    \"Farsi_4\": 16778996,\n    \"Farsi_5\": 16778997,\n    \"Farsi_6\": 16778998,\n    \"Farsi_7\": 16778999,\n    \"Farsi_8\": 16779000,\n    \"Farsi_9\": 16779001,\n    \"Farsi_yeh\": 16778956,\n    \"Find\": 65384,\n    \"First_Virtual_Screen\": 65232,\n    \"G\": 71,\n    \"Gabovedot\": 725,\n    \"Gbreve\": 683,\n    \"Gcaron\": 16777702,\n    \"Gcedilla\": 939,\n    \"Gcircumflex\": 728,\n    \"Georgian_an\": 16781520,\n    \"Georgian_ban\": 16781521,\n    \"Georgian_can\": 16781546,\n    \"Georgian_char\": 16781549,\n    \"Georgian_chin\": 16781545,\n    \"Georgian_cil\": 16781548,\n    \"Georgian_don\": 16781523,\n    \"Georgian_en\": 16781524,\n    \"Georgian_fi\": 16781558,\n    \"Georgian_gan\": 16781522,\n    \"Georgian_ghan\": 16781542,\n    \"Georgian_hae\": 16781552,\n    \"Georgian_har\": 16781556,\n    \"Georgian_he\": 16781553,\n    \"Georgian_hie\": 16781554,\n    \"Georgian_hoe\": 16781557,\n    \"Georgian_in\": 16781528,\n    \"Georgian_jhan\": 16781551,\n    \"Georgian_jil\": 16781547,\n    \"Georgian_kan\": 16781529,\n    \"Georgian_khar\": 16781541,\n    \"Georgian_las\": 16781530,\n    \"Georgian_man\": 16781531,\n    \"Georgian_nar\": 16781532,\n    \"Georgian_on\": 16781533,\n    \"Georgian_par\": 16781534,\n    \"Georgian_phar\": 16781540,\n    \"Georgian_qar\": 16781543,\n    \"Georgian_rae\": 16781536,\n    \"Georgian_san\": 16781537,\n    \"Georgian_shin\": 16781544,\n    \"Georgian_tan\": 16781527,\n    \"Georgian_tar\": 16781538,\n    \"Georgian_un\": 16781539,\n    \"Georgian_vin\": 16781525,\n    \"Georgian_we\": 16781555,\n    \"Georgian_xan\": 16781550,\n    \"Georgian_zen\": 16781526,\n    \"Georgian_zhar\": 16781535,\n    \"Greek_ALPHA\": 1985,\n    \"Greek_ALPHAaccent\": 1953,\n    \"Greek_BETA\": 1986,\n    \"Greek_CHI\": 2007,\n    \"Greek_DELTA\": 1988,\n    \"Greek_EPSILON\": 1989,\n    \"Greek_EPSILONaccent\": 1954,\n    \"Greek_ETA\": 1991,\n    \"Greek_ETAaccent\": 1955,\n    \"Greek_GAMMA\": 1987,\n    \"Greek_IOTA\": 1993,\n    \"Greek_IOTAaccent\": 1956,\n    \"Greek_IOTAdiaeresis\": 1957,\n    \"Greek_IOTAdieresis\": 1957,\n    \"Greek_KAPPA\": 1994,\n    \"Greek_LAMBDA\": 1995,\n    \"Greek_LAMDA\": 1995,\n    \"Greek_MU\": 1996,\n    \"Greek_NU\": 1997,\n    \"Greek_OMEGA\": 2009,\n    \"Greek_OMEGAaccent\": 1963,\n    \"Greek_OMICRON\": 1999,\n    \"Greek_OMICRONaccent\": 1959,\n    \"Greek_PHI\": 2006,\n    \"Greek_PI\": 2000,\n    \"Greek_PSI\": 2008,\n    \"Greek_RHO\": 2001,\n    \"Greek_SIGMA\": 2002,\n    \"Greek_TAU\": 2004,\n    \"Greek_THETA\": 1992,\n    \"Greek_UPSILON\": 2005,\n    \"Greek_UPSILONaccent\": 1960,\n    \"Greek_UPSILONdieresis\": 1961,\n    \"Greek_XI\": 1998,\n    \"Greek_ZETA\": 1990,\n    \"Greek_accentdieresis\": 1966,\n    \"Greek_alpha\": 2017,\n    \"Greek_alphaaccent\": 1969,\n    \"Greek_beta\": 2018,\n    \"Greek_chi\": 2039,\n    \"Greek_delta\": 2020,\n    \"Greek_epsilon\": 2021,\n    \"Greek_epsilonaccent\": 1970,\n    \"Greek_eta\": 2023,\n    \"Greek_etaaccent\": 1971,\n    \"Greek_finalsmallsigma\": 2035,\n    \"Greek_gamma\": 2019,\n    \"Greek_horizbar\": 1967,\n    \"Greek_iota\": 2025,\n    \"Greek_iotaaccent\": 1972,\n    \"Greek_iotaaccentdieresis\": 1974,\n    \"Greek_iotadieresis\": 1973,\n    \"Greek_kappa\": 2026,\n    \"Greek_lambda\": 2027,\n    \"Greek_lamda\": 2027,\n    \"Greek_mu\": 2028,\n    \"Greek_nu\": 2029,\n    \"Greek_omega\": 2041,\n    \"Greek_omegaaccent\": 1979,\n    \"Greek_omicron\": 2031,\n    \"Greek_omicronaccent\": 1975,\n    \"Greek_phi\": 2038,\n    \"Greek_pi\": 2032,\n    \"Greek_psi\": 2040,\n    \"Greek_rho\": 2033,\n    \"Greek_sigma\": 2034,\n    \"Greek_switch\": 65406,\n    \"Greek_tau\": 2036,\n    \"Greek_theta\": 2024,\n    \"Greek_upsilon\": 2037,\n    \"Greek_upsilonaccent\": 1976,\n    \"Greek_upsilonaccentdieresis\": 1978,\n    \"Greek_upsilondieresis\": 1977,\n    \"Greek_xi\": 2030,\n    \"Greek_zeta\": 2022,\n    \"H\": 72,\n    \"Hangul\": 65329,\n    \"Hangul_A\": 3775,\n    \"Hangul_AE\": 3776,\n    \"Hangul_AraeA\": 3830,\n    \"Hangul_AraeAE\": 3831,\n    \"Hangul_Banja\": 65337,\n    \"Hangul_Cieuc\": 3770,\n    \"Hangul_Codeinput\": 65335,\n    \"Hangul_Dikeud\": 3751,\n    \"Hangul_E\": 3780,\n    \"Hangul_EO\": 3779,\n    \"Hangul_EU\": 3793,\n    \"Hangul_End\": 65331,\n    \"Hangul_Hanja\": 65332,\n    \"Hangul_Hieuh\": 3774,\n    \"Hangul_I\": 3795,\n    \"Hangul_Ieung\": 3767,\n    \"Hangul_J_Cieuc\": 3818,\n    \"Hangul_J_Dikeud\": 3802,\n    \"Hangul_J_Hieuh\": 3822,\n    \"Hangul_J_Ieung\": 3816,\n    \"Hangul_J_Jieuj\": 3817,\n    \"Hangul_J_Khieuq\": 3819,\n    \"Hangul_J_Kiyeog\": 3796,\n    \"Hangul_J_KiyeogSios\": 3798,\n    \"Hangul_J_KkogjiDalrinIeung\": 3833,\n    \"Hangul_J_Mieum\": 3811,\n    \"Hangul_J_Nieun\": 3799,\n    \"Hangul_J_NieunHieuh\": 3801,\n    \"Hangul_J_NieunJieuj\": 3800,\n    \"Hangul_J_PanSios\": 3832,\n    \"Hangul_J_Phieuf\": 3821,\n    \"Hangul_J_Pieub\": 3812,\n    \"Hangul_J_PieubSios\": 3813,\n    \"Hangul_J_Rieul\": 3803,\n    \"Hangul_J_RieulHieuh\": 3810,\n    \"Hangul_J_RieulKiyeog\": 3804,\n    \"Hangul_J_RieulMieum\": 3805,\n    \"Hangul_J_RieulPhieuf\": 3809,\n    \"Hangul_J_RieulPieub\": 3806,\n    \"Hangul_J_RieulSios\": 3807,\n    \"Hangul_J_RieulTieut\": 3808,\n    \"Hangul_J_Sios\": 3814,\n    \"Hangul_J_SsangKiyeog\": 3797,\n    \"Hangul_J_SsangSios\": 3815,\n    \"Hangul_J_Tieut\": 3820,\n    \"Hangul_J_YeorinHieuh\": 3834,\n    \"Hangul_Jamo\": 65333,\n    \"Hangul_Jeonja\": 65336,\n    \"Hangul_Jieuj\": 3768,\n    \"Hangul_Khieuq\": 3771,\n    \"Hangul_Kiyeog\": 3745,\n    \"Hangul_KiyeogSios\": 3747,\n    \"Hangul_KkogjiDalrinIeung\": 3827,\n    \"Hangul_Mieum\": 3761,\n    \"Hangul_MultipleCandidate\": 65341,\n    \"Hangul_Nieun\": 3748,\n    \"Hangul_NieunHieuh\": 3750,\n    \"Hangul_NieunJieuj\": 3749,\n    \"Hangul_O\": 3783,\n    \"Hangul_OE\": 3786,\n    \"Hangul_PanSios\": 3826,\n    \"Hangul_Phieuf\": 3773,\n    \"Hangul_Pieub\": 3762,\n    \"Hangul_PieubSios\": 3764,\n    \"Hangul_PostHanja\": 65339,\n    \"Hangul_PreHanja\": 65338,\n    \"Hangul_PreviousCandidate\": 65342,\n    \"Hangul_Rieul\": 3753,\n    \"Hangul_RieulHieuh\": 3760,\n    \"Hangul_RieulKiyeog\": 3754,\n    \"Hangul_RieulMieum\": 3755,\n    \"Hangul_RieulPhieuf\": 3759,\n    \"Hangul_RieulPieub\": 3756,\n    \"Hangul_RieulSios\": 3757,\n    \"Hangul_RieulTieut\": 3758,\n    \"Hangul_RieulYeorinHieuh\": 3823,\n    \"Hangul_Romaja\": 65334,\n    \"Hangul_SingleCandidate\": 65340,\n    \"Hangul_Sios\": 3765,\n    \"Hangul_Special\": 65343,\n    \"Hangul_SsangDikeud\": 3752,\n    \"Hangul_SsangJieuj\": 3769,\n    \"Hangul_SsangKiyeog\": 3746,\n    \"Hangul_SsangPieub\": 3763,\n    \"Hangul_SsangSios\": 3766,\n    \"Hangul_Start\": 65330,\n    \"Hangul_SunkyeongeumMieum\": 3824,\n    \"Hangul_SunkyeongeumPhieuf\": 3828,\n    \"Hangul_SunkyeongeumPieub\": 3825,\n    \"Hangul_Tieut\": 3772,\n    \"Hangul_U\": 3788,\n    \"Hangul_WA\": 3784,\n    \"Hangul_WAE\": 3785,\n    \"Hangul_WE\": 3790,\n    \"Hangul_WEO\": 3789,\n    \"Hangul_WI\": 3791,\n    \"Hangul_YA\": 3777,\n    \"Hangul_YAE\": 3778,\n    \"Hangul_YE\": 3782,\n    \"Hangul_YEO\": 3781,\n    \"Hangul_YI\": 3794,\n    \"Hangul_YO\": 3787,\n    \"Hangul_YU\": 3792,\n    \"Hangul_YeorinHieuh\": 3829,\n    \"Hangul_switch\": 65406,\n    \"Hankaku\": 65321,\n    \"Hcircumflex\": 678,\n    \"Hebrew_switch\": 65406,\n    \"Help\": 65386,\n    \"Henkan\": 65315,\n    \"Henkan_Mode\": 65315,\n    \"Hiragana\": 65317,\n    \"Hiragana_Katakana\": 65319,\n    \"Home\": 65360,\n    \"Hstroke\": 673,\n    \"Hyper_L\": 65517,\n    \"Hyper_R\": 65518,\n    \"I\": 73,\n    \"ISO_Center_Object\": 65075,\n    \"ISO_Continuous_Underline\": 65072,\n    \"ISO_Discontinuous_Underline\": 65073,\n    \"ISO_Emphasize\": 65074,\n    \"ISO_Enter\": 65076,\n    \"ISO_Fast_Cursor_Down\": 65071,\n    \"ISO_Fast_Cursor_Left\": 65068,\n    \"ISO_Fast_Cursor_Right\": 65069,\n    \"ISO_Fast_Cursor_Up\": 65070,\n    \"ISO_First_Group\": 65036,\n    \"ISO_First_Group_Lock\": 65037,\n    \"ISO_Group_Latch\": 65030,\n    \"ISO_Group_Lock\": 65031,\n    \"ISO_Group_Shift\": 65406,\n    \"ISO_Last_Group\": 65038,\n    \"ISO_Last_Group_Lock\": 65039,\n    \"ISO_Left_Tab\": 65056,\n    \"ISO_Level2_Latch\": 65026,\n    \"ISO_Level3_Latch\": 65028,\n    \"ISO_Level3_Lock\": 65029,\n    \"ISO_Level3_Shift\": 65027,\n    \"ISO_Level5_Latch\": 65042,\n    \"ISO_Level5_Lock\": 65043,\n    \"ISO_Level5_Shift\": 65041,\n    \"ISO_Lock\": 65025,\n    \"ISO_Move_Line_Down\": 65058,\n    \"ISO_Move_Line_Up\": 65057,\n    \"ISO_Next_Group\": 65032,\n    \"ISO_Next_Group_Lock\": 65033,\n    \"ISO_Partial_Line_Down\": 65060,\n    \"ISO_Partial_Line_Up\": 65059,\n    \"ISO_Partial_Space_Left\": 65061,\n    \"ISO_Partial_Space_Right\": 65062,\n    \"ISO_Prev_Group\": 65034,\n    \"ISO_Prev_Group_Lock\": 65035,\n    \"ISO_Release_Both_Margins\": 65067,\n    \"ISO_Release_Margin_Left\": 65065,\n    \"ISO_Release_Margin_Right\": 65066,\n    \"ISO_Set_Margin_Left\": 65063,\n    \"ISO_Set_Margin_Right\": 65064,\n    \"Iabovedot\": 681,\n    \"Iacute\": 205,\n    \"Ibelowdot\": 16785098,\n    \"Ibreve\": 16777516,\n    \"Icircumflex\": 206,\n    \"Idiaeresis\": 207,\n    \"Igrave\": 204,\n    \"Ihook\": 16785096,\n    \"Imacron\": 975,\n    \"Insert\": 65379,\n    \"Iogonek\": 967,\n    \"Itilde\": 933,\n    \"J\": 74,\n    \"Jcircumflex\": 684,\n    \"K\": 75,\n    \"KP_0\": 65456,\n    \"KP_1\": 65457,\n    \"KP_2\": 65458,\n    \"KP_3\": 65459,\n    \"KP_4\": 65460,\n    \"KP_5\": 65461,\n    \"KP_6\": 65462,\n    \"KP_7\": 65463,\n    \"KP_8\": 65464,\n    \"KP_9\": 65465,\n    \"KP_Add\": 65451,\n    \"KP_Begin\": 65437,\n    \"KP_Decimal\": 65454,\n    \"KP_Delete\": 65439,\n    \"KP_Divide\": 65455,\n    \"KP_Down\": 65433,\n    \"KP_End\": 65436,\n    \"KP_Enter\": 65421,\n    \"KP_Equal\": 65469,\n    \"KP_F1\": 65425,\n    \"KP_F2\": 65426,\n    \"KP_F3\": 65427,\n    \"KP_F4\": 65428,\n    \"KP_Home\": 65429,\n    \"KP_Insert\": 65438,\n    \"KP_Left\": 65430,\n    \"KP_Multiply\": 65450,\n    \"KP_Next\": 65435,\n    \"KP_Page_Down\": 65435,\n    \"KP_Page_Up\": 65434,\n    \"KP_Prior\": 65434,\n    \"KP_Right\": 65432,\n    \"KP_Separator\": 65452,\n    \"KP_Space\": 65408,\n    \"KP_Subtract\": 65453,\n    \"KP_Tab\": 65417,\n    \"KP_Up\": 65431,\n    \"Kana_Lock\": 65325,\n    \"Kana_Shift\": 65326,\n    \"Kanji\": 65313,\n    \"Kanji_Bangou\": 65335,\n    \"Katakana\": 65318,\n    \"Kcedilla\": 979,\n    \"Korean_Won\": 3839,\n    \"L\": 76,\n    \"L1\": 65480,\n    \"L10\": 65489,\n    \"L2\": 65481,\n    \"L3\": 65482,\n    \"L4\": 65483,\n    \"L5\": 65484,\n    \"L6\": 65485,\n    \"L7\": 65486,\n    \"L8\": 65487,\n    \"L9\": 65488,\n    \"Lacute\": 453,\n    \"Last_Virtual_Screen\": 65236,\n    \"Lbelowdot\": 16784950,\n    \"Lcaron\": 421,\n    \"Lcedilla\": 934,\n    \"Left\": 65361,\n    \"Linefeed\": 65290,\n    \"LiraSign\": 16785572,\n    \"Lstroke\": 419,\n    \"M\": 77,\n    \"Mabovedot\": 16784960,\n    \"Macedonia_DSE\": 1717,\n    \"Macedonia_GJE\": 1714,\n    \"Macedonia_KJE\": 1724,\n    \"Macedonia_dse\": 1701,\n    \"Macedonia_gje\": 1698,\n    \"Macedonia_kje\": 1708,\n    \"Mae_Koho\": 65342,\n    \"Massyo\": 65324,\n    \"Menu\": 65383,\n    \"Meta_L\": 65511,\n    \"Meta_R\": 65512,\n    \"MillSign\": 16785573,\n    \"Mode_switch\": 65406,\n    \"MouseKeys_Accel_Enable\": 65143,\n    \"MouseKeys_Enable\": 65142,\n    \"Muhenkan\": 65314,\n    \"Multi_key\": 65312,\n    \"MultipleCandidate\": 65341,\n    \"N\": 78,\n    \"Nacute\": 465,\n    \"NairaSign\": 16785574,\n    \"Ncaron\": 466,\n    \"Ncedilla\": 977,\n    \"NewSheqelSign\": 16785578,\n    \"Next\": 65366,\n    \"Next_Virtual_Screen\": 65234,\n    \"Ntilde\": 209,\n    \"Num_Lock\": 65407,\n    \"O\": 79,\n    \"OE\": 5052,\n    \"Oacute\": 211,\n    \"Obarred\": 16777631,\n    \"Obelowdot\": 16785100,\n    \"Ocaron\": 16777681,\n    \"Ocircumflex\": 212,\n    \"Ocircumflexacute\": 16785104,\n    \"Ocircumflexbelowdot\": 16785112,\n    \"Ocircumflexgrave\": 16785106,\n    \"Ocircumflexhook\": 16785108,\n    \"Ocircumflextilde\": 16785110,\n    \"Odiaeresis\": 214,\n    \"Odoubleacute\": 469,\n    \"Ograve\": 210,\n    \"Ohook\": 16785102,\n    \"Ohorn\": 16777632,\n    \"Ohornacute\": 16785114,\n    \"Ohornbelowdot\": 16785122,\n    \"Ohorngrave\": 16785116,\n    \"Ohornhook\": 16785118,\n    \"Ohorntilde\": 16785120,\n    \"Omacron\": 978,\n    \"Ooblique\": 216,\n    \"Oslash\": 216,\n    \"Otilde\": 213,\n    \"Overlay1_Enable\": 65144,\n    \"Overlay2_Enable\": 65145,\n    \"P\": 80,\n    \"Pabovedot\": 16784982,\n    \"Page_Down\": 65366,\n    \"Page_Up\": 65365,\n    \"Pause\": 65299,\n    \"PesetaSign\": 16785575,\n    \"Pointer_Accelerate\": 65274,\n    \"Pointer_Button1\": 65257,\n    \"Pointer_Button2\": 65258,\n    \"Pointer_Button3\": 65259,\n    \"Pointer_Button4\": 65260,\n    \"Pointer_Button5\": 65261,\n    \"Pointer_Button_Dflt\": 65256,\n    \"Pointer_DblClick1\": 65263,\n    \"Pointer_DblClick2\": 65264,\n    \"Pointer_DblClick3\": 65265,\n    \"Pointer_DblClick4\": 65266,\n    \"Pointer_DblClick5\": 65267,\n    \"Pointer_DblClick_Dflt\": 65262,\n    \"Pointer_DfltBtnNext\": 65275,\n    \"Pointer_DfltBtnPrev\": 65276,\n    \"Pointer_Down\": 65251,\n    \"Pointer_DownLeft\": 65254,\n    \"Pointer_DownRight\": 65255,\n    \"Pointer_Drag1\": 65269,\n    \"Pointer_Drag2\": 65270,\n    \"Pointer_Drag3\": 65271,\n    \"Pointer_Drag4\": 65272,\n    \"Pointer_Drag5\": 65277,\n    \"Pointer_Drag_Dflt\": 65268,\n    \"Pointer_EnableKeys\": 65273,\n    \"Pointer_Left\": 65248,\n    \"Pointer_Right\": 65249,\n    \"Pointer_Up\": 65250,\n    \"Pointer_UpLeft\": 65252,\n    \"Pointer_UpRight\": 65253,\n    \"Prev_Virtual_Screen\": 65233,\n    \"PreviousCandidate\": 65342,\n    \"Print\": 65377,\n    \"Prior\": 65365,\n    \"Q\": 81,\n    \"R\": 82,\n    \"R1\": 65490,\n    \"R10\": 65499,\n    \"R11\": 65500,\n    \"R12\": 65501,\n    \"R13\": 65502,\n    \"R14\": 65503,\n    \"R15\": 65504,\n    \"R2\": 65491,\n    \"R3\": 65492,\n    \"R4\": 65493,\n    \"R5\": 65494,\n    \"R6\": 65495,\n    \"R7\": 65496,\n    \"R8\": 65497,\n    \"R9\": 65498,\n    \"Racute\": 448,\n    \"Rcaron\": 472,\n    \"Rcedilla\": 931,\n    \"Redo\": 65382,\n    \"RepeatKeys_Enable\": 65138,\n    \"Return\": 65293,\n    \"Right\": 65363,\n    \"Romaji\": 65316,\n    \"RupeeSign\": 16785576,\n    \"S\": 83,\n    \"SCHWA\": 16777615,\n    \"Sabovedot\": 16784992,\n    \"Sacute\": 422,\n    \"Scaron\": 425,\n    \"Scedilla\": 426,\n    \"Scircumflex\": 734,\n    \"Scroll_Lock\": 65300,\n    \"Select\": 65376,\n    \"Serbian_DJE\": 1713,\n    \"Serbian_DZE\": 1727,\n    \"Serbian_JE\": 1720,\n    \"Serbian_LJE\": 1721,\n    \"Serbian_NJE\": 1722,\n    \"Serbian_TSHE\": 1723,\n    \"Serbian_dje\": 1697,\n    \"Serbian_dze\": 1711,\n    \"Serbian_je\": 1704,\n    \"Serbian_lje\": 1705,\n    \"Serbian_nje\": 1706,\n    \"Serbian_tshe\": 1707,\n    \"Shift_L\": 65505,\n    \"Shift_Lock\": 65510,\n    \"Shift_R\": 65506,\n    \"SingleCandidate\": 65340,\n    \"Sinh_a\": 16780677,\n    \"Sinh_aa\": 16780678,\n    \"Sinh_aa2\": 16780751,\n    \"Sinh_ae\": 16780679,\n    \"Sinh_ae2\": 16780752,\n    \"Sinh_aee\": 16780680,\n    \"Sinh_aee2\": 16780753,\n    \"Sinh_ai\": 16780691,\n    \"Sinh_ai2\": 16780763,\n    \"Sinh_al\": 16780746,\n    \"Sinh_au\": 16780694,\n    \"Sinh_au2\": 16780766,\n    \"Sinh_ba\": 16780726,\n    \"Sinh_bha\": 16780727,\n    \"Sinh_ca\": 16780704,\n    \"Sinh_cha\": 16780705,\n    \"Sinh_dda\": 16780713,\n    \"Sinh_ddha\": 16780714,\n    \"Sinh_dha\": 16780719,\n    \"Sinh_dhha\": 16780720,\n    \"Sinh_e\": 16780689,\n    \"Sinh_e2\": 16780761,\n    \"Sinh_ee\": 16780690,\n    \"Sinh_ee2\": 16780762,\n    \"Sinh_fa\": 16780742,\n    \"Sinh_ga\": 16780700,\n    \"Sinh_gha\": 16780701,\n    \"Sinh_h2\": 16780675,\n    \"Sinh_ha\": 16780740,\n    \"Sinh_i\": 16780681,\n    \"Sinh_i2\": 16780754,\n    \"Sinh_ii\": 16780682,\n    \"Sinh_ii2\": 16780755,\n    \"Sinh_ja\": 16780706,\n    \"Sinh_jha\": 16780707,\n    \"Sinh_jnya\": 16780709,\n    \"Sinh_ka\": 16780698,\n    \"Sinh_kha\": 16780699,\n    \"Sinh_kunddaliya\": 16780788,\n    \"Sinh_la\": 16780733,\n    \"Sinh_lla\": 16780741,\n    \"Sinh_lu\": 16780687,\n    \"Sinh_lu2\": 16780767,\n    \"Sinh_luu\": 16780688,\n    \"Sinh_luu2\": 16780787,\n    \"Sinh_ma\": 16780728,\n    \"Sinh_mba\": 16780729,\n    \"Sinh_na\": 16780721,\n    \"Sinh_ndda\": 16780716,\n    \"Sinh_ndha\": 16780723,\n    \"Sinh_ng\": 16780674,\n    \"Sinh_ng2\": 16780702,\n    \"Sinh_nga\": 16780703,\n    \"Sinh_nja\": 16780710,\n    \"Sinh_nna\": 16780715,\n    \"Sinh_nya\": 16780708,\n    \"Sinh_o\": 16780692,\n    \"Sinh_o2\": 16780764,\n    \"Sinh_oo\": 16780693,\n    \"Sinh_oo2\": 16780765,\n    \"Sinh_pa\": 16780724,\n    \"Sinh_pha\": 16780725,\n    \"Sinh_ra\": 16780731,\n    \"Sinh_ri\": 16780685,\n    \"Sinh_rii\": 16780686,\n    \"Sinh_ru2\": 16780760,\n    \"Sinh_ruu2\": 16780786,\n    \"Sinh_sa\": 16780739,\n    \"Sinh_sha\": 16780737,\n    \"Sinh_ssha\": 16780738,\n    \"Sinh_tha\": 16780717,\n    \"Sinh_thha\": 16780718,\n    \"Sinh_tta\": 16780711,\n    \"Sinh_ttha\": 16780712,\n    \"Sinh_u\": 16780683,\n    \"Sinh_u2\": 16780756,\n    \"Sinh_uu\": 16780684,\n    \"Sinh_uu2\": 16780758,\n    \"Sinh_va\": 16780736,\n    \"Sinh_ya\": 16780730,\n    \"SlowKeys_Enable\": 65139,\n    \"StickyKeys_Enable\": 65141,\n    \"Super_L\": 65515,\n    \"Super_R\": 65516,\n    \"Sys_Req\": 65301,\n    \"T\": 84,\n    \"THORN\": 222,\n    \"Tab\": 65289,\n    \"Tabovedot\": 16785002,\n    \"Tcaron\": 427,\n    \"Tcedilla\": 478,\n    \"Terminate_Server\": 65237,\n    \"Thai_baht\": 3551,\n    \"Thai_bobaimai\": 3514,\n    \"Thai_chochan\": 3496,\n    \"Thai_chochang\": 3498,\n    \"Thai_choching\": 3497,\n    \"Thai_chochoe\": 3500,\n    \"Thai_dochada\": 3502,\n    \"Thai_dodek\": 3508,\n    \"Thai_fofa\": 3517,\n    \"Thai_fofan\": 3519,\n    \"Thai_hohip\": 3531,\n    \"Thai_honokhuk\": 3534,\n    \"Thai_khokhai\": 3490,\n    \"Thai_khokhon\": 3493,\n    \"Thai_khokhuat\": 3491,\n    \"Thai_khokhwai\": 3492,\n    \"Thai_khorakhang\": 3494,\n    \"Thai_kokai\": 3489,\n    \"Thai_lakkhangyao\": 3557,\n    \"Thai_lekchet\": 3575,\n    \"Thai_lekha\": 3573,\n    \"Thai_lekhok\": 3574,\n    \"Thai_lekkao\": 3577,\n    \"Thai_leknung\": 3569,\n    \"Thai_lekpaet\": 3576,\n    \"Thai_leksam\": 3571,\n    \"Thai_leksi\": 3572,\n    \"Thai_leksong\": 3570,\n    \"Thai_leksun\": 3568,\n    \"Thai_lochula\": 3532,\n    \"Thai_loling\": 3525,\n    \"Thai_lu\": 3526,\n    \"Thai_maichattawa\": 3563,\n    \"Thai_maiek\": 3560,\n    \"Thai_maihanakat\": 3537,\n    \"Thai_maihanakat_maitho\": 3550,\n    \"Thai_maitaikhu\": 3559,\n    \"Thai_maitho\": 3561,\n    \"Thai_maitri\": 3562,\n    \"Thai_maiyamok\": 3558,\n    \"Thai_moma\": 3521,\n    \"Thai_ngongu\": 3495,\n    \"Thai_nikhahit\": 3565,\n    \"Thai_nonen\": 3507,\n    \"Thai_nonu\": 3513,\n    \"Thai_oang\": 3533,\n    \"Thai_paiyannoi\": 3535,\n    \"Thai_phinthu\": 3546,\n    \"Thai_phophan\": 3518,\n    \"Thai_phophung\": 3516,\n    \"Thai_phosamphao\": 3520,\n    \"Thai_popla\": 3515,\n    \"Thai_rorua\": 3523,\n    \"Thai_ru\": 3524,\n    \"Thai_saraa\": 3536,\n    \"Thai_saraaa\": 3538,\n    \"Thai_saraae\": 3553,\n    \"Thai_saraaimaimalai\": 3556,\n    \"Thai_saraaimaimuan\": 3555,\n    \"Thai_saraam\": 3539,\n    \"Thai_sarae\": 3552,\n    \"Thai_sarai\": 3540,\n    \"Thai_saraii\": 3541,\n    \"Thai_sarao\": 3554,\n    \"Thai_sarau\": 3544,\n    \"Thai_saraue\": 3542,\n    \"Thai_sarauee\": 3543,\n    \"Thai_sarauu\": 3545,\n    \"Thai_sorusi\": 3529,\n    \"Thai_sosala\": 3528,\n    \"Thai_soso\": 3499,\n    \"Thai_sosua\": 3530,\n    \"Thai_thanthakhat\": 3564,\n    \"Thai_thonangmontho\": 3505,\n    \"Thai_thophuthao\": 3506,\n    \"Thai_thothahan\": 3511,\n    \"Thai_thothan\": 3504,\n    \"Thai_thothong\": 3512,\n    \"Thai_thothung\": 3510,\n    \"Thai_topatak\": 3503,\n    \"Thai_totao\": 3509,\n    \"Thai_wowaen\": 3527,\n    \"Thai_yoyak\": 3522,\n    \"Thai_yoying\": 3501,\n    \"Thorn\": 222,\n    \"Touroku\": 65323,\n    \"Tslash\": 940,\n    \"U\": 85,\n    \"Uacute\": 218,\n    \"Ubelowdot\": 16785124,\n    \"Ubreve\": 733,\n    \"Ucircumflex\": 219,\n    \"Udiaeresis\": 220,\n    \"Udoubleacute\": 475,\n    \"Ugrave\": 217,\n    \"Uhook\": 16785126,\n    \"Uhorn\": 16777647,\n    \"Uhornacute\": 16785128,\n    \"Uhornbelowdot\": 16785136,\n    \"Uhorngrave\": 16785130,\n    \"Uhornhook\": 16785132,\n    \"Uhorntilde\": 16785134,\n    \"Ukrainian_GHE_WITH_UPTURN\": 1725,\n    \"Ukrainian_I\": 1718,\n    \"Ukrainian_IE\": 1716,\n    \"Ukrainian_YI\": 1719,\n    \"Ukrainian_ghe_with_upturn\": 1709,\n    \"Ukrainian_i\": 1702,\n    \"Ukrainian_ie\": 1700,\n    \"Ukrainian_yi\": 1703,\n    \"Ukranian_I\": 1718,\n    \"Ukranian_JE\": 1716,\n    \"Ukranian_YI\": 1719,\n    \"Ukranian_i\": 1702,\n    \"Ukranian_je\": 1700,\n    \"Ukranian_yi\": 1703,\n    \"Umacron\": 990,\n    \"Undo\": 65381,\n    \"Uogonek\": 985,\n    \"Up\": 65362,\n    \"Uring\": 473,\n    \"Utilde\": 989,\n    \"V\": 86,\n    \"VoidSymbol\": 16777215,\n    \"W\": 87,\n    \"Wacute\": 16785026,\n    \"Wcircumflex\": 16777588,\n    \"Wdiaeresis\": 16785028,\n    \"Wgrave\": 16785024,\n    \"WonSign\": 16785577,\n    \"X\": 88,\n    \"XF86_AddFavorite\": 269025081,\n    \"XF86_ApplicationLeft\": 269025104,\n    \"XF86_ApplicationRight\": 269025105,\n    \"XF86_AudioCycleTrack\": 269025179,\n    \"XF86_AudioForward\": 269025175,\n    \"XF86_AudioLowerVolume\": 269025041,\n    \"XF86_AudioMedia\": 269025074,\n    \"XF86_AudioMicMute\": 269025202,\n    \"XF86_AudioMute\": 269025042,\n    \"XF86_AudioNext\": 269025047,\n    \"XF86_AudioPause\": 269025073,\n    \"XF86_AudioPlay\": 269025044,\n    \"XF86_AudioPreset\": 269025206,\n    \"XF86_AudioPrev\": 269025046,\n    \"XF86_AudioRaiseVolume\": 269025043,\n    \"XF86_AudioRandomPlay\": 269025177,\n    \"XF86_AudioRecord\": 269025052,\n    \"XF86_AudioRepeat\": 269025176,\n    \"XF86_AudioRewind\": 269025086,\n    \"XF86_AudioStop\": 269025045,\n    \"XF86_Away\": 269025165,\n    \"XF86_Back\": 269025062,\n    \"XF86_BackForward\": 269025087,\n    \"XF86_Battery\": 269025171,\n    \"XF86_Blue\": 269025190,\n    \"XF86_Bluetooth\": 269025172,\n    \"XF86_Book\": 269025106,\n    \"XF86_BrightnessAdjust\": 269025083,\n    \"XF86_CD\": 269025107,\n    \"XF86_Calculater\": 269025108,\n    \"XF86_Calculator\": 269025053,\n    \"XF86_Calendar\": 269025056,\n    \"XF86_Clear\": 269025109,\n    \"XF86_ClearGrab\": 269024801,\n    \"XF86_Close\": 269025110,\n    \"XF86_Community\": 269025085,\n    \"XF86_ContrastAdjust\": 269025058,\n    \"XF86_Copy\": 269025111,\n    \"XF86_Cut\": 269025112,\n    \"XF86_CycleAngle\": 269025180,\n    \"XF86_DOS\": 269025114,\n    \"XF86_Display\": 269025113,\n    \"XF86_Documents\": 269025115,\n    \"XF86_Eject\": 269025068,\n    \"XF86_Excel\": 269025116,\n    \"XF86_Explorer\": 269025117,\n    \"XF86_Favorites\": 269025072,\n    \"XF86_Finance\": 269025084,\n    \"XF86_Forward\": 269025063,\n    \"XF86_FrameBack\": 269025181,\n    \"XF86_FrameForward\": 269025182,\n    \"XF86_FullScreen\": 269025208,\n    \"XF86_Game\": 269025118,\n    \"XF86_Go\": 269025119,\n    \"XF86_Green\": 269025188,\n    \"XF86_Hibernate\": 269025192,\n    \"XF86_History\": 269025079,\n    \"XF86_HomePage\": 269025048,\n    \"XF86_HotLinks\": 269025082,\n    \"XF86_KbdBrightnessDown\": 269025030,\n    \"XF86_KbdBrightnessUp\": 269025029,\n    \"XF86_KbdLightOnOff\": 269025028,\n    \"XF86_Keyboard\": 269025203,\n    \"XF86_Launch0\": 269025088,\n    \"XF86_Launch1\": 269025089,\n    \"XF86_Launch2\": 269025090,\n    \"XF86_Launch3\": 269025091,\n    \"XF86_Launch4\": 269025092,\n    \"XF86_Launch5\": 269025093,\n    \"XF86_Launch6\": 269025094,\n    \"XF86_Launch7\": 269025095,\n    \"XF86_Launch8\": 269025096,\n    \"XF86_Launch9\": 269025097,\n    \"XF86_LaunchA\": 269025098,\n    \"XF86_LaunchB\": 269025099,\n    \"XF86_LaunchC\": 269025100,\n    \"XF86_LaunchD\": 269025101,\n    \"XF86_LaunchE\": 269025102,\n    \"XF86_LaunchF\": 269025103,\n    \"XF86_LightBulb\": 269025077,\n    \"XF86_LogGrabInfo\": 269024805,\n    \"XF86_LogOff\": 269025121,\n    \"XF86_LogWindowTree\": 269024804,\n    \"XF86_MacroRecordStart\": 268964528,\n    \"XF86_Mail\": 269025049,\n    \"XF86_MailForward\": 269025168,\n    \"XF86_Market\": 269025122,\n    \"XF86_Meeting\": 269025123,\n    \"XF86_Memo\": 269025054,\n    \"XF86_MenuKB\": 269025125,\n    \"XF86_MenuPB\": 269025126,\n    \"XF86_Messenger\": 269025166,\n    \"XF86_ModeLock\": 269025025,\n    \"XF86_MonBrightnessCycle\": 269025031,\n    \"XF86_MonBrightnessDown\": 269025027,\n    \"XF86_MonBrightnessUp\": 269025026,\n    \"XF86_Music\": 269025170,\n    \"XF86_MyComputer\": 269025075,\n    \"XF86_MySites\": 269025127,\n    \"XF86_New\": 269025128,\n    \"XF86_News\": 269025129,\n    \"XF86_Next_VMode\": 269024802,\n    \"XF86_OfficeHome\": 269025130,\n    \"XF86_Open\": 269025131,\n    \"XF86_OpenURL\": 269025080,\n    \"XF86_Option\": 269025132,\n    \"XF86_Paste\": 269025133,\n    \"XF86_Phone\": 269025134,\n    \"XF86_Pictures\": 269025169,\n    \"XF86_PowerDown\": 269025057,\n    \"XF86_PowerOff\": 269025066,\n    \"XF86_Prev_VMode\": 269024803,\n    \"XF86_Q\": 269025136,\n    \"XF86_RFKill\": 269025205,\n    \"XF86_Red\": 269025187,\n    \"XF86_Refresh\": 269025065,\n    \"XF86_Reload\": 269025139,\n    \"XF86_Reply\": 269025138,\n    \"XF86_RockerDown\": 269025060,\n    \"XF86_RockerEnter\": 269025061,\n    \"XF86_RockerUp\": 269025059,\n    \"XF86_RotateWindows\": 269025140,\n    \"XF86_RotationKB\": 269025142,\n    \"XF86_RotationLockToggle\": 269025207,\n    \"XF86_RotationPB\": 269025141,\n    \"XF86_Save\": 269025143,\n    \"XF86_ScreenSaver\": 269025069,\n    \"XF86_ScrollClick\": 269025146,\n    \"XF86_ScrollDown\": 269025145,\n    \"XF86_ScrollUp\": 269025144,\n    \"XF86_Search\": 269025051,\n    \"XF86_Select\": 269025184,\n    \"XF86_Send\": 269025147,\n    \"XF86_Shop\": 269025078,\n    \"XF86_Sleep\": 269025071,\n    \"XF86_Spell\": 269025148,\n    \"XF86_SplitScreen\": 269025149,\n    \"XF86_Standby\": 269025040,\n    \"XF86_Start\": 269025050,\n    \"XF86_Stop\": 269025064,\n    \"XF86_Subtitle\": 269025178,\n    \"XF86_Support\": 269025150,\n    \"XF86_Suspend\": 269025191,\n    \"XF86_Switch_VT_1\": 269024769,\n    \"XF86_Switch_VT_10\": 269024778,\n    \"XF86_Switch_VT_11\": 269024779,\n    \"XF86_Switch_VT_12\": 269024780,\n    \"XF86_Switch_VT_2\": 269024770,\n    \"XF86_Switch_VT_3\": 269024771,\n    \"XF86_Switch_VT_4\": 269024772,\n    \"XF86_Switch_VT_5\": 269024773,\n    \"XF86_Switch_VT_6\": 269024774,\n    \"XF86_Switch_VT_7\": 269024775,\n    \"XF86_Switch_VT_8\": 269024776,\n    \"XF86_Switch_VT_9\": 269024777,\n    \"XF86_TaskPane\": 269025151,\n    \"XF86_Terminal\": 269025152,\n    \"XF86_Time\": 269025183,\n    \"XF86_ToDoList\": 269025055,\n    \"XF86_Tools\": 269025153,\n    \"XF86_TopMenu\": 269025186,\n    \"XF86_TouchpadOff\": 269025201,\n    \"XF86_TouchpadOn\": 269025200,\n    \"XF86_TouchpadToggle\": 269025193,\n    \"XF86_Travel\": 269025154,\n    \"XF86_UWB\": 269025174,\n    \"XF86_Ungrab\": 269024800,\n    \"XF86_User1KB\": 269025157,\n    \"XF86_User2KB\": 269025158,\n    \"XF86_UserPB\": 269025156,\n    \"XF86_VendorHome\": 269025076,\n    \"XF86_Video\": 269025159,\n    \"XF86_View\": 269025185,\n    \"XF86_WLAN\": 269025173,\n    \"XF86_WWAN\": 269025204,\n    \"XF86_WWW\": 269025070,\n    \"XF86_WakeUp\": 269025067,\n    \"XF86_WebCam\": 269025167,\n    \"XF86_WheelButton\": 269025160,\n    \"XF86_Word\": 269025161,\n    \"XF86_Xfer\": 269025162,\n    \"XF86_Yellow\": 269025189,\n    \"XF86_ZoomIn\": 269025163,\n    \"XF86_ZoomOut\": 269025164,\n    \"XF86_iTouch\": 269025120,\n    \"Xabovedot\": 16785034,\n    \"Y\": 89,\n    \"Yacute\": 221,\n    \"Ybelowdot\": 16785140,\n    \"Ycircumflex\": 16777590,\n    \"Ydiaeresis\": 5054,\n    \"Ygrave\": 16785138,\n    \"Yhook\": 16785142,\n    \"Ytilde\": 16785144,\n    \"Z\": 90,\n    \"Zabovedot\": 431,\n    \"Zacute\": 428,\n    \"Zcaron\": 430,\n    \"Zen_Koho\": 65341,\n    \"Zenkaku\": 65320,\n    \"Zenkaku_Hankaku\": 65322,\n    \"Zstroke\": 16777653,\n    \"a\": 97,\n    \"aacute\": 225,\n    \"abelowdot\": 16785057,\n    \"abovedot\": 511,\n    \"abreve\": 483,\n    \"abreveacute\": 16785071,\n    \"abrevebelowdot\": 16785079,\n    \"abrevegrave\": 16785073,\n    \"abrevehook\": 16785075,\n    \"abrevetilde\": 16785077,\n    \"acircumflex\": 226,\n    \"acircumflexacute\": 16785061,\n    \"acircumflexbelowdot\": 16785069,\n    \"acircumflexgrave\": 16785063,\n    \"acircumflexhook\": 16785065,\n    \"acircumflextilde\": 16785067,\n    \"acute\": 180,\n    \"adiaeresis\": 228,\n    \"ae\": 230,\n    \"agrave\": 224,\n    \"ahook\": 16785059,\n    \"amacron\": 992,\n    \"ampersand\": 38,\n    \"aogonek\": 433,\n    \"apostrophe\": 39,\n    \"approxeq\": 16785992,\n    \"approximate\": 2248,\n    \"aring\": 229,\n    \"asciicircum\": 94,\n    \"asciitilde\": 126,\n    \"asterisk\": 42,\n    \"at\": 64,\n    \"atilde\": 227,\n    \"b\": 98,\n    \"babovedot\": 16784899,\n    \"backslash\": 92,\n    \"ballotcross\": 2804,\n    \"bar\": 124,\n    \"because\": 16785973,\n    \"blank\": 2527,\n    \"botintegral\": 2213,\n    \"botleftparens\": 2220,\n    \"botleftsqbracket\": 2216,\n    \"botleftsummation\": 2226,\n    \"botrightparens\": 2222,\n    \"botrightsqbracket\": 2218,\n    \"botrightsummation\": 2230,\n    \"bott\": 2550,\n    \"botvertsummationconnector\": 2228,\n    \"braceleft\": 123,\n    \"braceright\": 125,\n    \"bracketleft\": 91,\n    \"bracketright\": 93,\n    \"braille_blank\": 16787456,\n    \"braille_dot_1\": 65521,\n    \"braille_dot_10\": 65530,\n    \"braille_dot_2\": 65522,\n    \"braille_dot_3\": 65523,\n    \"braille_dot_4\": 65524,\n    \"braille_dot_5\": 65525,\n    \"braille_dot_6\": 65526,\n    \"braille_dot_7\": 65527,\n    \"braille_dot_8\": 65528,\n    \"braille_dot_9\": 65529,\n    \"braille_dots_1\": 16787457,\n    \"braille_dots_12\": 16787459,\n    \"braille_dots_123\": 16787463,\n    \"braille_dots_1234\": 16787471,\n    \"braille_dots_12345\": 16787487,\n    \"braille_dots_123456\": 16787519,\n    \"braille_dots_1234567\": 16787583,\n    \"braille_dots_12345678\": 16787711,\n    \"braille_dots_1234568\": 16787647,\n    \"braille_dots_123457\": 16787551,\n    \"braille_dots_1234578\": 16787679,\n    \"braille_dots_123458\": 16787615,\n    \"braille_dots_12346\": 16787503,\n    \"braille_dots_123467\": 16787567,\n    \"braille_dots_1234678\": 16787695,\n    \"braille_dots_123468\": 16787631,\n    \"braille_dots_12347\": 16787535,\n    \"braille_dots_123478\": 16787663,\n    \"braille_dots_12348\": 16787599,\n    \"braille_dots_1235\": 16787479,\n    \"braille_dots_12356\": 16787511,\n    \"braille_dots_123567\": 16787575,\n    \"braille_dots_1235678\": 16787703,\n    \"braille_dots_123568\": 16787639,\n    \"braille_dots_12357\": 16787543,\n    \"braille_dots_123578\": 16787671,\n    \"braille_dots_12358\": 16787607,\n    \"braille_dots_1236\": 16787495,\n    \"braille_dots_12367\": 16787559,\n    \"braille_dots_123678\": 16787687,\n    \"braille_dots_12368\": 16787623,\n    \"braille_dots_1237\": 16787527,\n    \"braille_dots_12378\": 16787655,\n    \"braille_dots_1238\": 16787591,\n    \"braille_dots_124\": 16787467,\n    \"braille_dots_1245\": 16787483,\n    \"braille_dots_12456\": 16787515,\n    \"braille_dots_124567\": 16787579,\n    \"braille_dots_1245678\": 16787707,\n    \"braille_dots_124568\": 16787643,\n    \"braille_dots_12457\": 16787547,\n    \"braille_dots_124578\": 16787675,\n    \"braille_dots_12458\": 16787611,\n    \"braille_dots_1246\": 16787499,\n    \"braille_dots_12467\": 16787563,\n    \"braille_dots_124678\": 16787691,\n    \"braille_dots_12468\": 16787627,\n    \"braille_dots_1247\": 16787531,\n    \"braille_dots_12478\": 16787659,\n    \"braille_dots_1248\": 16787595,\n    \"braille_dots_125\": 16787475,\n    \"braille_dots_1256\": 16787507,\n    \"braille_dots_12567\": 16787571,\n    \"braille_dots_125678\": 16787699,\n    \"braille_dots_12568\": 16787635,\n    \"braille_dots_1257\": 16787539,\n    \"braille_dots_12578\": 16787667,\n    \"braille_dots_1258\": 16787603,\n    \"braille_dots_126\": 16787491,\n    \"braille_dots_1267\": 16787555,\n    \"braille_dots_12678\": 16787683,\n    \"braille_dots_1268\": 16787619,\n    \"braille_dots_127\": 16787523,\n    \"braille_dots_1278\": 16787651,\n    \"braille_dots_128\": 16787587,\n    \"braille_dots_13\": 16787461,\n    \"braille_dots_134\": 16787469,\n    \"braille_dots_1345\": 16787485,\n    \"braille_dots_13456\": 16787517,\n    \"braille_dots_134567\": 16787581,\n    \"braille_dots_1345678\": 16787709,\n    \"braille_dots_134568\": 16787645,\n    \"braille_dots_13457\": 16787549,\n    \"braille_dots_134578\": 16787677,\n    \"braille_dots_13458\": 16787613,\n    \"braille_dots_1346\": 16787501,\n    \"braille_dots_13467\": 16787565,\n    \"braille_dots_134678\": 16787693,\n    \"braille_dots_13468\": 16787629,\n    \"braille_dots_1347\": 16787533,\n    \"braille_dots_13478\": 16787661,\n    \"braille_dots_1348\": 16787597,\n    \"braille_dots_135\": 16787477,\n    \"braille_dots_1356\": 16787509,\n    \"braille_dots_13567\": 16787573,\n    \"braille_dots_135678\": 16787701,\n    \"braille_dots_13568\": 16787637,\n    \"braille_dots_1357\": 16787541,\n    \"braille_dots_13578\": 16787669,\n    \"braille_dots_1358\": 16787605,\n    \"braille_dots_136\": 16787493,\n    \"braille_dots_1367\": 16787557,\n    \"braille_dots_13678\": 16787685,\n    \"braille_dots_1368\": 16787621,\n    \"braille_dots_137\": 16787525,\n    \"braille_dots_1378\": 16787653,\n    \"braille_dots_138\": 16787589,\n    \"braille_dots_14\": 16787465,\n    \"braille_dots_145\": 16787481,\n    \"braille_dots_1456\": 16787513,\n    \"braille_dots_14567\": 16787577,\n    \"braille_dots_145678\": 16787705,\n    \"braille_dots_14568\": 16787641,\n    \"braille_dots_1457\": 16787545,\n    \"braille_dots_14578\": 16787673,\n    \"braille_dots_1458\": 16787609,\n    \"braille_dots_146\": 16787497,\n    \"braille_dots_1467\": 16787561,\n    \"braille_dots_14678\": 16787689,\n    \"braille_dots_1468\": 16787625,\n    \"braille_dots_147\": 16787529,\n    \"braille_dots_1478\": 16787657,\n    \"braille_dots_148\": 16787593,\n    \"braille_dots_15\": 16787473,\n    \"braille_dots_156\": 16787505,\n    \"braille_dots_1567\": 16787569,\n    \"braille_dots_15678\": 16787697,\n    \"braille_dots_1568\": 16787633,\n    \"braille_dots_157\": 16787537,\n    \"braille_dots_1578\": 16787665,\n    \"braille_dots_158\": 16787601,\n    \"braille_dots_16\": 16787489,\n    \"braille_dots_167\": 16787553,\n    \"braille_dots_1678\": 16787681,\n    \"braille_dots_168\": 16787617,\n    \"braille_dots_17\": 16787521,\n    \"braille_dots_178\": 16787649,\n    \"braille_dots_18\": 16787585,\n    \"braille_dots_2\": 16787458,\n    \"braille_dots_23\": 16787462,\n    \"braille_dots_234\": 16787470,\n    \"braille_dots_2345\": 16787486,\n    \"braille_dots_23456\": 16787518,\n    \"braille_dots_234567\": 16787582,\n    \"braille_dots_2345678\": 16787710,\n    \"braille_dots_234568\": 16787646,\n    \"braille_dots_23457\": 16787550,\n    \"braille_dots_234578\": 16787678,\n    \"braille_dots_23458\": 16787614,\n    \"braille_dots_2346\": 16787502,\n    \"braille_dots_23467\": 16787566,\n    \"braille_dots_234678\": 16787694,\n    \"braille_dots_23468\": 16787630,\n    \"braille_dots_2347\": 16787534,\n    \"braille_dots_23478\": 16787662,\n    \"braille_dots_2348\": 16787598,\n    \"braille_dots_235\": 16787478,\n    \"braille_dots_2356\": 16787510,\n    \"braille_dots_23567\": 16787574,\n    \"braille_dots_235678\": 16787702,\n    \"braille_dots_23568\": 16787638,\n    \"braille_dots_2357\": 16787542,\n    \"braille_dots_23578\": 16787670,\n    \"braille_dots_2358\": 16787606,\n    \"braille_dots_236\": 16787494,\n    \"braille_dots_2367\": 16787558,\n    \"braille_dots_23678\": 16787686,\n    \"braille_dots_2368\": 16787622,\n    \"braille_dots_237\": 16787526,\n    \"braille_dots_2378\": 16787654,\n    \"braille_dots_238\": 16787590,\n    \"braille_dots_24\": 16787466,\n    \"braille_dots_245\": 16787482,\n    \"braille_dots_2456\": 16787514,\n    \"braille_dots_24567\": 16787578,\n    \"braille_dots_245678\": 16787706,\n    \"braille_dots_24568\": 16787642,\n    \"braille_dots_2457\": 16787546,\n    \"braille_dots_24578\": 16787674,\n    \"braille_dots_2458\": 16787610,\n    \"braille_dots_246\": 16787498,\n    \"braille_dots_2467\": 16787562,\n    \"braille_dots_24678\": 16787690,\n    \"braille_dots_2468\": 16787626,\n    \"braille_dots_247\": 16787530,\n    \"braille_dots_2478\": 16787658,\n    \"braille_dots_248\": 16787594,\n    \"braille_dots_25\": 16787474,\n    \"braille_dots_256\": 16787506,\n    \"braille_dots_2567\": 16787570,\n    \"braille_dots_25678\": 16787698,\n    \"braille_dots_2568\": 16787634,\n    \"braille_dots_257\": 16787538,\n    \"braille_dots_2578\": 16787666,\n    \"braille_dots_258\": 16787602,\n    \"braille_dots_26\": 16787490,\n    \"braille_dots_267\": 16787554,\n    \"braille_dots_2678\": 16787682,\n    \"braille_dots_268\": 16787618,\n    \"braille_dots_27\": 16787522,\n    \"braille_dots_278\": 16787650,\n    \"braille_dots_28\": 16787586,\n    \"braille_dots_3\": 16787460,\n    \"braille_dots_34\": 16787468,\n    \"braille_dots_345\": 16787484,\n    \"braille_dots_3456\": 16787516,\n    \"braille_dots_34567\": 16787580,\n    \"braille_dots_345678\": 16787708,\n    \"braille_dots_34568\": 16787644,\n    \"braille_dots_3457\": 16787548,\n    \"braille_dots_34578\": 16787676,\n    \"braille_dots_3458\": 16787612,\n    \"braille_dots_346\": 16787500,\n    \"braille_dots_3467\": 16787564,\n    \"braille_dots_34678\": 16787692,\n    \"braille_dots_3468\": 16787628,\n    \"braille_dots_347\": 16787532,\n    \"braille_dots_3478\": 16787660,\n    \"braille_dots_348\": 16787596,\n    \"braille_dots_35\": 16787476,\n    \"braille_dots_356\": 16787508,\n    \"braille_dots_3567\": 16787572,\n    \"braille_dots_35678\": 16787700,\n    \"braille_dots_3568\": 16787636,\n    \"braille_dots_357\": 16787540,\n    \"braille_dots_3578\": 16787668,\n    \"braille_dots_358\": 16787604,\n    \"braille_dots_36\": 16787492,\n    \"braille_dots_367\": 16787556,\n    \"braille_dots_3678\": 16787684,\n    \"braille_dots_368\": 16787620,\n    \"braille_dots_37\": 16787524,\n    \"braille_dots_378\": 16787652,\n    \"braille_dots_38\": 16787588,\n    \"braille_dots_4\": 16787464,\n    \"braille_dots_45\": 16787480,\n    \"braille_dots_456\": 16787512,\n    \"braille_dots_4567\": 16787576,\n    \"braille_dots_45678\": 16787704,\n    \"braille_dots_4568\": 16787640,\n    \"braille_dots_457\": 16787544,\n    \"braille_dots_4578\": 16787672,\n    \"braille_dots_458\": 16787608,\n    \"braille_dots_46\": 16787496,\n    \"braille_dots_467\": 16787560,\n    \"braille_dots_4678\": 16787688,\n    \"braille_dots_468\": 16787624,\n    \"braille_dots_47\": 16787528,\n    \"braille_dots_478\": 16787656,\n    \"braille_dots_48\": 16787592,\n    \"braille_dots_5\": 16787472,\n    \"braille_dots_56\": 16787504,\n    \"braille_dots_567\": 16787568,\n    \"braille_dots_5678\": 16787696,\n    \"braille_dots_568\": 16787632,\n    \"braille_dots_57\": 16787536,\n    \"braille_dots_578\": 16787664,\n    \"braille_dots_58\": 16787600,\n    \"braille_dots_6\": 16787488,\n    \"braille_dots_67\": 16787552,\n    \"braille_dots_678\": 16787680,\n    \"braille_dots_68\": 16787616,\n    \"braille_dots_7\": 16787520,\n    \"braille_dots_78\": 16787648,\n    \"braille_dots_8\": 16787584,\n    \"breve\": 418,\n    \"brokenbar\": 166,\n    \"c\": 99,\n    \"c_h\": 65187,\n    \"cabovedot\": 741,\n    \"cacute\": 486,\n    \"careof\": 2744,\n    \"caret\": 2812,\n    \"caron\": 439,\n    \"ccaron\": 488,\n    \"ccedilla\": 231,\n    \"ccircumflex\": 742,\n    \"cedilla\": 184,\n    \"cent\": 162,\n    \"ch\": 65184,\n    \"checkerboard\": 2529,\n    \"checkmark\": 2803,\n    \"circle\": 3023,\n    \"club\": 2796,\n    \"colon\": 58,\n    \"combining_acute\": 16777985,\n    \"combining_belowdot\": 16778019,\n    \"combining_grave\": 16777984,\n    \"combining_hook\": 16777993,\n    \"combining_tilde\": 16777987,\n    \"comma\": 44,\n    \"containsas\": 16785931,\n    \"copyright\": 169,\n    \"cr\": 2532,\n    \"crossinglines\": 2542,\n    \"cuberoot\": 16785947,\n    \"currency\": 164,\n    \"cursor\": 2815,\n    \"d\": 100,\n    \"dabovedot\": 16784907,\n    \"dagger\": 2801,\n    \"dcaron\": 495,\n    \"dead_A\": 65153,\n    \"dead_E\": 65155,\n    \"dead_I\": 65157,\n    \"dead_O\": 65159,\n    \"dead_SCHWA\": 65163,\n    \"dead_U\": 65161,\n    \"dead_a\": 65152,\n    \"dead_abovecomma\": 65124,\n    \"dead_abovedot\": 65110,\n    \"dead_abovereversedcomma\": 65125,\n    \"dead_abovering\": 65112,\n    \"dead_acute\": 65105,\n    \"dead_belowbreve\": 65131,\n    \"dead_belowcircumflex\": 65129,\n    \"dead_belowcomma\": 65134,\n    \"dead_belowdiaeresis\": 65132,\n    \"dead_belowdot\": 65120,\n    \"dead_belowmacron\": 65128,\n    \"dead_belowring\": 65127,\n    \"dead_belowtilde\": 65130,\n    \"dead_breve\": 65109,\n    \"dead_capital_schwa\": 65163,\n    \"dead_caron\": 65114,\n    \"dead_cedilla\": 65115,\n    \"dead_circumflex\": 65106,\n    \"dead_currency\": 65135,\n    \"dead_dasia\": 65125,\n    \"dead_diaeresis\": 65111,\n    \"dead_doubleacute\": 65113,\n    \"dead_doublegrave\": 65126,\n    \"dead_e\": 65154,\n    \"dead_grave\": 65104,\n    \"dead_greek\": 65164,\n    \"dead_hamza\": 65165,\n    \"dead_hook\": 65121,\n    \"dead_horn\": 65122,\n    \"dead_i\": 65156,\n    \"dead_invertedbreve\": 65133,\n    \"dead_iota\": 65117,\n    \"dead_macron\": 65108,\n    \"dead_o\": 65158,\n    \"dead_ogonek\": 65116,\n    \"dead_perispomeni\": 65107,\n    \"dead_psili\": 65124,\n    \"dead_schwa\": 65162,\n    \"dead_semivoiced_sound\": 65119,\n    \"dead_small_schwa\": 65162,\n    \"dead_stroke\": 65123,\n    \"dead_tilde\": 65107,\n    \"dead_u\": 65160,\n    \"dead_voiced_sound\": 65118,\n    \"decimalpoint\": 2749,\n    \"degree\": 176,\n    \"diaeresis\": 168,\n    \"diamond\": 2797,\n    \"digitspace\": 2725,\n    \"dintegral\": 16785964,\n    \"division\": 247,\n    \"dollar\": 36,\n    \"doubbaselinedot\": 2735,\n    \"doubleacute\": 445,\n    \"doubledagger\": 2802,\n    \"doublelowquotemark\": 2814,\n    \"downarrow\": 2302,\n    \"downcaret\": 2984,\n    \"downshoe\": 3030,\n    \"downstile\": 3012,\n    \"downtack\": 3010,\n    \"dstroke\": 496,\n    \"e\": 101,\n    \"eabovedot\": 1004,\n    \"eacute\": 233,\n    \"ebelowdot\": 16785081,\n    \"ecaron\": 492,\n    \"ecircumflex\": 234,\n    \"ecircumflexacute\": 16785087,\n    \"ecircumflexbelowdot\": 16785095,\n    \"ecircumflexgrave\": 16785089,\n    \"ecircumflexhook\": 16785091,\n    \"ecircumflextilde\": 16785093,\n    \"ediaeresis\": 235,\n    \"egrave\": 232,\n    \"ehook\": 16785083,\n    \"eightsubscript\": 16785544,\n    \"eightsuperior\": 16785528,\n    \"elementof\": 16785928,\n    \"ellipsis\": 2734,\n    \"em3space\": 2723,\n    \"em4space\": 2724,\n    \"emacron\": 954,\n    \"emdash\": 2729,\n    \"emfilledcircle\": 2782,\n    \"emfilledrect\": 2783,\n    \"emopencircle\": 2766,\n    \"emopenrectangle\": 2767,\n    \"emptyset\": 16785925,\n    \"emspace\": 2721,\n    \"endash\": 2730,\n    \"enfilledcircbullet\": 2790,\n    \"enfilledsqbullet\": 2791,\n    \"eng\": 959,\n    \"enopencircbullet\": 2784,\n    \"enopensquarebullet\": 2785,\n    \"enspace\": 2722,\n    \"eogonek\": 490,\n    \"equal\": 61,\n    \"eth\": 240,\n    \"etilde\": 16785085,\n    \"exclam\": 33,\n    \"exclamdown\": 161,\n    \"ezh\": 16777874,\n    \"f\": 102,\n    \"fabovedot\": 16784927,\n    \"femalesymbol\": 2808,\n    \"ff\": 2531,\n    \"figdash\": 2747,\n    \"filledlefttribullet\": 2780,\n    \"filledrectbullet\": 2779,\n    \"filledrighttribullet\": 2781,\n    \"filledtribulletdown\": 2793,\n    \"filledtribulletup\": 2792,\n    \"fiveeighths\": 2757,\n    \"fivesixths\": 2743,\n    \"fivesubscript\": 16785541,\n    \"fivesuperior\": 16785525,\n    \"fourfifths\": 2741,\n    \"foursubscript\": 16785540,\n    \"foursuperior\": 16785524,\n    \"fourthroot\": 16785948,\n    \"function\": 2294,\n    \"g\": 103,\n    \"gabovedot\": 757,\n    \"gbreve\": 699,\n    \"gcaron\": 16777703,\n    \"gcedilla\": 955,\n    \"gcircumflex\": 760,\n    \"grave\": 96,\n    \"greater\": 62,\n    \"greaterthanequal\": 2238,\n    \"guillemetleft\": 171,\n    \"guillemetright\": 187,\n    \"guillemotleft\": 171,\n    \"guillemotright\": 187,\n    \"h\": 104,\n    \"hairspace\": 2728,\n    \"hcircumflex\": 694,\n    \"heart\": 2798,\n    \"hebrew_aleph\": 3296,\n    \"hebrew_ayin\": 3314,\n    \"hebrew_bet\": 3297,\n    \"hebrew_beth\": 3297,\n    \"hebrew_chet\": 3303,\n    \"hebrew_dalet\": 3299,\n    \"hebrew_daleth\": 3299,\n    \"hebrew_doublelowline\": 3295,\n    \"hebrew_finalkaph\": 3306,\n    \"hebrew_finalmem\": 3309,\n    \"hebrew_finalnun\": 3311,\n    \"hebrew_finalpe\": 3315,\n    \"hebrew_finalzade\": 3317,\n    \"hebrew_finalzadi\": 3317,\n    \"hebrew_gimel\": 3298,\n    \"hebrew_gimmel\": 3298,\n    \"hebrew_he\": 3300,\n    \"hebrew_het\": 3303,\n    \"hebrew_kaph\": 3307,\n    \"hebrew_kuf\": 3319,\n    \"hebrew_lamed\": 3308,\n    \"hebrew_mem\": 3310,\n    \"hebrew_nun\": 3312,\n    \"hebrew_pe\": 3316,\n    \"hebrew_qoph\": 3319,\n    \"hebrew_resh\": 3320,\n    \"hebrew_samech\": 3313,\n    \"hebrew_samekh\": 3313,\n    \"hebrew_shin\": 3321,\n    \"hebrew_taf\": 3322,\n    \"hebrew_taw\": 3322,\n    \"hebrew_tet\": 3304,\n    \"hebrew_teth\": 3304,\n    \"hebrew_waw\": 3301,\n    \"hebrew_yod\": 3305,\n    \"hebrew_zade\": 3318,\n    \"hebrew_zadi\": 3318,\n    \"hebrew_zain\": 3302,\n    \"hebrew_zayin\": 3302,\n    \"hexagram\": 2778,\n    \"horizconnector\": 2211,\n    \"horizlinescan1\": 2543,\n    \"horizlinescan3\": 2544,\n    \"horizlinescan5\": 2545,\n    \"horizlinescan7\": 2546,\n    \"horizlinescan9\": 2547,\n    \"hstroke\": 689,\n    \"ht\": 2530,\n    \"hyphen\": 173,\n    \"i\": 105,\n    \"iacute\": 237,\n    \"ibelowdot\": 16785099,\n    \"ibreve\": 16777517,\n    \"icircumflex\": 238,\n    \"identical\": 2255,\n    \"idiaeresis\": 239,\n    \"idotless\": 697,\n    \"ifonlyif\": 2253,\n    \"igrave\": 236,\n    \"ihook\": 16785097,\n    \"imacron\": 1007,\n    \"implies\": 2254,\n    \"includedin\": 2266,\n    \"includes\": 2267,\n    \"infinity\": 2242,\n    \"integral\": 2239,\n    \"intersection\": 2268,\n    \"iogonek\": 999,\n    \"itilde\": 949,\n    \"j\": 106,\n    \"jcircumflex\": 700,\n    \"jot\": 3018,\n    \"k\": 107,\n    \"kana_A\": 1201,\n    \"kana_CHI\": 1217,\n    \"kana_E\": 1204,\n    \"kana_FU\": 1228,\n    \"kana_HA\": 1226,\n    \"kana_HE\": 1229,\n    \"kana_HI\": 1227,\n    \"kana_HO\": 1230,\n    \"kana_HU\": 1228,\n    \"kana_I\": 1202,\n    \"kana_KA\": 1206,\n    \"kana_KE\": 1209,\n    \"kana_KI\": 1207,\n    \"kana_KO\": 1210,\n    \"kana_KU\": 1208,\n    \"kana_MA\": 1231,\n    \"kana_ME\": 1234,\n    \"kana_MI\": 1232,\n    \"kana_MO\": 1235,\n    \"kana_MU\": 1233,\n    \"kana_N\": 1245,\n    \"kana_NA\": 1221,\n    \"kana_NE\": 1224,\n    \"kana_NI\": 1222,\n    \"kana_NO\": 1225,\n    \"kana_NU\": 1223,\n    \"kana_O\": 1205,\n    \"kana_RA\": 1239,\n    \"kana_RE\": 1242,\n    \"kana_RI\": 1240,\n    \"kana_RO\": 1243,\n    \"kana_RU\": 1241,\n    \"kana_SA\": 1211,\n    \"kana_SE\": 1214,\n    \"kana_SHI\": 1212,\n    \"kana_SO\": 1215,\n    \"kana_SU\": 1213,\n    \"kana_TA\": 1216,\n    \"kana_TE\": 1219,\n    \"kana_TI\": 1217,\n    \"kana_TO\": 1220,\n    \"kana_TSU\": 1218,\n    \"kana_TU\": 1218,\n    \"kana_U\": 1203,\n    \"kana_WA\": 1244,\n    \"kana_WO\": 1190,\n    \"kana_YA\": 1236,\n    \"kana_YO\": 1238,\n    \"kana_YU\": 1237,\n    \"kana_a\": 1191,\n    \"kana_closingbracket\": 1187,\n    \"kana_comma\": 1188,\n    \"kana_conjunctive\": 1189,\n    \"kana_e\": 1194,\n    \"kana_fullstop\": 1185,\n    \"kana_i\": 1192,\n    \"kana_middledot\": 1189,\n    \"kana_o\": 1195,\n    \"kana_openingbracket\": 1186,\n    \"kana_switch\": 65406,\n    \"kana_tsu\": 1199,\n    \"kana_tu\": 1199,\n    \"kana_u\": 1193,\n    \"kana_ya\": 1196,\n    \"kana_yo\": 1198,\n    \"kana_yu\": 1197,\n    \"kappa\": 930,\n    \"kcedilla\": 1011,\n    \"kra\": 930,\n    \"l\": 108,\n    \"lacute\": 485,\n    \"latincross\": 2777,\n    \"lbelowdot\": 16784951,\n    \"lcaron\": 437,\n    \"lcedilla\": 950,\n    \"leftanglebracket\": 2748,\n    \"leftarrow\": 2299,\n    \"leftcaret\": 2979,\n    \"leftdoublequotemark\": 2770,\n    \"leftmiddlecurlybrace\": 2223,\n    \"leftopentriangle\": 2764,\n    \"leftpointer\": 2794,\n    \"leftradical\": 2209,\n    \"leftshoe\": 3034,\n    \"leftsinglequotemark\": 2768,\n    \"leftt\": 2548,\n    \"lefttack\": 3036,\n    \"less\": 60,\n    \"lessthanequal\": 2236,\n    \"lf\": 2533,\n    \"logicaland\": 2270,\n    \"logicalor\": 2271,\n    \"lowleftcorner\": 2541,\n    \"lowrightcorner\": 2538,\n    \"lstroke\": 435,\n    \"m\": 109,\n    \"mabovedot\": 16784961,\n    \"macron\": 175,\n    \"malesymbol\": 2807,\n    \"maltesecross\": 2800,\n    \"marker\": 2751,\n    \"masculine\": 186,\n    \"minus\": 45,\n    \"minutes\": 2774,\n    \"mu\": 181,\n    \"multiply\": 215,\n    \"musicalflat\": 2806,\n    \"musicalsharp\": 2805,\n    \"n\": 110,\n    \"nabla\": 2245,\n    \"nacute\": 497,\n    \"ncaron\": 498,\n    \"ncedilla\": 1009,\n    \"ninesubscript\": 16785545,\n    \"ninesuperior\": 16785529,\n    \"nl\": 2536,\n    \"nobreakspace\": 160,\n    \"notapproxeq\": 16785991,\n    \"notelementof\": 16785929,\n    \"notequal\": 2237,\n    \"notidentical\": 16786018,\n    \"notsign\": 172,\n    \"ntilde\": 241,\n    \"numbersign\": 35,\n    \"numerosign\": 1712,\n    \"o\": 111,\n    \"oacute\": 243,\n    \"obarred\": 16777845,\n    \"obelowdot\": 16785101,\n    \"ocaron\": 16777682,\n    \"ocircumflex\": 244,\n    \"ocircumflexacute\": 16785105,\n    \"ocircumflexbelowdot\": 16785113,\n    \"ocircumflexgrave\": 16785107,\n    \"ocircumflexhook\": 16785109,\n    \"ocircumflextilde\": 16785111,\n    \"odiaeresis\": 246,\n    \"odoubleacute\": 501,\n    \"oe\": 5053,\n    \"ogonek\": 434,\n    \"ograve\": 242,\n    \"ohook\": 16785103,\n    \"ohorn\": 16777633,\n    \"ohornacute\": 16785115,\n    \"ohornbelowdot\": 16785123,\n    \"ohorngrave\": 16785117,\n    \"ohornhook\": 16785119,\n    \"ohorntilde\": 16785121,\n    \"omacron\": 1010,\n    \"oneeighth\": 2755,\n    \"onefifth\": 2738,\n    \"onehalf\": 189,\n    \"onequarter\": 188,\n    \"onesixth\": 2742,\n    \"onesubscript\": 16785537,\n    \"onesuperior\": 185,\n    \"onethird\": 2736,\n    \"ooblique\": 248,\n    \"openrectbullet\": 2786,\n    \"openstar\": 2789,\n    \"opentribulletdown\": 2788,\n    \"opentribulletup\": 2787,\n    \"ordfeminine\": 170,\n    \"ordmasculine\": 186,\n    \"oslash\": 248,\n    \"otilde\": 245,\n    \"overbar\": 3008,\n    \"overline\": 1150,\n    \"p\": 112,\n    \"pabovedot\": 16784983,\n    \"paragraph\": 182,\n    \"parenleft\": 40,\n    \"parenright\": 41,\n    \"partdifferential\": 16785922,\n    \"partialderivative\": 2287,\n    \"percent\": 37,\n    \"period\": 46,\n    \"periodcentered\": 183,\n    \"permille\": 2773,\n    \"phonographcopyright\": 2811,\n    \"plus\": 43,\n    \"plusminus\": 177,\n    \"prescription\": 2772,\n    \"prolongedsound\": 1200,\n    \"punctspace\": 2726,\n    \"q\": 113,\n    \"quad\": 3020,\n    \"question\": 63,\n    \"questiondown\": 191,\n    \"quotedbl\": 34,\n    \"quoteleft\": 96,\n    \"quoteright\": 39,\n    \"r\": 114,\n    \"racute\": 480,\n    \"radical\": 2262,\n    \"rcaron\": 504,\n    \"rcedilla\": 947,\n    \"registered\": 174,\n    \"rightanglebracket\": 2750,\n    \"rightarrow\": 2301,\n    \"rightcaret\": 2982,\n    \"rightdoublequotemark\": 2771,\n    \"rightmiddlecurlybrace\": 2224,\n    \"rightmiddlesummation\": 2231,\n    \"rightopentriangle\": 2765,\n    \"rightpointer\": 2795,\n    \"rightshoe\": 3032,\n    \"rightsinglequotemark\": 2769,\n    \"rightt\": 2549,\n    \"righttack\": 3068,\n    \"s\": 115,\n    \"sabovedot\": 16784993,\n    \"sacute\": 438,\n    \"scaron\": 441,\n    \"scedilla\": 442,\n    \"schwa\": 16777817,\n    \"scircumflex\": 766,\n    \"script_switch\": 65406,\n    \"seconds\": 2775,\n    \"section\": 167,\n    \"semicolon\": 59,\n    \"semivoicedsound\": 1247,\n    \"seveneighths\": 2758,\n    \"sevensubscript\": 16785543,\n    \"sevensuperior\": 16785527,\n    \"signaturemark\": 2762,\n    \"signifblank\": 2732,\n    \"similarequal\": 2249,\n    \"singlelowquotemark\": 2813,\n    \"sixsubscript\": 16785542,\n    \"sixsuperior\": 16785526,\n    \"slash\": 47,\n    \"soliddiamond\": 2528,\n    \"space\": 32,\n    \"squareroot\": 16785946,\n    \"ssharp\": 223,\n    \"sterling\": 163,\n    \"stricteq\": 16786019,\n    \"t\": 116,\n    \"tabovedot\": 16785003,\n    \"tcaron\": 443,\n    \"tcedilla\": 510,\n    \"telephone\": 2809,\n    \"telephonerecorder\": 2810,\n    \"therefore\": 2240,\n    \"thinspace\": 2727,\n    \"thorn\": 254,\n    \"threeeighths\": 2756,\n    \"threefifths\": 2740,\n    \"threequarters\": 190,\n    \"threesubscript\": 16785539,\n    \"threesuperior\": 179,\n    \"tintegral\": 16785965,\n    \"topintegral\": 2212,\n    \"topleftparens\": 2219,\n    \"topleftradical\": 2210,\n    \"topleftsqbracket\": 2215,\n    \"topleftsummation\": 2225,\n    \"toprightparens\": 2221,\n    \"toprightsqbracket\": 2217,\n    \"toprightsummation\": 2229,\n    \"topt\": 2551,\n    \"topvertsummationconnector\": 2227,\n    \"trademark\": 2761,\n    \"trademarkincircle\": 2763,\n    \"tslash\": 956,\n    \"twofifths\": 2739,\n    \"twosubscript\": 16785538,\n    \"twosuperior\": 178,\n    \"twothirds\": 2737,\n    \"u\": 117,\n    \"uacute\": 250,\n    \"ubelowdot\": 16785125,\n    \"ubreve\": 765,\n    \"ucircumflex\": 251,\n    \"udiaeresis\": 252,\n    \"udoubleacute\": 507,\n    \"ugrave\": 249,\n    \"uhook\": 16785127,\n    \"uhorn\": 16777648,\n    \"uhornacute\": 16785129,\n    \"uhornbelowdot\": 16785137,\n    \"uhorngrave\": 16785131,\n    \"uhornhook\": 16785133,\n    \"uhorntilde\": 16785135,\n    \"umacron\": 1022,\n    \"underbar\": 3014,\n    \"underscore\": 95,\n    \"union\": 2269,\n    \"uogonek\": 1017,\n    \"uparrow\": 2300,\n    \"upcaret\": 2985,\n    \"upleftcorner\": 2540,\n    \"uprightcorner\": 2539,\n    \"upshoe\": 3011,\n    \"upstile\": 3027,\n    \"uptack\": 3022,\n    \"uring\": 505,\n    \"utilde\": 1021,\n    \"v\": 118,\n    \"variation\": 2241,\n    \"vertbar\": 2552,\n    \"vertconnector\": 2214,\n    \"voicedsound\": 1246,\n    \"vt\": 2537,\n    \"w\": 119,\n    \"wacute\": 16785027,\n    \"wcircumflex\": 16777589,\n    \"wdiaeresis\": 16785029,\n    \"wgrave\": 16785025,\n    \"x\": 120,\n    \"xabovedot\": 16785035,\n    \"y\": 121,\n    \"yacute\": 253,\n    \"ybelowdot\": 16785141,\n    \"ycircumflex\": 16777591,\n    \"ydiaeresis\": 255,\n    \"yen\": 165,\n    \"ygrave\": 16785139,\n    \"yhook\": 16785143,\n    \"ytilde\": 16785145,\n    \"z\": 122,\n    \"zabovedot\": 447,\n    \"zacute\": 444,\n    \"zcaron\": 446,\n    \"zerosubscript\": 16785536,\n    \"zerosuperior\": 16785520,\n    \"zstroke\": 16777654,\n}\n"
  },
  {
    "path": "lib/logitech_receiver/__init__.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\"\"\"Low-level interface for devices using Logitech HID++ protocol.\n\nUses the HID api exposed through hidapi_impl.py, a Python thin layer over a native\nimplementation.\n\"\"\"\n\nimport logging\n\nlogger = logging.getLogger(__name__)\n"
  },
  {
    "path": "lib/logitech_receiver/base.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n\"\"\"Base low-level functions as API for upper layers.\"\"\"\n\nfrom __future__ import annotations\n\nimport dataclasses\nimport logging\nimport platform\nimport struct\nimport threading\nimport typing\n\nfrom contextlib import contextmanager\nfrom random import getrandbits\nfrom time import time\nfrom typing import Any\nfrom typing import Callable\n\nfrom . import base_usb\nfrom . import common\nfrom . import descriptors\nfrom . import exceptions\nfrom .common import LOGITECH_VENDOR_ID\nfrom .common import BusID\nfrom .hidpp10_constants import ErrorCode as Hidpp10ErrorCode\nfrom .hidpp20_constants import ErrorCode as Hidpp20ErrorCode\n\nif typing.TYPE_CHECKING:\n    import gi\n\n    from hidapi.common import DeviceInfo\n\n    gi.require_version(\"Gdk\", \"3.0\")\n    from gi.repository import GLib  # NOQA: E402\n\nif platform.system() == \"Linux\":\n    import hidapi.udev_impl as hidapi\nelse:\n    import hidapi.hidapi_impl as hidapi\n\nlogger = logging.getLogger(__name__)\n\n\nclass HIDProtocol(typing.Protocol):\n    def find_paired_node_wpid(self, receiver_path: str, index: int):\n        ...\n\n    def find_paired_node(self, receiver_path: str, index: int, timeout: int):\n        ...\n\n    def open(self, vendor_id, product_id, serial=None):\n        ...\n\n    def open_path(self, path) -> int:\n        ...\n\n    def enumerate(self, filter_func: Callable[[int, int, int, bool, bool], dict[str, typing.Any]]) -> DeviceInfo:\n        ...\n\n    def monitor_glib(\n        self, glib: GLib, callback: Callable, filter_func: Callable[[int, int, int, bool, bool], dict[str, typing.Any]]\n    ) -> None:\n        ...\n\n    def read(self, device_handle, bytes_count, timeout_ms):\n        ...\n\n    def write(self, device_handle: int, data: bytes) -> int:\n        ...\n\n    def close(self, device_handle) -> None:\n        ...\n\n\nSHORT_MESSAGE_SIZE = 7\n_LONG_MESSAGE_SIZE = 20\n_MEDIUM_MESSAGE_SIZE = 15\n_MAX_READ_SIZE = 32\n\nHIDPP_SHORT_MESSAGE_ID = 0x10\nHIDPP_LONG_MESSAGE_ID = 0x11\nDJ_MESSAGE_ID = 0x20\n\n\n\"\"\"Default timeout on read (in seconds).\"\"\"\nDEFAULT_TIMEOUT = 4\n# the receiver itself should reply very fast, within 500ms\n_RECEIVER_REQUEST_TIMEOUT = 0.9\n# devices may reply a lot slower, as the call has to go wireless to them and come back\n_DEVICE_REQUEST_TIMEOUT = DEFAULT_TIMEOUT\n# when pinging, be extra patient (no longer)\n_PING_TIMEOUT = DEFAULT_TIMEOUT\n\nhidapi = typing.cast(HIDProtocol, hidapi)\n\nrequest_lock = threading.Lock()  # serialize all requests\nhandles_lock = {}\n\n\n@dataclasses.dataclass\nclass HIDPPNotification:\n    report_id: int\n    devnumber: int\n    sub_id: int\n    address: int\n    data: bytes\n\n    def __str__(self):\n        text_as_hex = common.strhex(self.data)\n        return f\"Notification({self.report_id:02x},{self.devnumber},{self.sub_id:02X},{self.address:02X},{text_as_hex})\"\n\n\ndef _usb_device(product_id: int, usb_interface: int) -> dict[str, Any]:\n    return {\n        \"vendor_id\": LOGITECH_VENDOR_ID,\n        \"product_id\": product_id,\n        \"bus_id\": BusID.USB,\n        \"usb_interface\": usb_interface,\n        \"isDevice\": True,\n    }\n\n\ndef _bluetooth_device(product_id: int) -> dict[str, Any]:\n    return {\"vendor_id\": LOGITECH_VENDOR_ID, \"product_id\": product_id, \"bus_id\": BusID.BLUETOOTH, \"isDevice\": True}\n\n\nKNOWN_DEVICE_IDS = []\n\nfor _ignore, d in descriptors.DEVICES.items():\n    if d.usbid:\n        usb_interface = d.interface if d.interface else 2\n        KNOWN_DEVICE_IDS.append(_usb_device(d.usbid, usb_interface))\n    if d.btid:\n        KNOWN_DEVICE_IDS.append(_bluetooth_device(d.btid))\n\n\ndef product_information(usb_id: int) -> dict[str, Any]:\n    \"\"\"Returns hardcoded information from USB receiver.\"\"\"\n    return base_usb.get_receiver_info(usb_id)\n\n\ndef receivers():\n    \"\"\"Enumerate all the receivers attached to the machine.\"\"\"\n    yield from hidapi.enumerate(get_known_receiver_info)\n\n\ndef filter_products_of_interest(\n    bus_id: int, vendor_id: int, product_id: int, hidpp_short: bool = False, hidpp_long: bool = False\n) -> dict[str, Any] | None:\n    \"\"\"Check that this product is of interest and if so return the device record for further checking\"\"\"\n\n    recv = get_known_receiver_info(bus_id, vendor_id, product_id, hidpp_short, hidpp_long)\n    if recv:  # known or unknown receiver\n        return recv\n\n    device = get_known_device_info(bus_id, vendor_id, product_id)\n    if device:\n        return device\n\n    if hidpp_short or hidpp_long:\n        return get_unknown_hid_device_info(bus_id, vendor_id, product_id)\n\n    if hidpp_short is None and hidpp_long is None:\n        return get_unknown_logitech_device_info(bus_id, vendor_id, product_id)\n    return None\n\n\ndef get_known_device_info(bus_id: int, vendor_id: int, product_id: int) -> dict[str, Any]:\n    for recv in KNOWN_DEVICE_IDS:\n        if _match_device(recv, bus_id, vendor_id, product_id):\n            return recv\n\n\ndef get_unknown_hid_device_info(bus_id: int, vendor_id: int, product_id: int) -> dict[str, Any]:\n    return {\"vendor_id\": vendor_id, \"product_id\": product_id, \"bus_id\": bus_id, \"isDevice\": True}\n\n\ndef get_unknown_logitech_device_info(bus_id: int, vendor_id: int, product_id: int) -> dict[str, Any] | None:\n    \"\"\"Get info from unknown device in Logitech product range.\n\n    Check whether product is a Logitech USB-connected or Bluetooth\n    device based on bus, vendor, and product ID. This allows Solaar to\n    support receiverless HID++ 2.0 devices that it knows nothing about.\n    \"\"\"\n    if vendor_id != LOGITECH_VENDOR_ID:\n        return None\n\n    if bus_id == BusID.USB.value and (0xC07D <= product_id <= 0xC094 or 0xC32B <= product_id <= 0xC344):\n        device_info = _usb_device(product_id, 2)\n        return device_info\n    elif bus_id == BusID.BLUETOOTH.value and (0xB012 <= product_id <= 0xB0FF or 0xB317 <= product_id <= 0xB3FF):\n        device_info = _bluetooth_device(product_id)\n        return device_info\n\n    return None\n\n\ndef _match_device(record: dict[str, Any], bus_id: int, vendor_id: int, product_id: int):\n    return (\n        (record.get(\"bus_id\") is None or record.get(\"bus_id\") == bus_id)\n        and (record.get(\"vendor_id\") is None or record.get(\"vendor_id\") == vendor_id)\n        and (record.get(\"product_id\") is None or record.get(\"product_id\") == product_id)\n    )\n\n\ndef get_known_receiver_info(\n    bus_id: int, vendor_id: int, product_id: int, _hidpp_short: bool = False, _hidpp_long: bool = False\n) -> dict[str, Any]:\n    \"\"\"Check that this product is a Logitech receiver and return it.\n\n    Filters based on bus_id, vendor_id and product_id.\n\n    If so return the receiver record for further checking.\n    \"\"\"\n    try:\n        record = base_usb.get_receiver_info(product_id)\n        if _match_device(record, bus_id, vendor_id, product_id):\n            return record\n    except ValueError:\n        pass\n\n    if vendor_id == LOGITECH_VENDOR_ID and 0xC500 <= product_id <= 0xC5FF:  # unknown receiver\n        return {\"vendor_id\": vendor_id, \"product_id\": product_id, \"bus_id\": bus_id, \"isDevice\": False}\n    return None\n\n\ndef receivers_and_devices():\n    \"\"\"Enumerate all the receivers and devices directly attached to the machine.\"\"\"\n    yield from hidapi.enumerate(filter_products_of_interest)\n\n\ndef notify_on_receivers_glib(glib: GLib, callback: Callable):\n    \"\"\"Watch for matching devices and notifies the callback on the GLib thread.\n\n    Parameters\n    ----------\n    glib\n        GLib instance.\n    \"\"\"\n    return hidapi.monitor_glib(glib, callback, filter_products_of_interest)\n\n\ndef open_path(path) -> int:\n    \"\"\"Checks if the given Linux device path points to the right UR device.\n\n    :param path: the Linux device path.\n\n    The UR physical device may expose multiple linux devices with the same\n    interface, so we have to check for the right one. At this moment the only\n    way to distinguish betheen them is to do a test ping on an invalid\n    (attached) device number (i.e., 0), expecting a 'ping failed' reply.\n\n    :returns: an open receiver handle if this is the right Linux device, or\n    ``None``.\n    \"\"\"\n    return hidapi.open_path(path)\n\n\ndef open():\n    \"\"\"Opens the first Logitech Unifying Receiver found attached to the machine.\n\n    :returns: An open file handle for the found receiver, or ``None``.\n    \"\"\"\n    for rawdevice in receivers():\n        handle = open_path(rawdevice.path)\n        if handle:\n            return handle\n\n\ndef close(handle):\n    \"\"\"Closes a HID device handle.\"\"\"\n    if handle:\n        try:\n            if isinstance(handle, int):\n                hidapi.close(handle)\n            else:\n                handle.close()\n            return True\n        except Exception:\n            pass\n\n    return False\n\n\ndef write(handle, devnumber, data, long_message=False):\n    \"\"\"Writes some data to the receiver, addressed to a certain device.\n\n    :param handle: an open UR handle.\n    :param devnumber: attached device number.\n    :param data: data to send, up to 5 bytes.\n\n    The first two (required) bytes of data must be the SubId and address.\n\n    :raises NoReceiver: if the receiver is no longer available, i.e. has\n    been physically removed from the machine, or the kernel driver has been\n    unloaded. The handle will be closed automatically.\n    \"\"\"\n    # the data is padded to either 5 or 18 bytes\n    assert data is not None\n    assert isinstance(data, bytes), (repr(data), type(data))\n\n    if long_message or len(data) > SHORT_MESSAGE_SIZE - 2 or data[:1] == b\"\\x82\":\n        wdata = struct.pack(\"!BB18s\", HIDPP_LONG_MESSAGE_ID, devnumber, data)\n    else:\n        wdata = struct.pack(\"!BB5s\", HIDPP_SHORT_MESSAGE_ID, devnumber, data)\n    if logger.isEnabledFor(logging.DEBUG):\n        logger.debug(\n            \"(%s) <= w[%02X %02X %s %s]\",\n            handle,\n            ord(wdata[:1]),\n            devnumber,\n            common.strhex(wdata[2:4]),\n            common.strhex(wdata[4:]),\n        )\n\n    try:\n        hidapi.write(int(handle), wdata)\n    except Exception as reason:\n        logger.error(\"write failed, assuming handle %r no longer available\", handle)\n        close(handle)\n        raise exceptions.NoReceiver(reason=reason) from reason\n\n\ndef read(handle, timeout=DEFAULT_TIMEOUT):\n    \"\"\"Read some data from the receiver. Usually called after a write (feature\n    call), to get the reply.\n\n    :param: handle open handle to the receiver\n    :param: timeout how long to wait for a reply, in seconds\n\n    :returns: a tuple of (devnumber, message data), or `None`\n\n    :raises NoReceiver: if the receiver is no longer available, i.e. has\n    been physically removed from the machine, or the kernel driver has been\n    unloaded. The handle will be closed automatically.\n    \"\"\"\n    reply = _read(handle, timeout)\n    if reply:\n        return reply\n\n\ndef _is_relevant_message(data: bytes) -> bool:\n    \"\"\"Checks if given id is a HID++ or DJ message.\n\n    Applies sanity checks on message report ID and message size.\n    \"\"\"\n    assert isinstance(data, bytes), (repr(data), type(data))\n\n    # mapping from report_id to message length\n    report_lengths = {\n        HIDPP_SHORT_MESSAGE_ID: SHORT_MESSAGE_SIZE,\n        HIDPP_LONG_MESSAGE_ID: _LONG_MESSAGE_SIZE,\n        DJ_MESSAGE_ID: _MEDIUM_MESSAGE_SIZE,\n        0x21: _MAX_READ_SIZE,\n    }\n\n    report_id = ord(data[:1])\n    if report_id in report_lengths:\n        if report_lengths.get(report_id) == len(data):\n            return True\n        else:\n            logger.warning(f\"unexpected message size: report_id {report_id:02X} message {common.strhex(data)}\")\n    return False\n\n\ndef _read(handle, timeout) -> tuple[int, int, bytes]:\n    \"\"\"Read an incoming packet from the receiver.\n\n    :returns: a tuple of (report_id, devnumber, data), or `None`.\n\n    :raises NoReceiver: if the receiver is no longer available, i.e. has\n    been physically removed from the machine, or the kernel driver has been\n    unloaded. The handle will be closed automatically.\n    \"\"\"\n    try:\n        # convert timeout to milliseconds, the hidapi expects it\n        timeout = int(timeout * 1000)\n        data = hidapi.read(int(handle), _MAX_READ_SIZE, timeout)\n    except Exception as reason:\n        logger.warning(\"read failed, assuming handle %r no longer available\", handle)\n        close(handle)\n        raise exceptions.NoReceiver(reason=reason) from reason\n\n    if data and _is_relevant_message(data):  # ignore messages that fail check\n        report_id = ord(data[:1])\n        devnumber = ord(data[1:2])\n\n        if logger.isEnabledFor(logging.DEBUG) and (\n            report_id != DJ_MESSAGE_ID or ord(data[2:3]) > 0x10\n        ):  # ignore DJ input messages\n            logger.debug(\n                \"(%s) => r[%02X %02X %s %s]\",\n                handle,\n                report_id,\n                devnumber,\n                common.strhex(data[2:4]),\n                common.strhex(data[4:]),\n            )\n\n        return report_id, devnumber, data[2:]\n\n\ndef make_notification(report_id: int, devnumber: int, data: bytes) -> HIDPPNotification | None:\n    \"\"\"Guess if this is a notification (and not just a request reply), and\n    return a Notification if it is.\"\"\"\n\n    sub_id = ord(data[:1])\n    if sub_id & 0x80 == 0x80:\n        # this is either a HID++1.0 register r/w, or an error reply\n        return None\n\n    # DJ input records are not notifications\n    if report_id == DJ_MESSAGE_ID and (sub_id < 0x10):\n        return None\n\n    address = ord(data[1:2])\n    if sub_id == 0x00 and (address & 0x0F == 0x00):\n        # this is a no-op notification - don't do anything with it\n        return None\n\n    if (\n        # standard HID++ 1.0 notification, SubId may be 0x40 - 0x7F\n        (sub_id >= 0x40)  # noqa: E131\n        or\n        # custom HID++1.0 battery events, where SubId is 0x07/0x0D\n        (sub_id in (0x07, 0x0D) and len(data) == 5 and data[4:5] == b\"\\x00\")\n        or\n        # custom HID++1.0 illumination event, where SubId is 0x17\n        (sub_id == 0x17 and len(data) == 5)\n        or\n        # HID++ 2.0 feature notifications have the SoftwareID 0\n        (address & 0x0F == 0x00)\n    ):  # noqa: E129\n        return HIDPPNotification(report_id, devnumber, sub_id, address, data[2:])\n    return None\n\n\ndef handle_lock(handle):\n    with request_lock:\n        if handles_lock.get(handle) is None:\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"New lock %s\", repr(handle))\n            handles_lock[handle] = threading.Lock()  # Serialize requests on the handle\n    return handles_lock[handle]\n\n\n# context manager for locks with a timeout\n@contextmanager\ndef acquire_timeout(lock, handle, timeout):\n    result = lock.acquire(timeout=timeout)\n    try:\n        if not result:\n            logger.error(\"lock on handle %d not acquired, probably due to timeout\", int(handle))\n        yield result\n    finally:\n        if result:\n            lock.release()\n\n\ndef find_paired_node(receiver_path: str, index: int, timeout: int):\n    \"\"\"Find the node of a device paired with a receiver.\"\"\"\n    return hidapi.find_paired_node(receiver_path, index, timeout)\n\n\ndef find_paired_node_wpid(receiver_path: str, index: int):\n    \"\"\"Find the node of a device paired with a receiver.\n\n    Get wpid from udev.\n    \"\"\"\n    return hidapi.find_paired_node_wpid(receiver_path, index)\n\n\n# a very few requests (e.g., host switching) do not expect a reply, but use no_reply=True with extreme caution\ndef request(\n    handle,\n    devnumber,\n    request_id: int,\n    *params,\n    no_reply: bool = False,\n    return_error: bool = False,\n    long_message: bool = False,\n    protocol: float = 1.0,\n):\n    \"\"\"Makes a feature call to a device and waits for a matching reply.\n    :param handle: an open UR handle.\n    :param devnumber: attached device number.\n    :param request_id: a 16-bit integer.\n    :param params: parameters for the feature call, 3 to 16 bytes.\n    :returns: the reply data, or ``None`` if some error occurred. or no reply expected\n    \"\"\"\n    with acquire_timeout(handle_lock(handle), handle, 10.0):\n        assert isinstance(request_id, int)\n        if (devnumber != 0xFF or protocol >= 2.0) and request_id < 0x8000:\n            # Always set the most significant bit (8) in SoftwareId,\n            # to make notifications easier to distinguish from request replies.\n            # This only applies to peripheral requests, ofc.\n            sw_id = _get_next_sw_id()\n            request_id = (request_id & 0xFFF0) | sw_id  # was 0x08 | getrandbits(3)\n\n        timeout = _RECEIVER_REQUEST_TIMEOUT if devnumber == 0xFF else _DEVICE_REQUEST_TIMEOUT\n        # be extra patient on long register read\n        if request_id & 0xFF00 == 0x8300:\n            timeout *= 2\n\n        if params:\n            params = b\"\".join(struct.pack(\"B\", p) if isinstance(p, int) else p for p in params)\n        else:\n            params = b\"\"\n        request_data = struct.pack(\"!H\", request_id) + params\n\n        ihandle = int(handle)\n        notifications_hook = getattr(handle, \"notifications_hook\", None)\n        try:\n            _read_input_buffer(handle, ihandle, notifications_hook)\n        except exceptions.NoReceiver:\n            logger.warning(\"device or receiver disconnected\")\n            return None\n        write(ihandle, devnumber, request_data, long_message)\n\n        if no_reply:\n            return None\n\n        # we consider timeout from this point\n        request_started = time()\n        delta = 0\n\n        while delta < timeout:\n            reply = _read(handle, timeout)\n            if reply:\n                report_id, reply_devnumber, reply_data = reply\n                if reply_devnumber == devnumber or reply_devnumber == devnumber ^ 0xFF:  # BT device returning 0x00\n                    if (\n                        report_id == HIDPP_SHORT_MESSAGE_ID\n                        and reply_data[:1] == b\"\\x8f\"\n                        and reply_data[1:3] == request_data[:2]\n                    ):\n                        error = ord(reply_data[3:4])\n\n                        if logger.isEnabledFor(logging.DEBUG):\n                            logger.debug(\n                                \"(%s) device 0x%02X error on request {%04X}: %d = %s\",\n                                handle,\n                                devnumber,\n                                request_id,\n                                error,\n                                Hidpp10ErrorCode(error),\n                            )\n                        return Hidpp10ErrorCode(error) if return_error else None\n                    if reply_data[:1] == b\"\\xff\" and reply_data[1:3] == request_data[:2]:\n                        # a HID++ 2.0 feature call returned with an error\n                        error = ord(reply_data[3:4])\n                        logger.error(\n                            \"(%s) device %d error on feature request {%04X}: %d = %s\",\n                            handle,\n                            devnumber,\n                            request_id,\n                            error,\n                            Hidpp20ErrorCode(error),\n                        )\n                        raise exceptions.FeatureCallError(\n                            number=devnumber,\n                            request=request_id,\n                            error=error,\n                            params=params,\n                        )\n\n                    if reply_data[:2] == request_data[:2]:\n                        if devnumber == 0xFF:\n                            if request_id == 0x83B5 or request_id == 0x81F1:\n                                # these replies have to match the first parameter as well\n                                if reply_data[2:3] == params[:1]:\n                                    return reply_data[2:]\n                                else:\n                                    # hm, not matching my request, and certainly not a notification\n                                    continue\n                            else:\n                                return reply_data[2:]\n                        else:\n                            return reply_data[2:]\n                else:\n                    # a reply was received, but did not match our request in any way\n                    # reset the timeout starting point\n                    request_started = time()\n\n                if notifications_hook:\n                    n = make_notification(report_id, reply_devnumber, reply_data)\n                    if n:\n                        notifications_hook(n)\n            delta = time() - request_started\n\n        logger.warning(\n            \"timeout (%0.2f/%0.2f) on device %d request {%04X} params [%s]\",\n            delta,\n            timeout,\n            devnumber,\n            request_id,\n            common.strhex(params),\n        )\n        # raise DeviceUnreachable(number=devnumber, request=request_id)\n\n\ndef ping(handle, devnumber, long_message: bool = False):\n    \"\"\"Check if a device is connected to the receiver.\n    :returns: The HID protocol supported by the device, as a floating point number, if the device is active.\n    \"\"\"\n    if logger.isEnabledFor(logging.DEBUG):\n        logger.debug(\"(%s) pinging device %d\", handle, devnumber)\n    with acquire_timeout(handle_lock(handle), handle, 10.0):\n        notifications_hook = getattr(handle, \"notifications_hook\", None)\n        try:\n            _read_input_buffer(handle, int(handle), notifications_hook)\n        except exceptions.NoReceiver:\n            logger.warning(\"device or receiver disconnected\")\n            return\n\n        # randomize the mark byte to be able to identify the ping reply\n        sw_id = _get_next_sw_id()\n        request_id = 0x0010 | sw_id  # was 0x0018 | getrandbits(3)\n        request_data = struct.pack(\"!HBBB\", request_id, 0, 0, getrandbits(8))\n        write(int(handle), devnumber, request_data, long_message)\n\n        request_started = time()  # we consider timeout from this point\n        delta = 0\n        while delta < _PING_TIMEOUT:\n            reply = _read(handle, _PING_TIMEOUT)\n            if reply:\n                report_id, reply_devnumber, reply_data = reply\n                if reply_devnumber == devnumber or reply_devnumber == devnumber ^ 0xFF:  # BT device returning 0x00\n                    if reply_data[:2] == request_data[:2] and reply_data[4:5] == request_data[-1:]:\n                        # HID++ 2.0+ device, currently connected\n                        return ord(reply_data[2:3]) + ord(reply_data[3:4]) / 10.0\n\n                    if (\n                        report_id == HIDPP_SHORT_MESSAGE_ID\n                        and reply_data[:1] == b\"\\x8f\"\n                        and reply_data[1:3] == request_data[:2]\n                    ):  # error response\n                        error = ord(reply_data[3:4])\n                        if error == Hidpp10ErrorCode.INVALID_SUB_ID_COMMAND:\n                            # a valid reply from a HID++ 1.0 device\n                            return 1.0\n                        if error in [Hidpp10ErrorCode.RESOURCE_ERROR, Hidpp10ErrorCode.CONNECTION_REQUEST_FAILED]:\n                            return  # device unreachable\n                        if error == Hidpp10ErrorCode.UNKNOWN_DEVICE:  # no device with that number currently accessible\n                            logger.info(\"(%s) device %d error on ping request: unknown device\", handle, devnumber)\n                            raise exceptions.NoSuchDevice(number=devnumber, request=request_id)\n\n                if notifications_hook:\n                    n = make_notification(report_id, reply_devnumber, reply_data)\n                    if n:\n                        notifications_hook(n)\n\n            delta = time() - request_started\n\n        logger.warning(\"(%s) timeout (%0.2f/%0.2f) on device %d ping\", handle, delta, _PING_TIMEOUT, devnumber)\n\n\ndef _read_input_buffer(handle, ihandle, notifications_hook):\n    \"\"\"Consume anything already in the input buffer.\n\n    Used by request() and ping() before their write.\n    \"\"\"\n\n    while True:\n        try:\n            # read whatever is already in the buffer, if any\n            data = hidapi.read(ihandle, _MAX_READ_SIZE, 0)\n        except Exception as reason:\n            logger.error(\"read failed, assuming receiver %s no longer available\", handle)\n            close(handle)\n            raise exceptions.NoReceiver(reason=reason) from reason\n\n        if data:\n            if _is_relevant_message(data):  # only process messages that pass check\n                # report_id = ord(data[:1])\n                if notifications_hook:\n                    n = make_notification(ord(data[:1]), ord(data[1:2]), data[2:])\n                    if n:\n                        notifications_hook(n)\n        else:\n            # nothing in the input buffer, we're done\n            return\n\n\ndef _get_next_sw_id() -> int:\n    \"\"\"Returns 'random' software ID to separate replies from different devices.\n\n    Cycle the HID++ 2.0 software ID from 0x2 to 0xF to separate\n    results and notifications.\n    \"\"\"\n    if not hasattr(_get_next_sw_id, \"software_id\"):\n        _get_next_sw_id.software_id = 0xF\n\n    if _get_next_sw_id.software_id < 0xF:\n        _get_next_sw_id.software_id += 1\n    else:\n        _get_next_sw_id.software_id = 2\n    return _get_next_sw_id.software_id\n"
  },
  {
    "path": "lib/logitech_receiver/base_usb.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n\"\"\"Collection of known Logitech product IDs.\n\nAccording to Logitech, they use the following product IDs (as of September 2020)\nUSB product IDs for receivers: 0xC526 - 0xC5xx\nWireless PIDs for hidpp10 devices: 0x2006 - 0x2019\nWireless PIDs for hidpp20 devices: 0x4002 - 0x4097, 0x4101 - 0x4102\nUSB product IDs for hidpp20 devices: 0xC07D - 0xC094, 0xC32B - 0xC344\nBluetooth product IDs (for hidpp20 devices): 0xB012 - 0xB0xx, 0xB32A - 0xB3xx\n\nUSB ids of Logitech wireless receivers.\nOnly receivers supporting the HID++ protocol can go in here.\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom typing import Any\n\nfrom solaar.i18n import _\n\n# max_devices is only used for receivers that do not support reading from Registers.RECEIVER_INFO offset 0x03, default\n# to 1.\n# may_unpair is only used for receivers that do not support reading from Registers.RECEIVER_INFO offset 0x03,\n# default to False.\n# unpair is for receivers that do support reading from Registers.RECEIVER_INFO offset 0x03, no default.\n## should this last be changed so that may_unpair is used for all receivers? writing to Registers.RECEIVER_PAIRING\n## doesn't seem right\n\nLOGITECH_VENDOR_ID = 0x046D\n\n\ndef _bolt_receiver(product_id: int) -> dict:\n    return {\n        \"vendor_id\": LOGITECH_VENDOR_ID,\n        \"product_id\": product_id,\n        \"usb_interface\": 2,\n        \"name\": _(\"Bolt Receiver\"),\n        \"receiver_kind\": \"bolt\",\n        \"max_devices\": 6,\n        \"may_unpair\": True,\n    }\n\n\ndef _unifying_receiver(product_id: int) -> dict:\n    return {\n        \"vendor_id\": LOGITECH_VENDOR_ID,\n        \"product_id\": product_id,\n        \"usb_interface\": 2,\n        \"name\": _(\"Unifying Receiver\"),\n        \"receiver_kind\": \"unifying\",\n        \"may_unpair\": True,\n    }\n\n\ndef _nano_receiver(product_id: int) -> dict:\n    return {\n        \"vendor_id\": LOGITECH_VENDOR_ID,\n        \"product_id\": product_id,\n        \"usb_interface\": 1,\n        \"name\": _(\"Nano Receiver\"),\n        \"receiver_kind\": \"nano\",\n        \"may_unpair\": False,\n        \"re_pairs\": True,\n    }\n\n\ndef _nano_receiver_no_unpair(product_id: int) -> dict:\n    return {\n        \"vendor_id\": LOGITECH_VENDOR_ID,\n        \"product_id\": product_id,\n        \"usb_interface\": 1,\n        \"name\": _(\"Nano Receiver\"),\n        \"receiver_kind\": \"nano\",\n        \"may_unpair\": False,\n        \"unpair\": False,\n        \"re_pairs\": True,\n    }\n\n\ndef _nano_receiver_max2(product_id: int) -> dict:\n    return {\n        \"vendor_id\": LOGITECH_VENDOR_ID,\n        \"product_id\": product_id,\n        \"usb_interface\": 1,\n        \"name\": _(\"Nano Receiver\"),\n        \"receiver_kind\": \"nano\",\n        \"max_devices\": 2,\n        \"may_unpair\": False,\n        \"re_pairs\": True,\n    }\n\n\ndef _lenovo_receiver(product_id: int) -> dict:\n    return {\n        \"vendor_id\": 6127,\n        \"product_id\": product_id,\n        \"usb_interface\": 1,\n        \"name\": _(\"Nano Receiver\"),\n        \"receiver_kind\": \"nano\",\n        \"may_unpair\": False,\n    }\n\n\ndef _lightspeed_receiver(product_id: int) -> dict:\n    return {\n        \"vendor_id\": LOGITECH_VENDOR_ID,\n        \"product_id\": product_id,\n        \"usb_interface\": 2,\n        \"receiver_kind\": \"lightspeed\",\n        \"name\": _(\"Lightspeed Receiver\"),\n        \"may_unpair\": False,\n        \"re_pairs\": True,\n    }\n\n\ndef _ex100_receiver(product_id: int) -> dict:\n    return {\n        \"vendor_id\": LOGITECH_VENDOR_ID,\n        \"product_id\": product_id,\n        \"usb_interface\": 1,\n        \"name\": _(\"EX100 Receiver 27 Mhz\"),\n        \"receiver_kind\": \"27Mhz\",\n        \"max_devices\": 4,\n        \"may_unpair\": False,\n        \"re_pairs\": True,\n    }\n\n\n# Receivers added here should also be listed in\n# share/solaar/io.github.pwr_solaar.solaar.meta-info.xml\n# Look in https://github.com/torvalds/linux/blob/master/drivers/hid/hid-ids.h\n\n# Bolt receivers (marked with the yellow lightning bolt logo)\nBOLT_RECEIVER_C548 = _bolt_receiver(0xC548)\n\n# standard Unifying receivers (marked with the orange Unifying logo)\nUNIFYING_RECEIVER_C52B = _unifying_receiver(0xC52B)\nUNIFYING_RECEIVER_C532 = _unifying_receiver(0xC532)\n\n# Nano receivers (usually sold with low-end devices)\nNANO_RECEIVER_ADVANCED = _nano_receiver_no_unpair(0xC52F)\nNANO_RECEIVER_C518 = _nano_receiver(0xC518)\nNANO_RECEIVER_C51A = _nano_receiver(0xC51A)\nNANO_RECEIVER_C51B = _nano_receiver(0xC51B)\nNANO_RECEIVER_C521 = _nano_receiver(0xC521)\nNANO_RECEIVER_C525 = _nano_receiver(0xC525)\nNANO_RECEIVER_C526 = _nano_receiver(0xC526)\nNANO_RECEIVER_C52E = _nano_receiver_no_unpair(0xC52E)\nNANO_RECEIVER_C531 = _nano_receiver(0xC531)\nNANO_RECEIVER_C534 = _nano_receiver_max2(0xC534)\nNANO_RECEIVER_C535 = _nano_receiver(0xC535)  # branded as Dell\nNANO_RECEIVER_C537 = _nano_receiver(0xC537)\nNANO_RECEIVER_6042 = _lenovo_receiver(0x6042)\n\n# Lightspeed receivers (usually sold with gaming devices)\nLIGHTSPEED_RECEIVER_C539 = _lightspeed_receiver(0xC539)\nLIGHTSPEED_RECEIVER_C53A = _lightspeed_receiver(0xC53A)\nLIGHTSPEED_RECEIVER_C53D = _lightspeed_receiver(0xC53D)\nLIGHTSPEED_RECEIVER_C53F = _lightspeed_receiver(0xC53F)\nLIGHTSPEED_RECEIVER_C541 = _lightspeed_receiver(0xC541)\nLIGHTSPEED_RECEIVER_C545 = _lightspeed_receiver(0xC545)\nLIGHTSPEED_RECEIVER_C547 = _lightspeed_receiver(0xC547)\nLIGHTSPEED_RECEIVER_C54D = _lightspeed_receiver(0xC54D)\n\n# EX100 old style receiver pre-unifying protocol\nEX100_27MHZ_RECEIVER_C517 = _ex100_receiver(0xC517)\n\nKNOWN_RECEIVERS = {\n    0xC548: BOLT_RECEIVER_C548,\n    0xC52B: UNIFYING_RECEIVER_C52B,\n    0xC532: UNIFYING_RECEIVER_C532,\n    0xC52F: NANO_RECEIVER_ADVANCED,\n    0xC518: NANO_RECEIVER_C518,\n    0xC51A: NANO_RECEIVER_C51A,\n    0xC51B: NANO_RECEIVER_C51B,\n    0xC521: NANO_RECEIVER_C521,\n    0xC525: NANO_RECEIVER_C525,\n    0xC526: NANO_RECEIVER_C526,\n    0xC52E: NANO_RECEIVER_C52E,\n    0xC531: NANO_RECEIVER_C531,\n    0xC534: NANO_RECEIVER_C534,\n    0xC535: NANO_RECEIVER_C535,\n    0xC537: NANO_RECEIVER_C537,\n    0x6042: NANO_RECEIVER_6042,\n    0xC539: LIGHTSPEED_RECEIVER_C539,\n    0xC53A: LIGHTSPEED_RECEIVER_C53A,\n    0xC53D: LIGHTSPEED_RECEIVER_C53D,\n    0xC53F: LIGHTSPEED_RECEIVER_C53F,\n    0xC541: LIGHTSPEED_RECEIVER_C541,\n    0xC545: LIGHTSPEED_RECEIVER_C545,\n    0xC547: LIGHTSPEED_RECEIVER_C547,\n    0xC54D: LIGHTSPEED_RECEIVER_C54D,\n    0xC517: EX100_27MHZ_RECEIVER_C517,\n}\n\n\ndef get_receiver_info(product_id: int) -> dict[str, Any]:\n    \"\"\"Returns hardcoded information about a Logitech receiver.\n\n    Parameters\n    ----------\n    product_id\n        Product ID (pid) of the receiver, e.g. 0xC548 for a Logitech\n        Bolt receiver.\n\n    Returns\n    -------\n    dict[str, Any]\n        Receiver info with mandatory fields:\n        - vendor_id\n        - product_id\n\n    Raises\n    ------\n    ValueError\n        If the product ID is unknown.\n    \"\"\"\n    try:\n        return KNOWN_RECEIVERS[product_id]\n    except KeyError:\n        pass\n\n    raise ValueError(f\"Unknown product ID '0x{product_id:02X}'\")\n"
  },
  {
    "path": "lib/logitech_receiver/common.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nfrom __future__ import annotations\n\nimport binascii\nimport dataclasses\nimport typing\n\nfrom enum import Flag\nfrom enum import IntEnum\nfrom typing import Generator\nfrom typing import Iterable\nfrom typing import Optional\nfrom typing import Union\n\nimport yaml\n\nfrom solaar.i18n import _\n\nif typing.TYPE_CHECKING:\n    from logitech_receiver.hidpp20_constants import FirmwareKind\n\nLOGITECH_VENDOR_ID = 0x046D\n\n\ndef crc16(data: bytes):\n    \"\"\"\n    CRC-16 (CCITT) implemented with a precomputed lookup table\n    \"\"\"\n    table = [\n        0x0000,\n        0x1021,\n        0x2042,\n        0x3063,\n        0x4084,\n        0x50A5,\n        0x60C6,\n        0x70E7,\n        0x8108,\n        0x9129,\n        0xA14A,\n        0xB16B,\n        0xC18C,\n        0xD1AD,\n        0xE1CE,\n        0xF1EF,\n        0x1231,\n        0x0210,\n        0x3273,\n        0x2252,\n        0x52B5,\n        0x4294,\n        0x72F7,\n        0x62D6,\n        0x9339,\n        0x8318,\n        0xB37B,\n        0xA35A,\n        0xD3BD,\n        0xC39C,\n        0xF3FF,\n        0xE3DE,\n        0x2462,\n        0x3443,\n        0x0420,\n        0x1401,\n        0x64E6,\n        0x74C7,\n        0x44A4,\n        0x5485,\n        0xA56A,\n        0xB54B,\n        0x8528,\n        0x9509,\n        0xE5EE,\n        0xF5CF,\n        0xC5AC,\n        0xD58D,\n        0x3653,\n        0x2672,\n        0x1611,\n        0x0630,\n        0x76D7,\n        0x66F6,\n        0x5695,\n        0x46B4,\n        0xB75B,\n        0xA77A,\n        0x9719,\n        0x8738,\n        0xF7DF,\n        0xE7FE,\n        0xD79D,\n        0xC7BC,\n        0x48C4,\n        0x58E5,\n        0x6886,\n        0x78A7,\n        0x0840,\n        0x1861,\n        0x2802,\n        0x3823,\n        0xC9CC,\n        0xD9ED,\n        0xE98E,\n        0xF9AF,\n        0x8948,\n        0x9969,\n        0xA90A,\n        0xB92B,\n        0x5AF5,\n        0x4AD4,\n        0x7AB7,\n        0x6A96,\n        0x1A71,\n        0x0A50,\n        0x3A33,\n        0x2A12,\n        0xDBFD,\n        0xCBDC,\n        0xFBBF,\n        0xEB9E,\n        0x9B79,\n        0x8B58,\n        0xBB3B,\n        0xAB1A,\n        0x6CA6,\n        0x7C87,\n        0x4CE4,\n        0x5CC5,\n        0x2C22,\n        0x3C03,\n        0x0C60,\n        0x1C41,\n        0xEDAE,\n        0xFD8F,\n        0xCDEC,\n        0xDDCD,\n        0xAD2A,\n        0xBD0B,\n        0x8D68,\n        0x9D49,\n        0x7E97,\n        0x6EB6,\n        0x5ED5,\n        0x4EF4,\n        0x3E13,\n        0x2E32,\n        0x1E51,\n        0x0E70,\n        0xFF9F,\n        0xEFBE,\n        0xDFDD,\n        0xCFFC,\n        0xBF1B,\n        0xAF3A,\n        0x9F59,\n        0x8F78,\n        0x9188,\n        0x81A9,\n        0xB1CA,\n        0xA1EB,\n        0xD10C,\n        0xC12D,\n        0xF14E,\n        0xE16F,\n        0x1080,\n        0x00A1,\n        0x30C2,\n        0x20E3,\n        0x5004,\n        0x4025,\n        0x7046,\n        0x6067,\n        0x83B9,\n        0x9398,\n        0xA3FB,\n        0xB3DA,\n        0xC33D,\n        0xD31C,\n        0xE37F,\n        0xF35E,\n        0x02B1,\n        0x1290,\n        0x22F3,\n        0x32D2,\n        0x4235,\n        0x5214,\n        0x6277,\n        0x7256,\n        0xB5EA,\n        0xA5CB,\n        0x95A8,\n        0x8589,\n        0xF56E,\n        0xE54F,\n        0xD52C,\n        0xC50D,\n        0x34E2,\n        0x24C3,\n        0x14A0,\n        0x0481,\n        0x7466,\n        0x6447,\n        0x5424,\n        0x4405,\n        0xA7DB,\n        0xB7FA,\n        0x8799,\n        0x97B8,\n        0xE75F,\n        0xF77E,\n        0xC71D,\n        0xD73C,\n        0x26D3,\n        0x36F2,\n        0x0691,\n        0x16B0,\n        0x6657,\n        0x7676,\n        0x4615,\n        0x5634,\n        0xD94C,\n        0xC96D,\n        0xF90E,\n        0xE92F,\n        0x99C8,\n        0x89E9,\n        0xB98A,\n        0xA9AB,\n        0x5844,\n        0x4865,\n        0x7806,\n        0x6827,\n        0x18C0,\n        0x08E1,\n        0x3882,\n        0x28A3,\n        0xCB7D,\n        0xDB5C,\n        0xEB3F,\n        0xFB1E,\n        0x8BF9,\n        0x9BD8,\n        0xABBB,\n        0xBB9A,\n        0x4A75,\n        0x5A54,\n        0x6A37,\n        0x7A16,\n        0x0AF1,\n        0x1AD0,\n        0x2AB3,\n        0x3A92,\n        0xFD2E,\n        0xED0F,\n        0xDD6C,\n        0xCD4D,\n        0xBDAA,\n        0xAD8B,\n        0x9DE8,\n        0x8DC9,\n        0x7C26,\n        0x6C07,\n        0x5C64,\n        0x4C45,\n        0x3CA2,\n        0x2C83,\n        0x1CE0,\n        0x0CC1,\n        0xEF1F,\n        0xFF3E,\n        0xCF5D,\n        0xDF7C,\n        0xAF9B,\n        0xBFBA,\n        0x8FD9,\n        0x9FF8,\n        0x6E17,\n        0x7E36,\n        0x4E55,\n        0x5E74,\n        0x2E93,\n        0x3EB2,\n        0x0ED1,\n        0x1EF0,\n    ]\n\n    crc = 0xFFFF\n    for byte in data:\n        crc = (crc << 8) ^ table[(crc >> 8) ^ byte]\n        crc &= 0xFFFF  # important, crc must stay 16bits all the way through\n    return crc\n\n\nclass NamedInt(int):\n    \"\"\"A regular Python integer with an attached name.\n\n    Caution: comparison with strings will also match this NamedInt's name\n    (case-insensitive).\"\"\"\n\n    def __new__(cls, value, name):\n        assert isinstance(name, str)\n        obj = int.__new__(cls, value)\n        obj.name = str(name)\n        return obj\n\n    def bytes(self, count=2):\n        return int2bytes(self, count)\n\n    def __eq__(self, other):\n        if other is None:\n            return False\n        if isinstance(other, NamedInt):\n            return int(self) == int(other) and self.name == other.name\n        if isinstance(other, int):\n            return int(self) == int(other)\n        if isinstance(other, str):\n            return self.name.lower() == other.lower()\n        # this should catch comparisons with bytes in Py3\n        if other is not None:\n            raise TypeError(f\"Unsupported type {str(type(other))}\")\n\n    def __ne__(self, other):\n        return not self.__eq__(other)\n\n    def __hash__(self):\n        return int(self)\n\n    def __str__(self):\n        return self.name\n\n    def __repr__(self):\n        return f\"NamedInt({int(self)}, {self.name!r})\"\n\n    @classmethod\n    def from_yaml(cls, loader, node):\n        args = loader.construct_mapping(node)\n        return cls(value=args[\"value\"], name=args[\"name\"])\n\n    @classmethod\n    def to_yaml(cls, dumper, data):\n        return dumper.represent_mapping(\"!NamedInt\", {\"value\": int(data), \"name\": data.name}, flow_style=True)\n\n\nyaml.SafeLoader.add_constructor(\"!NamedInt\", NamedInt.from_yaml)\nyaml.add_representer(NamedInt, NamedInt.to_yaml)\n\n\nclass NamedInts:\n    \"\"\"An ordered set of NamedInt values.\n\n    Indexing can be made by int or string, and will return the corresponding\n    NamedInt if it exists in this set, or `None`.\n\n    Extracting slices will return all present NamedInts in the given interval\n    (extended slices are not supported).\n\n    Assigning a string to an indexed int will create a new NamedInt in this set;\n    if the value already exists in the set (int or string), ValueError will be\n    raised.\n    \"\"\"\n\n    __slots__ = (\"__dict__\", \"_values\", \"_indexed\", \"_fallback\", \"_is_sorted\")\n\n    def __init__(self, dict_=None, **kwargs):\n        def _readable_name(n):\n            return n.replace(\"__\", \"/\").replace(\"_\", \" \")\n\n        # print (repr(kwargs))\n        elements = dict_ if dict_ else kwargs\n        values = {k: NamedInt(v, _readable_name(k)) for (k, v) in elements.items()}\n        self.__dict__ = values\n        self._is_sorted = False\n        self._values = list(values.values())\n        self._sort_values()\n        self._indexed = {int(v): v for v in self._values}\n        # assert len(values) == len(self._indexed)\n        # \"(%d) %r\\n=> (%d) %r\" % (len(values), values, len(self._indexed), self._indexed)\n        self._fallback = None\n\n    @classmethod\n    def list(cls, items, name_generator=lambda x: str(x)):  # noqa: B008\n        values = {name_generator(x): x for x in items}\n        return NamedInts(**values)\n\n    @classmethod\n    def range(cls, from_value, to_value, name_generator=lambda x: str(x), step=1):  # noqa: B008\n        values = {name_generator(x): x for x in range(from_value, to_value + 1, step)}\n        return NamedInts(**values)\n\n    def flag_names(self, value):\n        unknown_bits = value\n        for k in self._indexed:\n            assert bin(k).count(\"1\") == 1\n            if k & value == k:\n                unknown_bits &= ~k\n                yield str(self._indexed[k])\n\n        if unknown_bits:\n            yield f\"unknown:{unknown_bits:06X}\"\n\n    def _sort_values(self):\n        self._values = sorted(self._values)\n        self._is_sorted = True\n\n    def __getitem__(self, index):\n        if isinstance(index, int):\n            if index in self._indexed:\n                return self._indexed[int(index)]\n            if self._fallback:\n                value = NamedInt(index, self._fallback(index))\n                self._indexed[index] = value\n                self._values.append(value)\n                self._is_sorted = False\n                self._sort_values()\n                return value\n\n        elif isinstance(index, str):\n            if index in self.__dict__:\n                return self.__dict__[index]\n            return next((x for x in self._values if str(x) == index), None)\n\n        elif isinstance(index, slice):\n            values = self._values if self._is_sorted else sorted(self._values)\n\n            if index.start is None and index.stop is None:\n                return values[:]\n\n            v_start = int(values[0]) if index.start is None else int(index.start)\n            v_stop = (values[-1] + 1) if index.stop is None else int(index.stop)\n\n            if v_start > v_stop or v_start > values[-1] or v_stop <= values[0]:\n                return []\n\n            if v_start <= values[0] and v_stop > values[-1]:\n                return values[:]\n\n            start_index = 0\n            stop_index = len(values)\n\n            for i, value in enumerate(values):\n                if value < v_start:\n                    start_index = i + 1\n                elif index.stop is None:\n                    break\n                if value >= v_stop:\n                    stop_index = i\n                    break\n\n            return values[start_index:stop_index]\n\n    def __setitem__(self, index, name):\n        assert isinstance(index, int), type(index)\n        if isinstance(name, NamedInt):\n            assert int(index) == int(name), f\"{repr(index)} {repr(name)}\"\n            value = name\n        elif isinstance(name, str):\n            value = NamedInt(index, name)\n        else:\n            raise TypeError(\"name must be a string\")\n\n        if str(value) in self.__dict__:\n            raise ValueError(f\"{value} ({int(value)}) already known\")\n        if int(value) in self._indexed:\n            raise ValueError(f\"{int(value)} ({value}) already known\")\n\n        self._values.append(value)\n        self._is_sorted = False\n        self._sort_values()\n        self.__dict__[str(value)] = value\n        self._indexed[int(value)] = value\n\n    def __contains__(self, value):\n        if isinstance(value, NamedInt):\n            return self[value] == value\n        elif isinstance(value, int):\n            return value in self._indexed\n        elif isinstance(value, str):\n            return value in self.__dict__ or value in self._values\n\n    def __iter__(self):\n        yield from self._values\n\n    def __len__(self):\n        return len(self._values)\n\n    def __repr__(self):\n        return f\"NamedInts({', '.join(repr(v) for v in self._values)})\"\n\n    def __or__(self, other):\n        return NamedInts(**self.__dict__, **other.__dict__)\n\n    def __eq__(self, other):\n        return isinstance(other, self.__class__) and self._values == other._values\n\n\ndef flag_names(enum_class: Iterable, value: int) -> Generator[str]:\n    \"\"\"Extracts single bit flags from a (binary) number.\n\n    Parameters\n    ----------\n    enum_class\n        Enum class to extract flags from.\n    value\n        Number to extract binary flags from.\n    \"\"\"\n    indexed = {item.value: item.name for item in enum_class}\n\n    unknown_bits = value\n    for k in indexed:\n        # Ensure that the key (flag value) is a power of 2 (a single bit flag)\n        assert bin(k).count(\"1\") == 1\n        if k & value == k:\n            unknown_bits &= ~k\n            yield indexed[k].lower()\n\n    # Yield any remaining unknown bits\n    if unknown_bits != 0:\n        yield f\"unknown:{unknown_bits:06X}\"\n\n\nclass UnsortedNamedInts(NamedInts):\n    def _sort_values(self):\n        pass\n\n    def __or__(self, other):\n        c = UnsortedNamedInts if isinstance(other, UnsortedNamedInts) else NamedInts\n        return c(**self.__dict__, **other.__dict__)\n\n\ndef strhex(x):\n    assert x is not None\n    \"\"\"Produce a hex-string representation of a sequence of bytes.\"\"\"\n    return binascii.hexlify(x).decode(\"ascii\").upper()\n\n\ndef bytes2int(x, signed=False):\n    return int.from_bytes(x, signed=signed, byteorder=\"big\")\n\n\ndef int2bytes(x, count=None, signed=False):\n    if count:\n        return x.to_bytes(length=count, byteorder=\"big\", signed=signed)\n    else:\n        return x.to_bytes(length=8, byteorder=\"big\", signed=signed).lstrip(b\"\\x00\")\n\n\nclass KwException(Exception):\n    \"\"\"An exception that remembers all arguments passed to the constructor.\n    They can be later accessed by simple member access.\n    \"\"\"\n\n    def __init__(self, **kwargs):\n        super().__init__(kwargs)\n\n    def __getattr__(self, k):\n        try:\n            return super().__getattr__(k)\n        except AttributeError:\n            return self.args[0].get(k)  # was self.args[0][k]\n\n\nclass FirmwareKind(IntEnum):\n    Firmware = 0x00\n    Bootloader = 0x01\n    Hardware = 0x02\n    Other = 0x03\n\n\n@dataclasses.dataclass\nclass FirmwareInfo:\n    kind: FirmwareKind\n    name: str\n    version: str\n    extras: str | None\n\n\nclass BatteryStatus(Flag):\n    DISCHARGING = 0x00\n    RECHARGING = 0x01\n    ALMOST_FULL = 0x02\n    FULL = 0x03\n    SLOW_RECHARGE = 0x04\n    INVALID_BATTERY = 0x05\n    THERMAL_ERROR = 0x06\n\n\nclass BatteryLevelApproximation(IntEnum):\n    EMPTY = 0\n    CRITICAL = 5\n    LOW = 20\n    GOOD = 50\n    FULL = 90\n\n\n@dataclasses.dataclass\nclass Battery:\n    \"\"\"Information about the current state of a battery\"\"\"\n\n    ATTENTION_LEVEL = 5\n\n    level: Optional[Union[BatteryLevelApproximation, int]]\n    next_level: Optional[Union[NamedInt, int]]\n    status: Optional[BatteryStatus]\n    voltage: Optional[int]\n    light_level: Optional[int] = None  # light level for devices with solaar recharging\n\n    def __post_init__(self):\n        if self.level is None:  # infer level from status if needed and possible\n            if self.status == BatteryStatus.FULL:\n                self.level = BatteryLevelApproximation.FULL\n            elif self.status in (BatteryStatus.ALMOST_FULL, BatteryStatus.RECHARGING):\n                self.level = BatteryLevelApproximation.GOOD\n            elif self.status == BatteryStatus.SLOW_RECHARGE:\n                self.level = BatteryLevelApproximation.LOW\n\n    def ok(self) -> bool:\n        return self.status not in (BatteryStatus.INVALID_BATTERY, BatteryStatus.THERMAL_ERROR) and (\n            self.level is None or self.level > Battery.ATTENTION_LEVEL\n        )\n\n    def charging(self) -> bool:\n        return self.status in (\n            BatteryStatus.RECHARGING,\n            BatteryStatus.ALMOST_FULL,\n            BatteryStatus.FULL,\n            BatteryStatus.SLOW_RECHARGE,\n        )\n\n    def to_str(self) -> str:\n        if isinstance(self.level, BatteryLevelApproximation):\n            level = self.level.name.lower()\n            status = self.status.name.lower().replace(\"_\", \" \") if self.status is not None else \"Unknown\"\n            return _(\"Battery: %(level)s (%(status)s)\") % {\"level\": _(level), \"status\": _(status)}\n        elif isinstance(self.level, int):\n            status = self.status.name.lower().replace(\"_\", \" \") if self.status is not None else \"Unknown\"\n            return _(\"Battery: %(percent)d%% (%(status)s)\") % {\"percent\": self.level, \"status\": _(status)}\n        return \"\"\n\n\nclass Alert(IntEnum):\n    NONE = 0x00\n    NOTIFICATION = 0x01\n    SHOW_WINDOW = 0x02\n    ATTENTION = 0x04\n    ALL = 0xFF\n\n\nclass Notification(IntEnum):\n    NO_OPERATION = 0x00\n    CONNECT_DISCONNECT = 0x40\n    DJ_PAIRING = 0x41\n    CONNECTED = 0x42\n    RAW_INPUT = 0x49\n    PAIRING_LOCK = 0x4A\n    POWER = 0x4B\n\n\nclass BusID(IntEnum):\n    USB = 0x03\n    BLUETOOTH = 0x05\n"
  },
  {
    "path": "lib/logitech_receiver/descriptors.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n\n\"\"\"Devices (not receivers) known to Solaar.\n\nSolaar can handle many recent devices without having any entry here.\nAn entry should only be added to fix problems, such as\n- the device's device ID or WPID falls outside the range that Solaar searches\n- the device uses a USB interface other than 2\n- the name or codename should be different from what the device reports\n\"\"\"\n\nfrom .hidpp10_constants import DEVICE_KIND\nfrom .hidpp10_constants import Registers as Reg\n\n\nclass _DeviceDescriptor:\n    def __init__(\n        self,\n        name=None,\n        kind=None,\n        wpid=None,\n        codename=None,\n        protocol=None,\n        registers=None,\n        usbid=None,\n        interface=None,\n        btid=None,\n    ):\n        self.name = name\n        self.kind = kind\n        self.wpid = wpid\n        self.codename = codename\n        self.protocol = protocol\n        self.registers = registers\n        self.usbid = usbid\n        self.interface = interface\n        self.btid = btid\n        self.settings = None\n\n\nDEVICES_WPID = {}\nDEVICES = {}\n\n\ndef _D(\n    name,\n    codename=None,\n    kind=None,\n    wpid=None,\n    protocol=None,\n    registers=None,\n    settings=None,\n    usbid=None,\n    interface=None,\n    btid=None,\n):\n    if kind is None:\n        kind = (\n            DEVICE_KIND.mouse\n            if \"Mouse\" in name\n            else DEVICE_KIND.keyboard\n            if \"Keyboard\" in name\n            else DEVICE_KIND.numpad\n            if \"Number Pad\" in name\n            else DEVICE_KIND.touchpad\n            if \"Touchpad\" in name\n            else DEVICE_KIND.trackball\n            if \"Trackball\" in name\n            else None\n        )\n    assert kind is not None, f\"descriptor for {name} does not have kind set\"\n\n    if protocol is not None:\n        if wpid:\n            for w in wpid if isinstance(wpid, tuple) else (wpid,):\n                if protocol > 1.0:\n                    assert w[0:1] == \"4\", f\"{name} has protocol {protocol:0.1f}, wpid {w}\"\n                else:\n                    if w[0:1] == \"1\":\n                        assert kind == DEVICE_KIND.mouse, f\"{name} has protocol {protocol:0.1f}, wpid {w}\"\n                    elif w[0:1] == \"2\":\n                        assert kind in (\n                            DEVICE_KIND.keyboard,\n                            DEVICE_KIND.numpad,\n                        ), f\"{name} has protocol {protocol:0.1f}, wpid {w}\"\n\n    device_descriptor = _DeviceDescriptor(\n        name=name,\n        kind=kind,\n        wpid=wpid,\n        codename=codename,\n        protocol=protocol,\n        registers=registers,\n        usbid=usbid,\n        interface=interface,\n        btid=btid,\n    )\n\n    if usbid:\n        found = get_usbid(usbid)\n        assert found is None, f\"duplicate usbid in device descriptors: {found}\"\n    if btid:\n        found = get_btid(btid)\n        assert found is None, f\"duplicate btid in device descriptors: {found}\"\n\n    assert codename not in DEVICES, f\"duplicate codename in device descriptors: {DEVICES[codename]}\"\n    if codename:\n        DEVICES[codename] = device_descriptor\n\n    if wpid:\n        for w in wpid if isinstance(wpid, tuple) else (wpid,):\n            assert w not in DEVICES_WPID, f\"duplicate wpid in device descriptors: {DEVICES_WPID[w]}\"\n            DEVICES_WPID[w] = device_descriptor\n\n\ndef get_wpid(wpid):\n    return DEVICES_WPID.get(wpid)\n\n\ndef get_codename(codename):\n    return DEVICES.get(codename)\n\n\ndef get_usbid(usbid):\n    if isinstance(usbid, str):\n        usbid = int(usbid, 16)\n    found = next((x for x in DEVICES.values() if x.usbid == usbid), None)\n    return found\n\n\ndef get_btid(btid):\n    if isinstance(btid, str):\n        btid = int(btid, 16)\n    found = next((x for x in DEVICES.values() if x.btid == btid), None)\n    return found\n\n\n# Some HID++1.0 registers and HID++2.0 features can be discovered at run-time,\n# so they are not specified here.\n#\n# State registers (battery, leds, some features, etc) are only used by\n# HID++ 1.0 devices, while HID++ 2.0 devices use features for the same\n# functionalities.\n\n# Well-known registers (in hex):\n#  * 00 - notification flags (all devices)\n#    01 - mice: smooth scrolling\n#    07 - battery status\n#    09 - keyboards: FN swap (if it has the FN key)\n#    0D - battery charge\n#       a device may have either the 07 or 0D register available;\n#       no known device uses both\n#    51 - leds\n#    63 - mice: DPI\n#  * F1 - firmware info\n# Some registers appear to be universally supported, no matter the HID++ version\n# (marked with *). The rest may or may not be supported, and their values may or\n# may not mean the same thing across different devices.\n\n# The 'codename' and 'kind' fields are usually guessed from the device name,\n# but in some cases (like the Logitech Cube) that heuristic fails and they have\n# to be specified.\n#\n# The 'protocol' and 'wpid' fields are optional (they can be discovered at\n# runtime), but specifying them here speeds up device discovery and reduces the\n# USB traffic Solaar has to do to fully identify peripherals.\n#\n# The 'registers' field indicates read-only registers, specifying a state. These\n# are valid (AFAIK) only to HID++ 1.0 devices.\n# The 'settings' field indicates a read/write register; based on them Solaar\n# generates, at runtime, the settings controls in the device panel.\n# Solaar now sets up this field in settings_templates.py to eliminate a imports loop.\n# HID++ 1.0 devices may only have register-based settings; HID++ 2.0 devices may only have\n# feature-based settings.\n\n# Devices are organized by kind\n# Within kind devices are sorted by wpid, then by usbid, then by btid, with missing values sorted later\n\n# Keyboards\n\n_D(\"Wireless Keyboard EX110\", codename=\"EX110\", protocol=1.0, wpid=\"0055\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Keyboard S510\", codename=\"S510\", protocol=1.0, wpid=\"0056\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Wave Keyboard K550\", codename=\"K550\", protocol=1.0, wpid=\"0060\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Keyboard EX100\", codename=\"EX100\", protocol=1.0, wpid=\"0065\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Keyboard MK300\", codename=\"MK300\", protocol=1.0, wpid=\"0068\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Number Pad N545\", codename=\"N545\", protocol=1.0, wpid=\"2006\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Compact Keyboard K340\", codename=\"K340\", protocol=1.0, wpid=\"2007\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Keyboard MK700\", codename=\"MK700\", protocol=1.0, wpid=\"2008\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Wave Keyboard K350\", codename=\"K350\", protocol=1.0, wpid=\"200A\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Keyboard MK320\", codename=\"MK320\", protocol=1.0, wpid=\"200F\", registers=(Reg.BATTERY_STATUS,))\n_D(\n    \"Wireless Illuminated Keyboard K800\",\n    codename=\"K800\",\n    protocol=1.0,\n    wpid=\"2010\",\n    registers=(Reg.BATTERY_STATUS, Reg.THREE_LEDS),\n)\n_D(\"Wireless Keyboard K520\", codename=\"K520\", protocol=1.0, wpid=\"2011\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Solar Keyboard K750\", codename=\"K750\", protocol=2.0, wpid=\"4002\")\n_D(\"Wireless Keyboard K270 (unifying)\", codename=\"K270\", protocol=2.0, wpid=\"4003\")\n# incorrect _D(\"Wireless Keyboard K360\", codename=\"K360\", protocol=2.0, wpid=\"4004\")\n_D(\"Wireless Keyboard K230\", codename=\"K230\", protocol=2.0, wpid=\"400D\")\n_D(\"Wireless Touch Keyboard K400\", codename=\"K400\", protocol=2.0, wpid=(\"400E\", \"4024\"))\n_D(\"Wireless Keyboard MK270\", codename=\"MK270\", protocol=2.0, wpid=\"4023\")\n_D(\"Illuminated Living-Room Keyboard K830\", codename=\"K830\", protocol=2.0, wpid=\"4032\")\n_D(\"Wireless Touch Keyboard K400 Plus\", codename=\"K400 Plus\", protocol=2.0, wpid=\"404D\")\n_D(\"Wireless Multi-Device Keyboard K780\", codename=\"K780\", protocol=4.5, wpid=\"405B\")\n_D(\"Wireless Keyboard K375s\", codename=\"K375s\", protocol=2.0, wpid=\"4061\")\n_D(\"Craft Advanced Keyboard\", codename=\"Craft\", protocol=4.5, wpid=\"4066\", btid=0xB350)\n_D(\"Wireless Illuminated Keyboard K800 new\", codename=\"K800 new\", protocol=4.5, wpid=\"406E\")\n_D(\"Wireless Keyboard K470\", codename=\"K470\", protocol=4.5, wpid=\"4075\")\n_D(\"MX Keys Keyboard\", codename=\"MX Keys\", protocol=4.5, wpid=\"408A\", btid=0xB35B)\n_D(\n    \"G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard\",\n    codename=\"G915 TKL\",\n    protocol=4.2,\n    wpid=\"408E\",\n    usbid=0xC343,\n)\n_D(\"Illuminated Keyboard\", codename=\"Illuminated\", protocol=1.0, usbid=0xC318, interface=1)\n_D(\"G213 Prodigy Gaming Keyboard\", codename=\"G213\", usbid=0xC336, interface=1)\n_D(\"G512 RGB Mechanical Gaming Keyboard\", codename=\"G512\", usbid=0xC33C, interface=1)\n_D(\"G815 Mechanical Keyboard\", codename=\"G815\", usbid=0xC33F, interface=1)\n_D(\"diNovo Edge Keyboard\", codename=\"diNovo\", protocol=1.0, wpid=\"C714\")\n_D(\"K845 Mechanical Keyboard\", codename=\"K845\", usbid=0xC341, interface=3)\n\n# Mice\n\n_D(\"LX5 Cordless Mouse\", codename=\"LX5\", protocol=1.0, wpid=\"0036\", registers=(Reg.BATTERY_STATUS,))\n_D(\"LX7 Cordless Laser Mouse\", codename=\"LX7\", protocol=1.0, wpid=\"0039\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Wave Mouse M550\", codename=\"M550\", protocol=1.0, wpid=\"003C\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Mouse EX100\", codename=\"EX100m\", protocol=1.0, wpid=\"003F\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Mouse M30\", codename=\"M30\", protocol=1.0, wpid=\"0085\", registers=(Reg.BATTERY_STATUS,))\n_D(\"MX610 Laser Cordless Mouse\", codename=\"MX610\", protocol=1.0, wpid=\"1001\", registers=(Reg.BATTERY_STATUS,))\n_D(\"G7 Cordless Laser Mouse\", codename=\"G7\", protocol=1.0, wpid=\"1002\", registers=(Reg.BATTERY_STATUS,))\n_D(\"V400 Laser Cordless Mouse\", codename=\"V400\", protocol=1.0, wpid=\"1003\", registers=(Reg.BATTERY_STATUS,))\n_D(\"MX610 Left-Handled Mouse\", codename=\"MX610L\", protocol=1.0, wpid=\"1004\", registers=(Reg.BATTERY_STATUS,))\n_D(\"V450 Laser Cordless Mouse\", codename=\"V450\", protocol=1.0, wpid=\"1005\", registers=(Reg.BATTERY_STATUS,))\n_D(\n    \"VX Revolution\",\n    codename=\"VX Revolution\",\n    kind=DEVICE_KIND.mouse,\n    protocol=1.0,\n    wpid=(\"1006\", \"100D\", \"0612\"),\n    registers=(Reg.BATTERY_CHARGE,),\n)\n_D(\n    \"MX Air\",\n    codename=\"MX Air\",\n    protocol=1.0,\n    kind=DEVICE_KIND.mouse,\n    wpid=(\"1007\", \"100E\"),\n    registers=Reg.BATTERY_CHARGE,\n)\n_D(\n    \"MX Revolution\",\n    codename=\"MX Revolution\",\n    protocol=1.0,\n    kind=DEVICE_KIND.mouse,\n    wpid=(\"1008\", \"100C\"),\n    registers=(Reg.BATTERY_CHARGE,),\n)\n_D(\n    \"MX620 Laser Cordless Mouse\",\n    codename=\"MX620\",\n    protocol=1.0,\n    wpid=(\"100A\", \"1016\"),\n    registers=(Reg.BATTERY_CHARGE,),\n)\n_D(\n    \"VX Nano Cordless Laser Mouse\",\n    codename=\"VX Nano\",\n    protocol=1.0,\n    wpid=(\"100B\", \"100F\"),\n    registers=(Reg.BATTERY_CHARGE,),\n)\n_D(\n    \"V450 Nano Cordless Laser Mouse\",\n    codename=\"V450 Nano\",\n    protocol=1.0,\n    wpid=\"1011\",\n    registers=(Reg.BATTERY_CHARGE,),\n)\n_D(\n    \"V550 Nano Cordless Laser Mouse\",\n    codename=\"V550 Nano\",\n    protocol=1.0,\n    wpid=\"1013\",\n    registers=(Reg.BATTERY_CHARGE,),\n)\n_D(\n    \"MX 1100 Cordless Laser Mouse\",\n    codename=\"MX 1100\",\n    protocol=1.0,\n    kind=DEVICE_KIND.mouse,\n    wpid=\"1014\",\n    registers=(Reg.BATTERY_CHARGE,),\n)\n_D(\"Anywhere Mouse MX\", codename=\"Anywhere MX\", protocol=1.0, wpid=\"1017\", registers=(Reg.BATTERY_CHARGE,))\n_D(\n    \"Performance Mouse MX\",\n    codename=\"Performance MX\",\n    protocol=1.0,\n    wpid=\"101A\",\n    registers=(Reg.BATTERY_STATUS, Reg.THREE_LEDS),\n)\n_D(\n    \"Marathon Mouse M705 (M-R0009)\",\n    codename=\"M705 (M-R0009)\",\n    protocol=1.0,\n    wpid=\"101B\",\n    registers=(Reg.BATTERY_CHARGE,),\n)\n_D(\n    \"Wireless Mouse M350\",\n    codename=\"M350\",\n    protocol=1.0,\n    wpid=\"101C\",\n    registers=(Reg.BATTERY_CHARGE,),\n)\n_D(\n    \"Wireless Mouse M505\",\n    codename=\"M505/B605\",\n    protocol=1.0,\n    wpid=\"101D\",\n    registers=(Reg.BATTERY_CHARGE,),\n)\n_D(\n    \"Wireless Mouse M305\",\n    codename=\"M305\",\n    protocol=1.0,\n    wpid=\"101F\",\n    registers=(Reg.BATTERY_STATUS,),\n)\n_D(\n    \"Wireless Mouse M215\",\n    codename=\"M215\",\n    protocol=1.0,\n    wpid=\"1020\",\n)\n_D(\n    \"G700 Gaming Mouse\",\n    codename=\"G700\",\n    protocol=1.0,\n    wpid=\"1023\",\n    usbid=0xC06B,\n    interface=1,\n    registers=(\n        Reg.BATTERY_STATUS,\n        Reg.THREE_LEDS,\n    ),\n)\n_D(\"Wireless Mouse M310\", codename=\"M310\", protocol=1.0, wpid=\"1024\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Wireless Mouse M510\", codename=\"M510\", protocol=1.0, wpid=\"1025\", registers=(Reg.BATTERY_STATUS,))\n_D(\"Fujitsu Sonic Mouse\", codename=\"Sonic\", protocol=1.0, wpid=\"1029\")\n_D(\n    \"G700s Gaming Mouse\",\n    codename=\"G700s\",\n    protocol=1.0,\n    wpid=\"102A\",\n    usbid=0xC07C,\n    interface=1,\n    registers=(\n        Reg.BATTERY_STATUS,\n        Reg.THREE_LEDS,\n    ),\n)\n_D(\"Couch Mouse M515\", codename=\"M515\", protocol=2.0, wpid=\"4007\")\n# _D(\"Wireless Mouse M175\", codename=\"M175\", protocol=2.0, wpid=\"4008\")\n_D(\"Wireless Mouse M325\", codename=\"M325\", protocol=2.0, wpid=\"400A\")\n_D(\"Wireless Mouse M525\", codename=\"M525\", protocol=2.0, wpid=\"4013\")\n_D(\"Wireless Mouse M345\", codename=\"M345\", protocol=2.0, wpid=\"4017\")\n_D(\"Wireless Mouse M187\", codename=\"M187\", protocol=2.0, wpid=\"4019\")\n_D(\"Touch Mouse M600\", codename=\"M600\", protocol=2.0, wpid=\"401A\")\n_D(\"Wireless Mouse M150\", codename=\"M150\", protocol=2.0, wpid=\"4022\")\n_D(\"Wireless Mouse M185\", codename=\"M185\", protocol=2.0, wpid=\"4038\")\n_D(\"Wireless Mouse MX Master\", codename=\"MX Master\", protocol=4.5, wpid=\"4041\", btid=0xB012)\n_D(\"Anywhere Mouse MX 2\", codename=\"Anywhere MX 2\", protocol=4.5, wpid=\"404A\")\n_D(\"Wireless Mouse M510\", codename=\"M510v2\", protocol=2.0, wpid=\"4051\")\n_D(\"Wireless Mouse M185 new\", codename=\"M185n\", protocol=4.5, wpid=\"4054\")\n_D(\"Wireless Mouse M185/M235/M310\", codename=\"M185/M235/M310\", protocol=4.5, wpid=\"4055\")\n_D(\"Wireless Mouse MX Master 2S\", codename=\"MX Master 2S\", protocol=4.5, wpid=\"4069\", btid=0xB019)\n_D(\"Multi Device Silent Mouse M585/M590\", codename=\"M585/M590\", protocol=4.5, wpid=\"406B\")\n_D(\n    \"Marathon Mouse M705 (M-R0073)\",\n    codename=\"M705 (M-R0073)\",\n    protocol=4.5,\n    wpid=\"406D\",\n)\n_D(\"MX Vertical Wireless Mouse\", codename=\"MX Vertical\", protocol=4.5, wpid=\"407B\", btid=0xB020, usbid=0xC08A)\n_D(\"Wireless Mouse Pebble M350\", codename=\"Pebble\", protocol=2.0, wpid=\"4080\")\n_D(\"MX Master 3 Wireless Mouse\", codename=\"MX Master 3\", protocol=4.5, wpid=\"4082\", btid=0xB023)\n_D(\"PRO X Wireless\", kind=\"mouse\", codename=\"PRO X\", wpid=\"4093\", usbid=0xC094)\n\n_D(\"G9 Laser Mouse\", codename=\"G9\", usbid=0xC048, interface=1, protocol=1.0)\n_D(\"G9x Laser Mouse\", codename=\"G9x\", usbid=0xC066, interface=1, protocol=1.0)\n_D(\"G502 Gaming Mouse\", codename=\"G502\", usbid=0xC07D, interface=1)\n_D(\"G402 Gaming Mouse\", codename=\"G402\", usbid=0xC07E, interface=1)\n_D(\"G900 Chaos Spectrum Gaming Mouse\", codename=\"G900\", usbid=0xC081)\n_D(\"G403 Gaming Mouse\", codename=\"G403\", usbid=0xC082)\n_D(\"G903 Lightspeed Gaming Mouse\", codename=\"G903\", usbid=0xC086)\n_D(\"G703 Lightspeed Gaming Mouse\", codename=\"G703\", usbid=0xC087)\n_D(\"GPro Gaming Mouse\", codename=\"GPro\", usbid=0xC088)\n_D(\"G502 SE Hero Gaming Mouse\", codename=\"G502 Hero\", usbid=0xC08B, interface=1)\n_D(\"G502 Lightspeed Gaming Mouse\", codename=\"G502 Lightspeed\", usbid=0xC08D)\n_D(\"MX518 Gaming Mouse\", codename=\"MX518\", usbid=0xC08E, interface=1)\n_D(\"G703 Hero Gaming Mouse\", codename=\"G703 Hero\", usbid=0xC090)\n_D(\"G903 Hero Gaming Mouse\", codename=\"G903 Hero\", usbid=0xC091)\n_D(None, kind=DEVICE_KIND.mouse, usbid=0xC092, interface=1)  # two mice share this ID\n_D(\"M500S Mouse\", codename=\"M500S\", usbid=0xC093, interface=1)\n# _D('G600 Gaming Mouse', codename='G600 Gaming', usbid=0xc24a, interface=1) # not an HID++ device\n_D(\"G500 Gaming Mouse\", codename=\"G500 Gaming\", usbid=0xC068, interface=1, protocol=1.0)\n_D(\"G500s Gaming Mouse\", codename=\"G500s Gaming\", usbid=0xC24E, interface=1, protocol=1.0)\n_D(\"G502 Proteus Spectrum Optical Mouse\", codename=\"G502 Proteus Spectrum\", usbid=0xC332, interface=1)\n_D(\"Logitech PRO Gaming Keyboard\", codename=\"PRO Gaming Keyboard\", usbid=0xC339, interface=1)\n\n_D(\"Logitech MX Revolution Mouse M-RCL 124\", codename=\"M-RCL 124\", btid=0xB007, interface=1)\n\n# Trackballs\n\n_D(\"Wireless Trackball M570\", codename=\"M570\")\n\n# Touchpads\n\n_D(\"Wireless Touchpad\", codename=\"Wireless Touch\", protocol=2.0, wpid=\"4011\")\n_D(\"Wireless Rechargeable Touchpad T650\", codename=\"T650\", protocol=2.0, wpid=\"4101\")\n_D(\n    \"G Powerplay\", codename=\"Powerplay\", protocol=2.0, kind=DEVICE_KIND.touchpad, wpid=\"405F\"\n)  # To override self-identification\n\n# Headset\n\n_D(\"G533 Gaming Headset\", codename=\"G533 Headset\", protocol=2.0, interface=3, kind=DEVICE_KIND.headset, usbid=0x0A66)\n_D(\"G535 Gaming Headset\", codename=\"G535 Headset\", protocol=2.0, interface=3, kind=DEVICE_KIND.headset, usbid=0x0AC4)\n_D(\"G935 Gaming Headset\", codename=\"G935 Headset\", protocol=2.0, interface=3, kind=DEVICE_KIND.headset, usbid=0x0A87)\n_D(\"G733 Gaming Headset\", codename=\"G733 Headset\", protocol=2.0, interface=3, kind=DEVICE_KIND.headset, usbid=0x0AB5)\n_D(\n    \"G733 Gaming Headset\",\n    codename=\"G733 Headset New\",\n    protocol=2.0,\n    interface=3,\n    kind=DEVICE_KIND.headset,\n    usbid=0x0AFE,\n)\n_D(\n    \"PRO X Wireless Gaming Headset\",\n    codename=\"PRO Headset\",\n    protocol=2.0,\n    interface=3,\n    kind=DEVICE_KIND.headset,\n    usbid=0x0ABA,\n)\n"
  },
  {
    "path": "lib/logitech_receiver/desktop_notifications.py",
    "content": "## Copyright (C) 2024 Solaar contributors\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n\"\"\"Implements the desktop notification service.\"\"\"\n\nimport importlib\nimport logging\n\nlogger = logging.getLogger(__name__)\n\n\ndef notifications_available():\n    \"\"\"Checks if notification service is available.\"\"\"\n    notifications_supported = False\n    try:\n        import gi\n\n        gi.require_version(\"Notify\", \"0.7\")\n        gi.require_version(\"Gtk\", \"3.0\")\n\n        importlib.util.find_spec(\"gi.repository.GLib\")\n        importlib.util.find_spec(\"gi.repository.Gtk\")\n        importlib.util.find_spec(\"gi.repository.Notify\")\n\n        notifications_supported = True\n    except ValueError as e:\n        logger.warning(f\"Notification service is not available: {e}\")\n    return notifications_supported\n\n\navailable = notifications_available()\n\nif available:\n    from gi.repository import GLib\n    from gi.repository import Gtk\n    from gi.repository import Notify\n\n    # cache references to shown notifications here to allow reuse\n    _notifications = {}\n    _ICON_LISTS = {}\n\n    def init():\n        \"\"\"Initialize desktop notifications.\"\"\"\n        global available\n        if available:\n            if not Notify.is_initted():\n                if logger.isEnabledFor(logging.INFO):\n                    logger.info(\"starting desktop notifications\")\n                try:\n                    return Notify.init(\"solaar\")  # replace with better name later\n                except Exception:\n                    logger.exception(\"initializing desktop notifications\")\n                    available = False\n        return available and Notify.is_initted()\n\n    def uninit():\n        \"\"\"Stop desktop notifications.\"\"\"\n        if available and Notify.is_initted():\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"stopping desktop notifications\")\n            _notifications.clear()\n            Notify.uninit()\n\n    def show(dev, message: str, icon=None):\n        \"\"\"Show a notification with title and text.\"\"\"\n        if available and (Notify.is_initted() or init()):\n            summary = dev.name\n            n = _notifications.get(summary)  # reuse notification of same name\n            if n is None:\n                n = _notifications[summary] = Notify.Notification()\n            icon_name = device_icon_name(dev.name, dev.kind) if icon is None else icon\n            n.update(summary, message, icon_name)\n            n.set_urgency(Notify.Urgency.NORMAL)\n            n.set_hint(\"desktop-entry\", GLib.Variant(\"s\", \"solaar\"))  # replace with better name late\n            try:\n                return n.show()\n            except Exception:\n                logger.exception(f\"showing {n}\")\n\n    def device_icon_list(name=\"_\", kind=None):\n        icon_list = _ICON_LISTS.get(name)\n        if icon_list is None:\n            # names of possible icons, in reverse order of likelihood\n            # the theme will hopefully pick up the most appropriate\n            icon_list = [\"preferences-desktop-peripherals\"]\n            kind = str(kind)\n            if kind:\n                if kind == \"numpad\":\n                    icon_list += (\"input-keyboard\", \"input-dialpad\")\n                elif kind == \"touchpad\":\n                    icon_list += (\"input-mouse\", \"input-tablet\")\n                elif kind == \"trackball\":\n                    icon_list += (\"input-mouse\",)\n                elif kind == \"headset\":\n                    icon_list += (\"audio-headphones\", \"audio-headset\")\n                icon_list += (f\"input-{kind}\",)\n            _ICON_LISTS[name] = icon_list\n        return icon_list\n\n    def device_icon_name(name, kind=None):\n        _default_theme = Gtk.IconTheme.get_default()\n        icon_list = device_icon_list(name, kind)\n        for n in reversed(icon_list):\n            if _default_theme.has_icon(n):\n                return n\n\nelse:\n\n    def init():\n        return False\n\n    def uninit():\n        return None\n\n    def show(dev, reason=None):\n        return None\n"
  },
  {
    "path": "lib/logitech_receiver/device.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom __future__ import annotations\n\nimport errno\nimport logging\nimport threading\nimport time\nimport typing\n\nfrom typing import Callable\nfrom typing import Optional\nfrom typing import Protocol\n\nfrom solaar import configuration\n\nfrom . import descriptors\nfrom . import exceptions\nfrom . import hidpp10\nfrom . import hidpp10_constants\nfrom . import hidpp20\nfrom . import settings\nfrom . import settings_templates\nfrom .common import Alert\nfrom .common import Battery\nfrom .hidpp10_constants import NotificationFlag\nfrom .hidpp20_constants import SupportedFeature\n\nif typing.TYPE_CHECKING:\n    from logitech_receiver import common\n\nlogger = logging.getLogger(__name__)\n\n_hidpp10 = hidpp10.Hidpp10()\n_hidpp20 = hidpp20.Hidpp20()\n\n\nclass LowLevelInterface(Protocol):\n    def open_path(self, path) -> int:\n        ...\n\n    def find_paired_node(self, receiver_path: str, index: int, timeout: int):\n        ...\n\n    def ping(self, handle, number, long_message: bool):\n        ...\n\n    def request(self, handle, devnumber, request_id, *params, **kwargs):\n        ...\n\n    def close(self, handle, *args, **kwargs) -> bool:\n        ...\n\n\ndef create_device(low_level: LowLevelInterface, device_info, setting_callback=None):\n    \"\"\"Opens a Logitech Device found attached to the machine, by Linux device path.\n    :returns: An open file handle for the found receiver, or None.\n    \"\"\"\n    try:\n        handle = low_level.open_path(device_info.path)\n        if handle:\n            # a direct connected device might not be online (as reported by user)\n            return Device(\n                low_level,\n                None,\n                None,\n                None,\n                handle=handle,\n                device_info=device_info,\n                setting_callback=setting_callback,\n            )\n    except OSError as e:\n        logger.exception(\"open %s\", device_info)\n        if e.errno == errno.EACCES:\n            raise e\n    except Exception as e:\n        logger.exception(\"open %s\", device_info)\n        raise e\n\n\nclass Device:\n    instances = []\n    read_register: Callable = hidpp10.read_register\n    write_register: Callable = hidpp10.write_register\n\n    def __init__(\n        self,\n        low_level: LowLevelInterface,\n        receiver,\n        number,\n        online,\n        pairing_info=None,\n        handle=None,\n        device_info=None,\n        setting_callback=None,\n    ):\n        assert receiver or device_info\n        if receiver:\n            assert 0 < number <= 15  # some receivers have devices past their max # of devices\n        self.low_level = low_level\n        self.number = number  # will be None at this point for directly connected devices\n        self.online = online  # is the device online? - gates many atempts to contact the device\n        self.descriptor = None\n        self.isDevice = True  # some devices act as receiver so we need a property to distinguish them\n        self.may_unpair = False\n        self.receiver = receiver\n        self.handle = handle\n        self.path = device_info.path if device_info else None\n        self.product_id = device_info.product_id if device_info else None\n        self.hidpp_short = device_info.hidpp_short if device_info else None\n        self.hidpp_long = device_info.hidpp_long if device_info else None\n        self.bluetooth = device_info.bus_id == 0x0005 if device_info else False  # Bluetooth needs long messages\n        self.hid_serial = device_info.serial if device_info else None\n        self.setting_callback = setting_callback  # for changes to settings\n        self.status_callback = None  # for changes to other potentially visible aspects\n        self.wpid = pairing_info[\"wpid\"] if pairing_info else None  # the Wireless PID is unique per device model\n        self._kind = pairing_info[\"kind\"] if pairing_info else None  # mouse, keyboard, etc (see hidpp10.DEVICE_KIND)\n        self._serial = pairing_info[\"serial\"] if pairing_info else None  # serial number (an 8-char hex string)\n        self._polling_rate = pairing_info[\"polling\"] if pairing_info else None\n        self._power_switch = pairing_info[\"power_switch\"] if pairing_info else None\n        self._name = None  # the full name of the model\n        self._codename = None  # Unifying peripherals report a codename.\n        self._protocol = None  # HID++ protocol version, 1.0 or 2.0\n        self._unitId = None  # unit id (distinguishes within a model - generally the same as serial)\n        self._modelId = None  # model id (contains identifiers for the transports of the device)\n        self._tid_map = None  # map from transports to product identifiers\n        self._persister = None  # persister holds settings\n        self._led_effects = self._firmware = self._keys = self._remap_keys = self._gestures = self._force_buttons = None\n        self._profiles = self._backlight = self._settings = None\n        self.registers = []\n        self.notification_flags = None\n        self.battery_info = None\n        self.link_encrypted = None\n        self._active = None  # lags self.online - is used to help determine when to setup devices\n        self.present = True  # used for devices that are integral with their receiver but that separately be disconnected\n\n        self._feature_settings_checked = False\n        self._gestures_lock = threading.Lock()\n        self._settings_lock = threading.Lock()\n        self._persister_lock = threading.Lock()\n        self._simple_lock = threading.Lock()\n        self._notification_handlers = {}  # See `add_notification_handler`\n        self.cleanups = []  # functions to run on the device when it is closed\n\n        if not self.path:\n            self.path = self.low_level.find_paired_node(receiver.path, number, 1) if receiver else None\n        if not self.handle:\n            try:\n                self.handle = self.low_level.open_path(self.path) if self.path else None\n            except Exception:  # maybe the device wasn't set up\n                try:\n                    time.sleep(1)\n                    self.handle = self.low_level.open_path(self.path) if self.path else None\n                except Exception:  # give up\n                    self.handle = None  # should this give up completely?\n\n        if receiver:\n            if not self.wpid:\n                raise exceptions.NoSuchDevice(\n                    number=number, receiver=receiver, error=\"no wpid for device connected to receiver\"\n                )\n            self.descriptor = descriptors.get_wpid(self.wpid)\n            if self.descriptor is None:\n                codename = self.receiver.device_codename(self.number)  # Last chance to get a descriptor, may fail\n                if codename:\n                    self._codename = codename\n                    self.descriptor = descriptors.get_codename(self._codename)\n        else:\n            self.descriptor = (\n                descriptors.get_btid(self.product_id) if self.bluetooth else descriptors.get_usbid(self.product_id)\n            )\n            # for direct-connected devices get 'number' from descriptor protocol else use 0xFF\n            self.number = 0x00 if self.descriptor and self.descriptor.protocol and self.descriptor.protocol < 2.0 else 0xFF\n            try:  # determine whether a direct-connected device is online\n                self.ping()\n            except exceptions.NoSuchDevice as e:\n                if self.number == 0xFF:  # guessed wrong number?\n                    self.number = 0x00\n                    self.ping()\n                else:\n                    raise e\n\n        if self.descriptor:\n            self._name = self.descriptor.name\n            if self._codename is None:\n                self._codename = self.descriptor.codename\n            if self._kind is None:\n                self._kind = self.descriptor.kind\n            self._protocol = self.descriptor.protocol if self.descriptor.protocol else None\n            self.registers = self.descriptor.registers if self.descriptor.registers else []\n\n        if self._protocol is not None:\n            self.features = {} if self._protocol < 2.0 else hidpp20.FeaturesArray(self)\n        else:\n            self.features = hidpp20.FeaturesArray(self)  # may be a 2.0 device; if not, it will fix itself later\n\n        Device.instances.append(self)\n\n    def find(self, id):  # find a device by serial number or unit ID or name or codename\n        assert id, \"need id to find a device\"\n        for device in Device.instances:\n            if device.online and (device.unitId == id or device.serial == id or device.name == id or device.codename == id):\n                return device\n\n    @property\n    def protocol(self):\n        if not self._protocol:\n            try:\n                self.ping()\n            except exceptions.NoSuchDevice:\n                logger.warning(\"device %s inaccessible - no protocol set\", self)\n        return self._protocol or 0\n\n    @property\n    def codename(self):\n        if not self._codename:\n            if self.online and self.protocol >= 2.0:\n                self._codename = _hidpp20.get_friendly_name(self)\n                if not self._codename and self.name:\n                    names = self.name.split(\" \")\n                    self._codename = names[1 if len(names) > 1 and names[0] == \"Logitech\" else 0]\n            if not self._codename and self.receiver:\n                codename = self.receiver.device_codename(self.number)\n                if codename:\n                    self._codename = codename\n                elif self.protocol < 2.0:\n                    self._codename = \"? (%s)\" % (self.wpid or self.product_id)\n        return self._codename or f\"?? ({self.wpid or self.product_id})\"\n\n    @property\n    def name(self):\n        if not self._name:\n            with self._simple_lock:\n                if self._name is None:\n                    if self.online and self.protocol >= 2.0:\n                        self._name = _hidpp20.get_name(self)\n        return self._name or self._codename or f\"Unknown device {self.wpid or self.product_id}\"\n\n    def get_ids(self):\n        ids = _hidpp20.get_ids(self)\n        if ids:\n            self._unitId, self._modelId, self._tid_map = ids\n            if logger.isEnabledFor(logging.INFO) and self._serial and self._serial != self._unitId:\n                logger.info(\"%s: unitId %s does not match serial %s\", self, self._unitId, self._serial)\n\n    @property\n    def unitId(self):\n        if not self._unitId and self.online and self.protocol >= 2.0:\n            self.get_ids()\n        return self._unitId\n\n    @property\n    def modelId(self):\n        if not self._modelId and self.online and self.protocol >= 2.0:\n            self.get_ids()\n        return self._modelId\n\n    @property\n    def tid_map(self):\n        if not self._tid_map and self.online and self.protocol >= 2.0:\n            self.get_ids()\n        return self._tid_map\n\n    @property\n    def kind(self):\n        if not self._kind and self.online and self.protocol >= 2.0:\n            self._kind = _hidpp20.get_kind(self)\n        return self._kind or \"?\"\n\n    @property\n    def firmware(self) -> tuple[common.FirmwareInfo]:\n        if self._firmware is None and self.online:\n            if self.protocol >= 2.0:\n                self._firmware = _hidpp20.get_firmware(self)\n            else:\n                self._firmware = _hidpp10.get_firmware(self)\n        return self._firmware or ()\n\n    @property\n    def serial(self):\n        return self._serial or \"\"\n\n    @property\n    def id(self):\n        return self.unitId or self.serial\n\n    @property\n    def power_switch_location(self):\n        return self._power_switch\n\n    @property\n    def polling_rate(self):\n        if self.online and self.protocol >= 2.0:\n            rate = _hidpp20.get_polling_rate(self)\n            self._polling_rate = rate if rate else self._polling_rate\n        return self._polling_rate\n\n    @property\n    def led_effects(self):\n        if not self._led_effects and self.online and self.protocol >= 2.0:\n            if SupportedFeature.COLOR_LED_EFFECTS in self.features:\n                self._led_effects = hidpp20.LEDEffectsInfo(self)\n            elif SupportedFeature.RGB_EFFECTS in self.features:\n                self._led_effects = hidpp20.RGBEffectsInfo(self)\n        return self._led_effects\n\n    @property\n    def keys(self):\n        if not self._keys:\n            if self.online and self.protocol >= 2.0:\n                self._keys = _hidpp20.get_keys(self) or ()\n        return self._keys\n\n    @property\n    def remap_keys(self):\n        if self._remap_keys is None:\n            if self.online and self.protocol >= 2.0:\n                self._remap_keys = _hidpp20.get_remap_keys(self) or ()\n        return self._remap_keys\n\n    @property\n    def gestures(self):\n        if self._gestures is None:\n            with self._gestures_lock:\n                if self._gestures is None:\n                    if self.online and self.protocol >= 2.0:\n                        self._gestures = _hidpp20.get_gestures(self) or ()\n        return self._gestures\n\n    @property\n    def backlight(self):\n        if self._backlight is None:\n            if self.online and self.protocol >= 2.0:\n                self._backlight = _hidpp20.get_backlight(self)\n        return self._backlight\n\n    @property\n    def profiles(self):\n        if self._profiles is None:\n            if self.online and self.protocol >= 2.0:\n                self._profiles = _hidpp20.get_profiles(self)\n        return self._profiles\n\n    def force_buttons(self):\n        if self._force_buttons is None:\n            if self.online and self.protocol >= 2.0:\n                self._force_buttons = _hidpp20.get_force_buttons(self) or ()\n        return self._force_buttons\n\n    def set_configuration(self, configuration_, no_reply=False):\n        if self.online and self.protocol >= 2.0:\n            _hidpp20.config_change(self, configuration_, no_reply=no_reply)\n\n    def reset(self, no_reply=False):\n        self.set_configuration(0, no_reply)\n\n    @property\n    def persister(self):\n        if not self._persister:\n            with self._persister_lock:\n                if not self._persister:\n                    self._persister = configuration.persister(self)\n        return self._persister\n\n    @property\n    def settings(self):\n        if not self._settings:\n            with self._settings_lock:\n                if not self._settings:\n                    settings = []\n                    if self.persister and self.descriptor and self.descriptor.settings:\n                        for sclass in self.descriptor.settings:\n                            try:\n                                setting = sclass.build(self)\n                            except Exception as e:  # Do nothing if the device is offline\n                                setting = None\n                                if self.online:\n                                    raise e\n                            if setting is not None:\n                                settings.append(setting)\n                    self._settings = settings\n        if not self._feature_settings_checked:\n            with self._settings_lock:\n                if not self._feature_settings_checked:\n                    self._feature_settings_checked = settings_templates.check_feature_settings(self, self._settings)\n        return self._settings\n\n    def battery(self):  # None  or  level, next, status, voltage\n        if self.protocol < 2.0:\n            return _hidpp10.get_battery(self)\n        else:\n            battery_feature = self.persister.get(\"_battery\", None) if self.persister else None\n            if battery_feature != 0:\n                result = _hidpp20.get_battery(self, battery_feature)\n                try:\n                    feature, battery = result\n                    if self.persister and battery_feature is None:\n                        self.persister[\"_battery\"] = feature.value\n                    return battery\n                except Exception:\n                    if self.persister and battery_feature is None and result is not None and result != 0:\n                        self.persister[\"_battery\"] = result.value\n\n    def set_battery_info(self, info):\n        \"\"\"Update battery information for device, calling changed callback if necessary\"\"\"\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: battery %s, %s\", self, info.level, info.status)\n        if info.level is None and self.battery_info:  # use previous level if missing from new information\n            info.level = self.battery_info.level\n\n        changed = self.battery_info != info\n        self.battery_info, old_info = info, self.battery_info\n        if old_info is None:\n            old_info = Battery(None, None, None, None)\n\n        alert, reason = Alert.NONE, None\n        if not info.ok():\n            logger.warning(\"%s: battery %d%%, ALERT %s\", self, info.level, info.status)\n            if old_info.status != info.status:\n                alert = Alert.NOTIFICATION | Alert.ATTENTION\n            reason = info.to_str()\n\n        if changed or reason:\n            # update the leds on the device, if any\n            _hidpp10.set_3leds(self, info.level, charging=info.charging(), warning=bool(alert))\n            self.changed(active=True, alert=alert, reason=reason)\n\n    # Retrieve and regularize battery status\n    def read_battery(self):\n        if self.online:\n            battery = self.battery()\n            self.set_battery_info(battery if battery is not None else Battery(None, None, None, None))\n\n    def changed(self, active=None, alert=Alert.NONE, reason=None, push=False):\n        \"\"\"The status of the device had changed, so invoke the status callback.\n        Also push notifications and settings to the device when necessary.\"\"\"\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"device %d changing: active=%s %s present=%s\", self.number, active, self._active, self.present)\n        if active is not None:\n            self.online = active\n            was_active, self._active = self._active, active\n            if active:\n                # Push settings for new devices when devices request software reconfiguration\n                # and when devices become active if they don't have wireless device status feature,\n                if (\n                    was_active is None\n                    or not was_active\n                    or push\n                    and (not self.features or SupportedFeature.WIRELESS_DEVICE_STATUS not in self.features)\n                ):\n                    if logger.isEnabledFor(logging.INFO):\n                        logger.info(\"%s pushing device settings %s\", self, self.settings)\n                    settings.apply_all_settings(self)\n                if not was_active:\n                    if self.protocol < 2.0:  # Make sure to set notification flags on the device\n                        self.notification_flags = self.enable_connection_notifications()\n                    else:\n                        self.set_configuration(0x11)  # signal end of configuration\n                    self.read_battery()  # battery information may have changed so try to read it now\n            elif was_active and self.receiver:  # need to set configuration pending flag in receiver\n                hidpp10.set_configuration_pending_flags(self.receiver, 0xFF)\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"device %d changed: active=%s %s\", self.number, self._active, self.battery_info)\n        if self.status_callback is not None:\n            self.status_callback(self, alert, reason)\n\n    def enable_connection_notifications(self, enable=True):\n        \"\"\"Enable or disable device (dis)connection notifications on this\n        receiver.\"\"\"\n        if not bool(self.receiver) or self.protocol >= 2.0:\n            return False\n\n        if enable:\n            set_flag_bits = NotificationFlag.BATTERY_STATUS | NotificationFlag.UI | NotificationFlag.CONFIGURATION_COMPLETE\n        else:\n            set_flag_bits = 0\n        ok = _hidpp10.set_notification_flags(self, set_flag_bits)\n        if not ok:\n            logger.warning(\"%s: failed to %s device notifications\", self, \"enable\" if enable else \"disable\")\n\n        flag_bits = _hidpp10.get_notification_flags(self)\n        if logger.isEnabledFor(logging.INFO):\n            if flag_bits is None:\n                flag_names = None\n            else:\n                flag_names = hidpp10_constants.NotificationFlag.flag_names(flag_bits)\n            is_enabled = \"enabled\" if enable else \"disabled\"\n            logger.info(f\"{self}: device notifications {is_enabled} {flag_names}\")\n        return flag_bits if ok else None\n\n    def add_notification_handler(self, id: str, fn):\n        \"\"\"Adds the notification handling callback `fn` to this device under name `id`.\n        If a callback has already been registered under this name, it's replaced with\n        the argument.\n        The callback will be invoked whenever the device emits an event message, and\n        the resulting notification hasn't been handled by another handler on this device\n        (order is not guaranteed, so handlers should not overlap in functionality).\n        The callback should have type `(PairedDevice, Notification) -> Optional[bool]`.\n        It should return `None` if it hasn't handled the notification, return `True`\n        if it did so successfully and return `False` if an error should be reported\n        (malformed notification, etc).\n        \"\"\"\n        self._notification_handlers[id] = fn\n\n    def remove_notification_handler(self, id: str):\n        \"\"\"Unregisters the notification handler under name `id`.\"\"\"\n\n        if id not in self._notification_handlers and logger.isEnabledFor(logging.INFO):\n            logger.info(f\"Tried to remove nonexistent notification handler {id} from device {self}.\")\n        else:\n            del self._notification_handlers[id]\n\n    def handle_notification(self, n) -> Optional[bool]:\n        for h in self._notification_handlers.values():\n            ret = h(self, n)\n            if ret is not None:\n                return ret\n        return None\n\n    def request(self, request_id, *params, no_reply=False):\n        if self:\n            long = self.hidpp_long is True or (\n                self.hidpp_long is None and (self.bluetooth or self._protocol is not None and self._protocol >= 2.0)\n            )\n            return self.low_level.request(\n                self.handle or (self.receiver.handle if self.receiver else None),\n                self.number,\n                request_id,\n                *params,\n                no_reply=no_reply,\n                long_message=long,\n                protocol=self.protocol,\n            )\n\n    def feature_request(self, feature, function=0x00, *params, no_reply=False):\n        if self.protocol >= 2.0:\n            return hidpp20.feature_request(self, feature, function, *params, no_reply=no_reply)\n\n    def ping(self):\n        \"\"\"Checks if the device is online and present, returns True of False.\n        Some devices are integral with their receiver but may not be present even if the receiver responds to ping.\"\"\"\n        long = self.hidpp_long is True or (\n            self.hidpp_long is None and (self.bluetooth or self._protocol is not None and self._protocol >= 2.0)\n        )\n        handle = self.handle or self.receiver.handle\n        try:\n            protocol = self.low_level.ping(handle, self.number, long_message=long)\n        except exceptions.NoReceiver:  # if ping fails, device is offline\n            protocol = None\n        self.online = protocol is not None and self.present\n        if protocol:\n            self._protocol = protocol\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"pinged %s: online %s protocol %s present %s\", self.number, self.online, protocol, self.present)\n        return self.online\n\n    def notify_devices(self):  # no need to notify, as there are none\n        pass\n\n    def close(self):\n        handle, self.handle = self.handle, None\n        if self in Device.instances:\n            Device.instances.remove(self)\n        if hasattr(self, \"cleanups\"):\n            for cleanup in self.cleanups:\n                cleanup(self)\n        return handle and self.low_level.close(handle)\n\n    def __index__(self):\n        return self.number\n\n    __int__ = __index__\n\n    def __eq__(self, other):\n        return other is not None and self._kind == other._kind and self.wpid == other.wpid\n\n    def __ne__(self, other):\n        return other is None or self.kind != other.kind or self.wpid != other.wpid\n\n    def __hash__(self):\n        return self.wpid.__hash__()\n\n    def __bool__(self):\n        return self.wpid is not None and self.number in self.receiver if self.receiver else self.handle is not None\n\n    __nonzero__ = __bool__\n\n    def status_string(self):\n        return self.battery_info.to_str() if self.battery_info is not None else \"\"\n\n    def __str__(self):\n        try:\n            name = self._name or self._codename or \"?\"\n        except exceptions.NoSuchDevice:\n            name = \"name not available\"\n        return f\"<Device({int(self.number)},{self.wpid or self.product_id},{name},{self.serial})>\"\n\n    __repr__ = __str__\n\n    def __del__(self):\n        self.close()\n"
  },
  {
    "path": "lib/logitech_receiver/diversion.py",
    "content": "## Copyright (C) 2020 Peter Patel-Schneider\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom __future__ import annotations\n\nimport ctypes\nimport logging\nimport math\nimport numbers\nimport os\nimport platform\nimport socket\nimport struct\nimport subprocess\nimport sys\nimport time\nimport typing\n\nfrom typing import Any\nfrom typing import Dict\nfrom typing import Tuple\n\nimport gi\nimport psutil\nimport yaml\n\nfrom keysyms import keysymdef\n\n# There is no evdev on macOS or Windows. Diversion will not work without\n# it but other Solaar functionality is available.\nif platform.system() in (\"Darwin\", \"Windows\"):\n    evdev = None\nelse:\n    import evdev\n\nfrom .common import NamedInt\nfrom .hidpp20 import SupportedFeature\nfrom .special_keys import CONTROL\n\ngi.require_version(\"Gdk\", \"3.0\")  # isort:skip\nfrom gi.repository import Gdk, GLib  # NOQA: E402 # isort:skip\n\nif typing.TYPE_CHECKING:\n    from .base import HIDPPNotification\n\nlogger = logging.getLogger(__name__)\n\n#\n# See docs/rules.md for documentation\n#\n# Several capabilities of rules depend on aspects of GDK, X11, or XKB\n# As the Solaar GUI uses GTK, Glib and GDK are always available and are obtained from gi.repository\n#\n# Process condition depends on X11 from python-xlib, and is probably not possible at all in Wayland\n# MouseProcess condition depends on X11 from python-xlib, and is probably not possible at all in Wayland\n# Modifiers condition depends only on GDK\n# KeyPress action determines whether a keysym is a currently-down modifier using get_modifier_mapping from python-xlib;\n#   under Wayland no modifier keys are considered down so all modifier keys are pressed, potentially leading to problems\n# KeyPress action translates key names to keysysms using the local file described for GUI keyname determination\n# KeyPress action gets the current keyboard group using XkbGetState from libX11.so using ctypes definitions\n#   under Wayland the keyboard group is None resulting in using the first keyboard group\n# KeyPress action translates keysyms to keycodes using the GDK keymap\n# KeyPress, MouseScroll, and MouseClick actions use uinput.\n# For uinput to work the user must have write access for /dev/uinput.\n# The Solaar udev rule should set this up\n# Otherwise run  sudo setfacl -m u:${user}:rw /dev/uinput\n#\n# Rule GUI keyname determination uses a local file generated\n#   from http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h\n#   and http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h\n# because there does not seem to be a non-X11 file for this set of key names\n\n# Setting up is complex because there are several systems that each provide partial facilities:\n# GDK - always available (when running with a window system) but only provides access to keymap\n# X11 - provides access to active process and process with window under mouse and current modifier keys\n# uinput and evdev - provides input simulation\n\nXK_KEYS: Dict[str, int] = keysymdef.key_symbols\n\n# Event codes - can't use Xlib.X codes because Xlib might not be available\n_KEY_RELEASE = 0\n_KEY_PRESS = 1\n_BUTTON_RELEASE = 2\n_BUTTON_PRESS = 3\n\nCLICK, DEPRESS, RELEASE = \"click\", \"depress\", \"release\"\n\ngdisplay = Gdk.Display.get_default()  # can be None if Solaar is run without a full window system\ngkeymap = Gdk.Keymap.get_for_display(gdisplay) if gdisplay else None\nif logger.isEnabledFor(logging.INFO):\n    logger.info(\"GDK Keymap %sset up\", \"\" if gkeymap else \"not \")\n\nwayland = os.getenv(\"WAYLAND_DISPLAY\")  # is this Wayland?\nif wayland:\n    logger.warning(\n        \"rules cannot access modifier keys in Wayland, \"\n        \"accessing process only works on GNOME with Solaar Gnome extension installed\"\n    )\n\ntry:\n    _x11 = None  # X11 might be available\nexcept Exception:\n    _x11 = False  # X11 is not available\n\n# Globals\nxdisplay = None\n\n\nXkbdisplay = None  # xkb might be available\nX11Lib = None\n\nmodifier_keycodes = []\nXkbUseCoreKbd = 0x100\nNET_ACTIVE_WINDOW = None\nNET_WM_PID = None\nWM_CLASS = None\n\n\nudevice = None\n\nkey_down = None\nkey_up = None\n\nkeys_down = []\ng_keys_down = 0\nm_keys_down = 0\nmr_key_down = False\nthumb_wheel_displacement = 0\n\n_dbus_interface = None\n\n\nclass XkbDisplay(ctypes.Structure):\n    \"\"\"opaque struct\"\"\"\n\n\nclass XkbStateRec(ctypes.Structure):\n    _fields_ = [\n        (\"group\", ctypes.c_ubyte),\n        (\"locked_group\", ctypes.c_ubyte),\n        (\"base_group\", ctypes.c_ushort),\n        (\"latched_group\", ctypes.c_ushort),\n        (\"mods\", ctypes.c_ubyte),\n        (\"base_mods\", ctypes.c_ubyte),\n        (\"latched_mods\", ctypes.c_ubyte),\n        (\"locked_mods\", ctypes.c_ubyte),\n        (\"compat_state\", ctypes.c_ubyte),\n        (\"grab_mods\", ctypes.c_ubyte),\n        (\"compat_grab_mods\", ctypes.c_ubyte),\n        (\"lookup_mods\", ctypes.c_ubyte),\n        (\"compat_lookup_mods\", ctypes.c_ubyte),\n        (\"ptr_buttons\", ctypes.c_ushort),\n    ]  # something strange is happening here but it is not being used\n\n\ndef x11_setup():\n    global _x11, xdisplay, modifier_keycodes, NET_ACTIVE_WINDOW, NET_WM_PID, WM_CLASS\n    if _x11 is not None:\n        return _x11\n    try:\n        from Xlib.display import Display\n\n        xdisplay = Display()\n        modifier_keycodes = xdisplay.get_modifier_mapping()  # there should be a way to do this in Gdk\n        NET_ACTIVE_WINDOW = xdisplay.intern_atom(\"_NET_ACTIVE_WINDOW\")\n        NET_WM_PID = xdisplay.intern_atom(\"_NET_WM_PID\")\n        WM_CLASS = xdisplay.intern_atom(\"WM_CLASS\")\n        _x11 = True  # X11 available\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"X11 library loaded and display set up\")\n    except Exception:\n        logger.warning(\"X11 not available - some rule capabilities inoperable\", exc_info=sys.exc_info())\n        _x11 = False\n    return _x11\n\n\ndef gnome_dbus_interface_setup():\n    global _dbus_interface\n    if _dbus_interface is not None:\n        return _dbus_interface\n    try:\n        import dbus\n\n        bus = dbus.SessionBus()\n        remote_object = bus.get_object(\"org.gnome.Shell\", \"/io/github/pwr_solaar/solaar\")\n        _dbus_interface = dbus.Interface(remote_object, \"io.github.pwr_solaar.solaar\")\n    except dbus.exceptions.DBusException:\n        logger.warning(\n            \"Solaar Gnome extension not installed - some rule capabilities inoperable\",\n            exc_info=sys.exc_info(),\n        )\n        _dbus_interface = False\n    return _dbus_interface\n\n\ndef xkb_setup():\n    global X11Lib, Xkbdisplay\n    if Xkbdisplay is not None:\n        return Xkbdisplay\n    try:  # set up to get keyboard state using ctypes interface to libx11\n        X11Lib = ctypes.cdll.LoadLibrary(\"libX11.so\")\n        X11Lib.XOpenDisplay.restype = ctypes.POINTER(XkbDisplay)\n        X11Lib.XkbGetState.argtypes = [ctypes.POINTER(XkbDisplay), ctypes.c_uint, ctypes.POINTER(XkbStateRec)]\n        Xkbdisplay = X11Lib.XOpenDisplay(None)\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"XKB display set up\")\n    except Exception:\n        logger.warning(\"XKB display not available - rules cannot access keyboard group\", exc_info=sys.exc_info())\n        Xkbdisplay = False\n    return Xkbdisplay\n\n\nif evdev:\n    buttons = {\n        \"unknown\": (None, None),\n        \"left\": (1, evdev.ecodes.ecodes[\"BTN_LEFT\"]),\n        \"middle\": (2, evdev.ecodes.ecodes[\"BTN_MIDDLE\"]),\n        \"right\": (3, evdev.ecodes.ecodes[\"BTN_RIGHT\"]),\n        \"scroll_up\": (4, evdev.ecodes.ecodes[\"BTN_4\"]),\n        \"scroll_down\": (5, evdev.ecodes.ecodes[\"BTN_5\"]),\n        \"scroll_left\": (6, evdev.ecodes.ecodes[\"BTN_6\"]),\n        \"scroll_right\": (7, evdev.ecodes.ecodes[\"BTN_7\"]),\n        \"button8\": (8, evdev.ecodes.ecodes[\"BTN_8\"]),\n        \"button9\": (9, evdev.ecodes.ecodes[\"BTN_9\"]),\n        \"back\": (10, evdev.ecodes.ecodes[\"BTN_SIDE\"]),\n        \"forward\": (11, evdev.ecodes.ecodes[\"BTN_EXTRA\"]),\n    }\n\n    # uinput capability for keyboard keys, mouse buttons, and scrolling\n    key_events = [c for n, c in evdev.ecodes.ecodes.items() if n.startswith(\"KEY\") and n != \"KEY_CNT\"]\n    for _, evcode in buttons.values():\n        if evcode:\n            key_events.append(evcode)\n    devicecap = {\n        evdev.ecodes.EV_KEY: key_events,\n        evdev.ecodes.EV_REL: [evdev.ecodes.REL_WHEEL, evdev.ecodes.REL_HWHEEL],\n    }\nelse:\n    # Just mock these since they won't be useful without evdev anyway\n    buttons = {}\n    key_events = []\n    devicecap = {}\n\n\ndef setup_uinput():\n    global udevice\n    if udevice is not None:\n        return udevice\n    try:\n        udevice = evdev.uinput.UInput(events=devicecap, name=\"solaar-keyboard\")\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"uinput device set up\")\n        return True\n    except Exception as e:\n        logger.warning(\"cannot create uinput device: %s\", e)\n\n\ndef kbdgroup():\n    if xkb_setup():\n        state = XkbStateRec()\n        X11Lib.XkbGetState(Xkbdisplay, XkbUseCoreKbd, ctypes.pointer(state))\n        return state.group\n    else:\n        return None\n\n\ndef modifier_code(keycode):\n    if wayland or not x11_setup() or keycode == 0:\n        return None\n    for m in range(0, len(modifier_keycodes)):\n        if keycode in modifier_keycodes[m]:\n            return m\n\n\ndef signed(bytes_: bytes) -> int:\n    return int.from_bytes(bytes_, \"big\", signed=True)\n\n\ndef xy_direction(_x, _y):\n    # normalize x and y\n    m = math.sqrt((_x * _x) + (_y * _y))\n    if m == 0:\n        return \"noop\"\n    x = round(_x / m)\n    y = round(_y / m)\n    if x < 0 and y < 0:\n        return \"Mouse Up-left\"\n    elif x > 0 > y:\n        return \"Mouse Up-right\"\n    elif x < 0 < y:\n        return \"Mouse Down-left\"\n    elif x > 0 and y > 0:\n        return \"Mouse Down-right\"\n    elif x > 0:\n        return \"Mouse Right\"\n    elif x < 0:\n        return \"Mouse Left\"\n    elif y > 0:\n        return \"Mouse Down\"\n    elif y < 0:\n        return \"Mouse Up\"\n    else:\n        return \"noop\"\n\n\ndef simulate_uinput(what, code, arg):\n    global udevice\n    if setup_uinput():\n        try:\n            udevice.write(what, code, arg)\n            udevice.syn()\n            if logger.isEnabledFor(logging.DEBUG):\n                logger.debug(\"uinput simulated input %s %s %s\", what, code, arg)\n            return True\n        except Exception as e:\n            udevice = None\n            logger.warning(\"uinput write failed: %s\", e)\n\n\ndef simulate_key(code, event):  # X11 keycode but Solaar event code\n    if evdev and simulate_uinput(evdev.ecodes.EV_KEY, code - 8, event):\n        return True\n    logger.warning(\"no way to simulate key input\")\n\n\ndef click_uinput(button, count):\n    if isinstance(count, int):\n        for _ in range(count):\n            if not simulate_uinput(evdev.ecodes.EV_KEY, button[1], 1):\n                return False\n            if not simulate_uinput(evdev.ecodes.EV_KEY, button[1], 0):\n                return False\n    else:\n        if count != RELEASE:\n            if not simulate_uinput(evdev.ecodes.EV_KEY, button[1], 1):\n                return False\n        if count != DEPRESS:\n            if not simulate_uinput(evdev.ecodes.EV_KEY, button[1], 0):\n                return False\n    return True\n\n\ndef click(button, count):\n    if click_uinput(button, count):\n        return True\n    logger.warning(\"no way to simulate mouse click\")\n    return False\n\n\ndef simulate_scroll(dx, dy):\n    if setup_uinput():\n        success = True\n        if dx:\n            success = simulate_uinput(evdev.ecodes.EV_REL, evdev.ecodes.REL_HWHEEL, dx)\n        if dy and success:\n            success = simulate_uinput(evdev.ecodes.EV_REL, evdev.ecodes.REL_WHEEL, dy)\n        if success:\n            return True\n    logger.warning(\"no way to simulate scrolling\")\n\n\ndef thumb_wheel_up(f, r, d, a):\n    global thumb_wheel_displacement\n    if f != SupportedFeature.THUMB_WHEEL or r != 0:\n        return False\n    if a is None:\n        return signed(d[0:2]) < 0 and signed(d[0:2])\n    elif thumb_wheel_displacement <= -a:\n        thumb_wheel_displacement += a\n        return 1\n    else:\n        return False\n\n\ndef thumb_wheel_down(f, r, d, a):\n    global thumb_wheel_displacement\n    if f != SupportedFeature.THUMB_WHEEL or r != 0:\n        return False\n    if a is None:\n        return signed(d[0:2]) > 0 and signed(d[0:2])\n    elif thumb_wheel_displacement >= a:\n        thumb_wheel_displacement -= a\n        return 1\n    else:\n        return False\n\n\ndef charging(f, r, d, _a):\n    if (\n        (f == SupportedFeature.BATTERY_STATUS and r == 0 and 1 <= d[2] <= 4)\n        or (f == SupportedFeature.BATTERY_VOLTAGE and r == 0 and d[2] & (1 << 7))\n        or (f == SupportedFeature.UNIFIED_BATTERY and r == 0 and 1 <= d[2] <= 3)\n    ):\n        return 1\n    else:\n        return False\n\n\nTESTS = {\n    \"crown_right\": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[1] < 128 and d[1], False],\n    \"crown_left\": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[1] >= 128 and 256 - d[1], False],\n    \"crown_right_ratchet\": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[2] < 128 and d[2], False],\n    \"crown_left_ratchet\": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[2] >= 128 and 256 - d[2], False],\n    \"crown_tap\": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[5] == 0x01 and d[5], False],\n    \"crown_start_press\": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[6] == 0x01 and d[6], False],\n    \"crown_end_press\": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[6] == 0x05 and d[6], False],\n    \"crown_pressed\": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and 0x01 <= d[6] <= 0x04 and d[6], False],\n    \"thumb_wheel_up\": [thumb_wheel_up, True],\n    \"thumb_wheel_down\": [thumb_wheel_down, True],\n    \"lowres_wheel_up\": [\n        lambda f, r, d, a: f == SupportedFeature.LOWRES_WHEEL and r == 0 and signed(d[0:1]) > 0 and signed(d[0:1]),\n        False,\n    ],\n    \"lowres_wheel_down\": [\n        lambda f, r, d, a: f == SupportedFeature.LOWRES_WHEEL and r == 0 and signed(d[0:1]) < 0 and signed(d[0:1]),\n        False,\n    ],\n    \"hires_wheel_up\": [\n        lambda f, r, d, a: f == SupportedFeature.HIRES_WHEEL and r == 0 and signed(d[1:3]) > 0 and signed(d[1:3]),\n        False,\n    ],\n    \"hires_wheel_down\": [\n        lambda f, r, d, a: f == SupportedFeature.HIRES_WHEEL and r == 0 and signed(d[1:3]) < 0 and signed(d[1:3]),\n        False,\n    ],\n    \"charging\": [charging, False],\n    \"False\": [lambda f, r, d, a: False, False],\n    \"True\": [lambda f, r, d, a: True, False],\n}\n\nMOUSE_GESTURE_TESTS = {\n    \"mouse-down\": [\"Mouse Down\"],\n    \"mouse-up\": [\"Mouse Up\"],\n    \"mouse-left\": [\"Mouse Left\"],\n    \"mouse-right\": [\"Mouse Right\"],\n    \"mouse-noop\": [],\n}\n\n# COMPONENTS = {}\n\n\nclass RuleComponent:\n    def compile(self, c):\n        if isinstance(c, RuleComponent):\n            return c\n        elif isinstance(c, dict) and len(c) == 1:\n            k, v = next(iter(c.items()))\n            if k in COMPONENTS:\n                return COMPONENTS[k](v)\n        logger.warning(\"illegal component in rule: %s\", c)\n        return Condition()\n\n\ndef _evaluate(components, feature, notification: HIDPPNotification, device, result) -> Any:\n    res = True\n    for component in components:\n        res = component.evaluate(feature, notification, device, result)\n        if not isinstance(component, Action) and res is None:\n            return None\n        if isinstance(component, Condition) and not res:\n            return res\n    return res\n\n\nclass Rule(RuleComponent):\n    def __init__(self, args, source=None, warn=True):\n        self.components = [self.compile(a) for a in args]\n        self.source = source\n\n    def __str__(self):\n        source = f\"({self.source})\" if self.source else \"\"\n        return f\"Rule{source}[{', '.join([c.__str__() for c in self.components])}]\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate rule: %s\", self)\n        return _evaluate(self.components, feature, notification, device, True)\n\n    def once(self, feature, notification: HIDPPNotification, device, last_result):\n        self.evaluate(feature, notification, device, last_result)\n        return False\n\n    def data(self):\n        return {\"Rule\": [c.data() for c in self.components]}\n\n\nclass Condition(RuleComponent):\n    def __init__(self, *args):\n        pass\n\n    def __str__(self):\n        return \"CONDITION\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        return False\n\n\nclass Not(Condition):\n    def __init__(self, op, warn=True):\n        if isinstance(op, list) and len(op) == 1:\n            op = op[0]\n        self.op = op\n        self.component = self.compile(op)\n\n    def __str__(self):\n        return f\"Not: {str(self.component)}\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        result = self.component.evaluate(feature, notification, device, last_result)\n        return None if result is None else not result\n\n    def data(self):\n        return {\"Not\": self.component.data()}\n\n\nclass Or(Condition):\n    def __init__(self, args, warn=True):\n        self.components = [self.compile(a) for a in args]\n\n    def __str__(self):\n        return \"Or: [\" + \", \".join(str(c) for c in self.components) + \"]\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        result = False\n        for component in self.components:\n            result = component.evaluate(feature, notification, device, last_result)\n            if not isinstance(component, Action) and result is None:\n                return None\n            if isinstance(component, Condition) and result:\n                return result\n        return result\n\n    def data(self):\n        return {\"Or\": [c.data() for c in self.components]}\n\n\nclass And(Condition):\n    def __init__(self, args, warn=True):\n        self.components = [self.compile(a) for a in args]\n\n    def __str__(self):\n        return \"And: [\" + \", \".join(str(c) for c in self.components) + \"]\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        return _evaluate(self.components, feature, notification, device, last_result)\n\n    def data(self):\n        return {\"And\": [c.data() for c in self.components]}\n\n\ndef x11_focus_prog():\n    if not x11_setup():\n        return None\n    pid = wm_class = None\n    window = xdisplay.get_input_focus().focus\n    while window:\n        pid = window.get_full_property(NET_WM_PID, 0)\n        wm_class = window.get_wm_class()\n        if wm_class and pid:\n            break\n        window = window.query_tree().parent\n    try:\n        name = psutil.Process(pid.value[0]).name() if pid else \"\"\n    except Exception:\n        name = \"\"\n    return (wm_class[0], wm_class[1], name) if wm_class else (name,)\n\n\ndef x11_pointer_prog():\n    if not x11_setup():\n        return None\n    pid = wm_class = None\n    window = xdisplay.screen().root.query_pointer().child\n    for child in reversed(window.query_tree().children):\n        pid = child.get_full_property(NET_WM_PID, 0)\n        wm_class = child.get_wm_class()\n        if wm_class:\n            break\n    name = psutil.Process(pid.value[0]).name() if pid else \"\"\n    return (wm_class[0], wm_class[1], name) if wm_class else (name,)\n\n\ndef gnome_dbus_focus_prog():\n    if not gnome_dbus_interface_setup():\n        return None\n    wm_class = _dbus_interface.ActiveWindow()\n    return (wm_class,) if wm_class else None\n\n\ndef gnome_dbus_pointer_prog():\n    if not gnome_dbus_interface_setup():\n        return None\n    wm_class = _dbus_interface.PointerOverWindow()\n    return (wm_class,) if wm_class else None\n\n\nclass Process(Condition):\n    def __init__(self, process, warn=True):\n        self.process = process\n        if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()):\n            if warn:\n                logger.warning(\n                    \"rules can only access active process in X11 or in Wayland under GNOME with Solaar Gnome \"\n                    \"extension - %s\",\n                    self,\n                )\n        if not isinstance(process, str):\n            if warn:\n                logger.warning(\"rule Process argument not a string: %s\", process)\n            self.process = str(process)\n\n    def __str__(self):\n        return f\"Process: {str(self.process)}\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        if not isinstance(self.process, str):\n            return False\n        focus = x11_focus_prog() if not wayland else gnome_dbus_focus_prog()\n        result = any(bool(s and s.startswith(self.process)) for s in focus) if focus else None\n        return result\n\n    def data(self):\n        return {\"Process\": str(self.process)}\n\n\nclass MouseProcess(Condition):\n    def __init__(self, process, warn=True):\n        self.process = process\n        if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()):\n            if warn:\n                logger.warning(\n                    \"rules cannot access active mouse process \"\n                    \"in X11 or in Wayland under GNOME with Solaar Extension for GNOME - %s\",\n                    self,\n                )\n        if not isinstance(process, str):\n            if warn:\n                logger.warning(\"rule MouseProcess argument not a string: %s\", process)\n            self.process = str(process)\n\n    def __str__(self):\n        return f\"MouseProcess: {str(self.process)}\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        if not isinstance(self.process, str):\n            return False\n        pointer_focus = x11_pointer_prog() if not wayland else gnome_dbus_pointer_prog()\n        result = any(bool(s and s.startswith(self.process)) for s in pointer_focus) if pointer_focus else None\n        return result\n\n    def data(self):\n        return {\"MouseProcess\": str(self.process)}\n\n\nclass Feature(Condition):\n    def __init__(self, feature: str, warn: bool = True):\n        try:\n            self.feature = SupportedFeature[feature.replace(\" \", \"_\")]\n        except KeyError:\n            self.feature = None\n            if warn:\n                logger.warning(\"rule Feature argument not name of a feature: %s\", feature)\n\n    def __str__(self):\n        return f\"Feature: {str(self.feature)}\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        return feature == self.feature\n\n    def data(self):\n        return {\"Feature\": str(self.feature)}\n\n\nclass Report(Condition):\n    def __init__(self, report, warn=True):\n        if not (isinstance(report, int)):\n            if warn:\n                logger.warning(\"rule Report argument not an integer: %s\", report)\n            self.report = -1\n        else:\n            self.report = report\n\n    def __str__(self):\n        return f\"Report: {str(self.report)}\"\n\n    def evaluate(self, report, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        return (notification.address >> 4) == self.report\n\n    def data(self):\n        return {\"Report\": self.report}\n\n\n# Setting(device, setting, [key], value...)\nclass Setting(Condition):\n    def __init__(self, args, warn=True):\n        if not (isinstance(args, list) and len(args) > 2):\n            if warn:\n                logger.warning(\"rule Setting argument not list with minimum length 3: %s\", args)\n            self.args = []\n        else:\n            self.args = args\n\n    def __str__(self):\n        return \"Setting: \" + \" \".join([str(a) for a in self.args])\n\n    def evaluate(self, report, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        if len(self.args) < 3:\n            return None\n        dev = device.find(self.args[0]) if self.args[0] is not None else device\n        if dev is None:\n            logger.warning(\"Setting condition: device %s is not known\", self.args[0])\n            return False\n        setting = next((s for s in dev.settings if s.name == self.args[1]), None)\n        if setting is None:\n            logger.warning(\"Setting condition: setting %s is not the name of a setting for %s\", self.args[1], dev.name)\n            return None\n        # should the value argument be checked to be sure it is acceptable?? needs to be careful about boolean toggle\n        # TODO add compare  methods for more validators\n        try:\n            result = setting.compare(self.args[2:], setting.read())\n        except Exception as e:\n            logger.warning(\"Setting condition: error when checking setting %s: %s\", self.args, e)\n            result = False\n        return result\n\n    def data(self):\n        return {\"Setting\": self.args[:]}\n\n\nMODIFIERS = {\n    \"Shift\": int(Gdk.ModifierType.SHIFT_MASK),\n    \"Control\": int(Gdk.ModifierType.CONTROL_MASK),\n    \"Alt\": int(Gdk.ModifierType.MOD1_MASK),\n    \"Super\": int(Gdk.ModifierType.MOD4_MASK),\n}\nMODIFIER_MASK = MODIFIERS[\"Shift\"] + MODIFIERS[\"Control\"] + MODIFIERS[\"Alt\"] + MODIFIERS[\"Super\"]\n\n\nclass Modifiers(Condition):\n    def __init__(self, modifiers, warn=True):\n        modifiers = [modifiers] if isinstance(modifiers, str) else modifiers\n        self.desired = 0\n        self.modifiers = []\n        for k in modifiers:\n            if k in MODIFIERS:\n                self.desired += MODIFIERS.get(k, 0)\n                self.modifiers.append(k)\n            else:\n                if warn:\n                    logger.warning(\"unknown rule Modifier value: %s\", k)\n\n    def __str__(self):\n        return f\"Modifiers: {str(self.desired)}\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        if gkeymap:\n            current = gkeymap.get_modifier_state()  # get the current keyboard modifier\n            return self.desired == (current & MODIFIER_MASK)\n        else:\n            logger.warning(\"no keymap so cannot determine modifier keys\")\n            return False\n\n    def data(self):\n        return {\"Modifiers\": [str(m) for m in self.modifiers]}\n\n\nclass Key(Condition):\n    DOWN = \"pressed\"\n    UP = \"released\"\n\n    def __init__(self, args, warn=True):\n        default_key = 0\n        default_action = self.DOWN\n\n        key, action = None, None\n\n        if not args or not isinstance(args, (list, str)):\n            if warn:\n                logger.warning(f\"rule Key arguments unknown: {args}\")\n            key = default_key\n            action = default_action\n        elif isinstance(args, str):\n            logger.debug(f'rule Key assuming action \"{default_action}\" for \"{args}\"')\n            key = args\n            action = default_action\n        elif isinstance(args, list):\n            if len(args) == 1:\n                logger.debug(f'rule Key assuming action \"{default_action}\" for \"{args}\"')\n                key, action = args[0], default_action\n            elif len(args) >= 2:\n                key, action = args[:2]\n\n        if isinstance(key, str) and key in CONTROL:\n            self.key = CONTROL[key]\n        elif isinstance(key, str) and key.startswith(\"unknown:\"):\n            logger.info(f\"rule Key key name currently unknown: {key}\")\n            self.key = CONTROL[int(key[-4:], 16)]\n        else:\n            if warn:\n                logger.warning(f\"rule Key key name not name of a Logitech key: {key}\")\n            self.key = default_key\n\n        if isinstance(action, str) and action in (self.DOWN, self.UP):\n            self.action = action\n        else:\n            if warn:\n                logger.warning(f\"rule Key action unknown: {action}, assuming {default_action}\")\n            self.action = default_action\n\n    def __str__(self):\n        return f\"Key: {str(self.key) if self.key else 'None'} ({self.action})\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        return bool(self.key and self.key == (key_down if self.action == self.DOWN else key_up))\n\n    def data(self):\n        return {\"Key\": [str(self.key), self.action]}\n\n\nclass KeyIsDown(Condition):\n    def __init__(self, args, warn=True):\n        default_key = 0\n\n        key = None\n\n        if not args or not isinstance(args, str):\n            if warn:\n                logger.warning(f\"rule KeyDown arguments unknown: {args}\")\n            key = default_key\n        elif isinstance(args, str):\n            key = args\n\n        if isinstance(key, str) and key in CONTROL:\n            self.key = CONTROL[key]\n        else:\n            if warn:\n                logger.warning(f\"rule Key key name not name of a Logitech key: {key}\")\n            self.key = default_key\n\n    def __str__(self):\n        return f\"KeyIsDown: {str(self.key) if self.key else 'None'}\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        return key_is_down(self.key)\n\n    def data(self):\n        return {\"KeyIsDown\": str(self.key)}\n\n\ndef bit_test(start, end, bits):\n    return lambda f, r, d: int.from_bytes(d[start:end], byteorder=\"big\", signed=True) & bits\n\n\ndef range_test(start, end, min, max):\n    def range_test_helper(_f, _r, d):\n        value = int.from_bytes(d[start:end], byteorder=\"big\", signed=True)\n        return min <= value <= max and (value if value else True)\n\n    return range_test_helper\n\n\nclass Test(Condition):\n    def __init__(self, test, warn=True):\n        self.test = \"\"\n        self.parameter = None\n        if isinstance(test, str):\n            test = [test]\n        if isinstance(test, list) and all(isinstance(t, int) for t in test):\n            if warn:\n                logger.warning(\"Test rules consisting of numbers are deprecated, converting to a TestBytes condition\")\n            self.__class__ = TestBytes\n            self.__init__(test, warn=warn)\n        elif isinstance(test, list):\n            if test[0] in MOUSE_GESTURE_TESTS:\n                if warn:\n                    logger.warning(\"mouse movement test %s deprecated, converting to a MouseGesture\", test)\n                self.__class__ = MouseGesture\n                self.__init__(MOUSE_GESTURE_TESTS[0][test], warn=warn)\n            elif test[0] in TESTS:\n                self.test = test[0]\n                self.function = TESTS[test[0]][0]\n                self.parameter = test[1] if len(test) > 1 else None\n            else:\n                if warn:\n                    logger.warning(\"rule Test name not name of a test: %s\", test)\n                self.test = \"False\"\n                self.function = TESTS[\"False\"][0]\n        else:\n            if warn:\n                logger.warning(\"rule Test argument not valid %s\", test)\n\n    def __str__(self):\n        return f\"Test: {str(self.test)}\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        return self.function(feature, notification.address, notification.data, self.parameter)\n\n    def data(self):\n        return {\"Test\": ([self.test, self.parameter] if self.parameter is not None else [self.test])}\n\n\nclass TestBytes(Condition):\n    def __init__(self, test, warn=True):\n        self.test = test\n        if (\n            isinstance(test, list)\n            and 2 < len(test) <= 4\n            and all(isinstance(t, int) for t in test)\n            and 0 <= test[0] <= 16\n            and 0 <= test[1] <= 16\n            and test[0] < test[1]\n        ):\n            self.function = bit_test(*test) if len(test) == 3 else range_test(*test)\n        else:\n            if warn:\n                logger.warning(\"rule TestBytes argument not valid %s\", test)\n\n    def __str__(self):\n        return f\"TestBytes: {str(self.test)}\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        return self.function(feature, notification.address, notification.data)\n\n    def data(self):\n        return {\"TestBytes\": self.test[:]}\n\n\nclass MouseGesture(Condition):\n    MOVEMENTS = [\n        \"Mouse Up\",\n        \"Mouse Down\",\n        \"Mouse Left\",\n        \"Mouse Right\",\n        \"Mouse Up-left\",\n        \"Mouse Up-right\",\n        \"Mouse Down-left\",\n        \"Mouse Down-right\",\n    ]\n\n    def __init__(self, movements, warn=True):\n        if isinstance(movements, str):\n            movements = [movements]\n        for x in movements:\n            if x not in self.MOVEMENTS and x not in CONTROL:\n                if warn:\n                    logger.warning(\"rule Mouse Gesture argument not direction or name of a Logitech key: %s\", x)\n        self.movements = movements\n\n    def __str__(self):\n        return \"MouseGesture: \" + \" \".join(self.movements)\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        if feature == SupportedFeature.MOUSE_GESTURE:\n            d = notification.data\n            data = struct.unpack(\"!\" + (int(len(d) / 2) * \"h\"), d)\n            data_offset = 1\n            movement_offset = 0\n            if self.movements and self.movements[0] not in self.MOVEMENTS:  # matching against initiating key\n                movement_offset = 1\n                if self.movements[0] != str(CONTROL[data[0]]):\n                    return False\n            for m in self.movements[movement_offset:]:\n                if data_offset >= len(data):\n                    return False\n                if data[data_offset] == 0:\n                    direction = xy_direction(data[data_offset + 1], data[data_offset + 2])\n                    if m != direction:\n                        return False\n                    data_offset += 3\n                elif data[data_offset] == 1:\n                    if m != str(CONTROL[data[data_offset + 1]]):\n                        return False\n                    data_offset += 2\n            return data_offset == len(data)\n        return False\n\n    def data(self):\n        return {\"MouseGesture\": [str(m) for m in self.movements]}\n\n\nclass Active(Condition):\n    def __init__(self, devID, warn=True):\n        if not (isinstance(devID, str)):\n            if warn:\n                logger.warning(\"rule Active argument not a string: %s\", devID)\n            self.devID = \"\"\n        self.devID = devID\n\n    def __str__(self):\n        return f\"Active: {str(self.devID)}\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        dev = device.find(self.devID)\n        return bool(dev and dev.ping())\n\n    def data(self):\n        return {\"Active\": self.devID}\n\n\nclass Device(Condition):\n    def __init__(self, devID, warn=True):\n        if not (isinstance(devID, str)):\n            if warn:\n                logger.warning(\"rule Device argument not a string: %s\", devID)\n            self.devID = \"\"\n        self.devID = devID\n\n    def __str__(self):\n        return f\"Device: {str(self.devID)}\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        return (\n            device.unitId == self.devID\n            or device.serial == self.devID\n            or device.codename == self.devID\n            or device.name == self.devID\n        )\n\n    def data(self):\n        return {\"Device\": self.devID}\n\n\nclass Host(Condition):\n    def __init__(self, host, warn=True):\n        if not (isinstance(host, str)):\n            if warn:\n                logger.warning(\"rule Host Name argument not a string: %s\", host)\n            self.host = \"\"\n        self.host = host\n\n    def __str__(self):\n        return f\"Host: {str(self.host)}\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"evaluate condition: %s\", self)\n        hostname = socket.getfqdn()\n        return hostname.startswith(self.host)\n\n    def data(self):\n        return {\"Host\": self.host}\n\n\nclass Action(RuleComponent):\n    def __init__(self, *args):\n        pass\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        return None\n\n\ndef keysym_to_keycode(keysym, _modifiers) -> Tuple[int, int]:  # maybe should take shift into account\n    \"\"\"Reverse the keycode to keysym mapping.\n\n    Warning:\n    This is an attempt to reverse the keycode to keysym mappping in XKB.\n    It may not be completely general.\n    \"\"\"\n    group = kbdgroup() or 0\n    keycodes = gkeymap.get_entries_for_keyval(keysym)\n    (keycode, level) = (None, None)\n    for k in keycodes.keys:  # mappings that have the correct group\n        if group == k.group and k.keycode < 256 and (level is None or k.level < level):\n            keycode = k.keycode\n            level = k.level\n    if keycode or group == 0:\n        return keycode, level\n\n    for k in keycodes.keys:  # mappings for group 0 where keycode only has group 0 mappings\n        if 0 == k.group and k.keycode < 256 and (level is None or k.level < level):\n            (a, m, vs) = gkeymap.get_entries_for_keycode(k.keycode)\n            if a and all(mk.group == 0 for mk in m):\n                keycode = k.keycode\n                level = k.level\n    return keycode, level\n\n\nclass KeyPress(Action):\n    def __init__(self, args, warn=True):\n        self.key_names, self.action = self.regularize_args(args)\n        if not isinstance(self.key_names, list):\n            if warn:\n                logger.warning(\"rule KeyPress keys not key names %s\", self.keys_names)\n            self.key_symbols = []\n        else:\n            self.key_symbols = [XK_KEYS.get(k, None) for k in self.key_names]\n        if not all(self.key_symbols):\n            if warn:\n                logger.warning(\"rule KeyPress keys not key names %s\", self.key_names)\n            self.key_symbols = []\n\n    def regularize_args(self, args):\n        action = CLICK\n        if not isinstance(args, list):\n            args = [args]\n        keys = args\n        if len(args) == 2 and args[1] in [CLICK, DEPRESS, RELEASE]:\n            keys = [args[0]] if isinstance(args[0], str) else args[0]\n            action = args[1]\n        return keys, action\n\n    def __str__(self):\n        return \"KeyPress: \" + \" \".join(self.key_names) + \" \" + self.action\n\n    def needed(self, k, modifiers):\n        code = modifier_code(k)\n        return not (code is not None and modifiers & (1 << code))\n\n    def mods(self, level, modifiers, direction):\n        if level == 2 or level == 3:\n            (sk, _) = keysym_to_keycode(XK_KEYS.get(\"ISO_Level3_Shift\", None), modifiers)\n            if sk and self.needed(sk, modifiers):\n                simulate_key(sk, direction)\n        if level == 1 or level == 3:\n            (sk, _) = keysym_to_keycode(XK_KEYS.get(\"Shift_L\", None), modifiers)\n            if sk and self.needed(sk, modifiers):\n                simulate_key(sk, direction)\n\n    def keyDown(self, keysyms_, modifiers):\n        for k in keysyms_:\n            (keycode, level) = keysym_to_keycode(k, modifiers)\n            if keycode is None:\n                logger.warning(\"rule KeyPress key symbol not currently available %s\", self)\n            elif self.action != CLICK or self.needed(keycode, modifiers):  # only check needed when clicking\n                self.mods(level, modifiers, _KEY_PRESS)\n                simulate_key(keycode, _KEY_PRESS)\n\n    def keyUp(self, keysyms_, modifiers):\n        for k in keysyms_:\n            (keycode, level) = keysym_to_keycode(k, modifiers)\n            if keycode and (self.action != CLICK or self.needed(keycode, modifiers)):  # only check needed when clicking\n                simulate_key(keycode, _KEY_RELEASE)\n                self.mods(level, modifiers, _KEY_RELEASE)\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if gkeymap:\n            current = gkeymap.get_modifier_state()\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\n                    \"KeyPress action: %s %s, group %s, modifiers %s\",\n                    self.key_names,\n                    self.action,\n                    kbdgroup(),\n                    current,\n                )\n            if self.action != RELEASE:\n                self.keyDown(self.key_symbols, current)\n            if self.action != DEPRESS:\n                self.keyUp(reversed(self.key_symbols), current)\n            time.sleep(0.01)\n        else:\n            logger.warning(\"no keymap so cannot determine which keycode to send\")\n        return None\n\n    def data(self):\n        return {\"KeyPress\": [[str(k) for k in self.key_names], self.action]}\n\n\n# KeyDown is dangerous as the key can auto-repeat and make your system unusable\n# class KeyDown(KeyPress):\n#    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n#        super().keyDown(self.keys, current_key_modifiers)\n# class KeyUp(KeyPress):\n#    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n#        super().keyUp(self.keys, current_key_modifiers)\n\n\nclass MouseScroll(Action):\n    def __init__(self, amounts, warn=True):\n        if len(amounts) == 1 and isinstance(amounts[0], list):\n            amounts = amounts[0]\n        if not (len(amounts) == 2 and all([isinstance(a, numbers.Number) for a in amounts])):\n            if warn:\n                logger.warning(\"rule MouseScroll argument not two numbers %s\", amounts)\n            amounts = [0, 0]\n        self.amounts = amounts\n\n    def __str__(self):\n        return \"MouseScroll: \" + \" \".join([str(a) for a in self.amounts])\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        amounts = self.amounts\n        if isinstance(last_result, numbers.Number):\n            amounts = [math.floor(last_result * a) for a in self.amounts]\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"MouseScroll action: %s %s %s\", self.amounts, last_result, amounts)\n        dx, dy = amounts\n        simulate_scroll(dx, dy)\n        time.sleep(0.01)\n        return None\n\n    def data(self):\n        return {\"MouseScroll\": self.amounts[:]}\n\n\nclass MouseClick(Action):\n    def __init__(self, args, warn=True):\n        if len(args) == 1 and isinstance(args[0], list):\n            args = args[0]\n        if not isinstance(args, list):\n            args = [args]\n        self.button = str(args[0]) if len(args) >= 0 else None\n        if self.button not in buttons:\n            if warn:\n                logger.warning(\"rule MouseClick action: button %s not known\", self.button)\n            self.button = None\n        count = args[1] if len(args) >= 2 else 1\n        try:\n            self.count = int(count)\n        except (ValueError, TypeError):\n            if count in [CLICK, DEPRESS, RELEASE]:\n                self.count = count\n            elif warn:\n                logger.warning(\n                    \"rule MouseClick action: argument %s should be an integer or click, depress, or release\",\n                    count,\n                )\n                self.count = 1\n\n    def __str__(self):\n        return f\"MouseClick: {self.button} ({str(self.count)})\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(f\"MouseClick action: {str(self.count)} {self.button}\")\n        if self.button and self.count:\n            click(buttons[self.button], self.count)\n        time.sleep(0.01)\n        return None\n\n    def data(self):\n        return {\"MouseClick\": [self.button, self.count]}\n\n\nclass Set(Action):\n    def __init__(self, args, warn=True):\n        if not (isinstance(args, list) and len(args) > 2):\n            if warn:\n                logger.warning(\"rule Set argument not list with minimum length 3: %s\", args)\n            self.args = []\n        else:\n            self.args = args\n\n    def __str__(self):\n        return \"Set: \" + \" \".join([str(a) for a in self.args])\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if len(self.args) < 3:\n            return None\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"Set action: %s\", self.args)\n        dev = device.find(self.args[0]) if self.args[0] is not None else device\n        if dev is None:\n            logger.warning(\"Set action: device %s is not known\", self.args[0])\n            return None\n        setting = next((s for s in dev.settings if s.name == self.args[1]), None)\n        if setting is None:\n            logger.warning(\"Set action: setting %s is not the name of a setting for %s\", self.args[1], dev.name)\n            return None\n        args = setting.acceptable(self.args[2:], setting.read())\n        if args is None:\n            logger.warning(\n                \"Set Action: invalid args %s for setting %s of %s\",\n                self.args[2:],\n                self.args[1],\n                self.args[0],\n            )\n            return None\n        if len(args) > 1:\n            setting.write_key_value(args[0], args[1])\n        else:\n            setting.write(args[0])\n        if device.setting_callback:\n            device.setting_callback(device, type(setting), args)\n        return None\n\n    def data(self):\n        return {\"Set\": self.args[:]}\n\n\nclass Execute(Action):\n    def __init__(self, args, warn=True):\n        if isinstance(args, str):\n            args = [args]\n        if not (isinstance(args, list) and all(isinstance(arg), str) for arg in args):\n            if warn:\n                logger.warning(\"rule Execute argument not list of strings: %s\", args)\n            self.args = []\n        else:\n            self.args = args\n\n    def __str__(self):\n        return \"Execute: \" + \" \".join([a for a in self.args])\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"Execute action: %s\", self.args)\n        subprocess.Popen(self.args)\n        return None\n\n    def data(self):\n        return {\"Execute\": self.args[:]}\n\n\nclass Later(Action):\n    def __init__(self, args, warn=True):\n        self.delay = 0\n        self.rule = Rule([])\n        self.components = []\n        if not (isinstance(args, list)):\n            args = [args]\n        if not (isinstance(args, list) and len(args) >= 1):\n            if warn:\n                logger.warning(\"rule Later argument not list with minimum length 1: %s\", args)\n        elif not (isinstance(args[0], (int, float))) or not 0.01 <= args[0] <= 100:\n            if warn:\n                logger.warning(\"rule Later delay not between 0.01 and 100: %s\", args)\n        else:\n            self.delay = args[0]\n            self.rule = Rule(args[1:], warn=warn)\n            self.components = self.rule.components\n\n    def __str__(self):\n        return f\"Later: [{str(self.delay)}, \" + \", \".join(str(c) for c in self.components) + \"]\"\n\n    def evaluate(self, feature, notification: HIDPPNotification, device, last_result):\n        if self.delay and self.rule:\n            if self.delay >= 1:\n                GLib.timeout_add_seconds(int(self.delay), Rule.once, self.rule, feature, notification, device, last_result)\n            else:\n                GLib.timeout_add(int(self.delay * 1000), Rule.once, self.rule, feature, notification, device, last_result)\n        return None\n\n    def data(self):\n        data = [c.data() for c in self.components]\n        data.insert(0, self.delay)\n        return {\"Later\": data}\n\n\nCOMPONENTS = {\n    \"Rule\": Rule,\n    \"Not\": Not,\n    \"Or\": Or,\n    \"And\": And,\n    \"Process\": Process,\n    \"MouseProcess\": MouseProcess,\n    \"Feature\": Feature,\n    \"Report\": Report,\n    \"Setting\": Setting,\n    \"Modifiers\": Modifiers,\n    \"Key\": Key,\n    \"KeyIsDown\": KeyIsDown,\n    \"Test\": Test,\n    \"TestBytes\": TestBytes,\n    \"MouseGesture\": MouseGesture,\n    \"Active\": Active,\n    \"Device\": Device,\n    \"Host\": Host,\n    \"KeyPress\": KeyPress,\n    \"MouseScroll\": MouseScroll,\n    \"MouseClick\": MouseClick,\n    \"Set\": Set,\n    \"Execute\": Execute,\n    \"Later\": Later,\n}\n\n\nbuilt_in_rules = Rule(\n    [\n        {\n            \"Rule\": [  # Implement problematic keys for Craft and MX Master\n                {\"Rule\": [{\"Key\": [\"Brightness Down\", \"pressed\"]}, {\"KeyPress\": \"XF86_MonBrightnessDown\"}]},\n                {\"Rule\": [{\"Key\": [\"Brightness Up\", \"pressed\"]}, {\"KeyPress\": \"XF86_MonBrightnessUp\"}]},\n            ]\n        },\n    ]\n)\n\n\ndef key_is_down(key: NamedInt) -> bool:\n    \"\"\"Checks if given key is pressed or not.\"\"\"\n    if key == CONTROL.MR:\n        return mr_key_down\n    elif CONTROL.M1 <= key <= CONTROL.M8:\n        return bool(m_keys_down & (0x01 << (key - CONTROL.M1)))\n    elif CONTROL.G1 <= key <= CONTROL.G32:\n        return bool(g_keys_down & (0x01 << (key - CONTROL.G1)))\n    return key in keys_down\n\n\ndef evaluate_rules(feature, notification: HIDPPNotification, device):\n    if logger.isEnabledFor(logging.DEBUG):\n        logger.debug(\"evaluating rules on %s %s\", feature, notification)\n    rules.evaluate(feature, notification, device, True)\n\n\ndef process_notification(device, notification: HIDPPNotification, feature) -> None:\n    \"\"\"Processes HID++ notifications.\"\"\"\n    global keys_down, g_keys_down, m_keys_down, mr_key_down, key_down, key_up, thumb_wheel_displacement\n    key_down, key_up = None, None\n    # need to keep track of keys that are down to find a new key down\n    if notification.address == 0x00:\n        if feature == SupportedFeature.REPROG_CONTROLS_V4:\n            new_keys_down = struct.unpack(\"!4H\", notification.data[:8])\n            for key in new_keys_down:\n                if key and key not in keys_down:\n                    key_down = key\n            for key in keys_down:\n                if key and key not in new_keys_down:\n                    key_up = key\n            keys_down = new_keys_down\n        # and also G keys down\n        elif feature == SupportedFeature.GKEY:\n            new_g_keys_down = struct.unpack(\"<I\", notification.data[:4])[0]\n            for i in range(32):\n                if new_g_keys_down & (0x01 << i) and not g_keys_down & (0x01 << i):\n                    key_down = CONTROL[\"G\" + str(i + 1)]\n                if g_keys_down & (0x01 << i) and not new_g_keys_down & (0x01 << i):\n                    key_up = CONTROL[\"G\" + str(i + 1)]\n            g_keys_down = new_g_keys_down\n        # and also M keys down\n        elif feature == SupportedFeature.MKEYS:\n            new_m_keys_down = struct.unpack(\"!1B\", notification.data[:1])[0]\n            for i in range(1, 9):\n                if new_m_keys_down & (0x01 << (i - 1)) and not m_keys_down & (0x01 << (i - 1)):\n                    key_down = CONTROL[\"M\" + str(i)]\n                if m_keys_down & (0x01 << (i - 1)) and not new_m_keys_down & (0x01 << (i - 1)):\n                    key_up = CONTROL[\"M\" + str(i)]\n            m_keys_down = new_m_keys_down\n        # and also MR key\n        elif feature == SupportedFeature.MR:\n            new_mr_key_down = struct.unpack(\"!1B\", notification.data[:1])[0]\n            if not mr_key_down and new_mr_key_down:\n                key_down = CONTROL[\"MR\"]\n            if mr_key_down and not new_mr_key_down:\n                key_up = CONTROL[\"MR\"]\n            mr_key_down = new_mr_key_down\n        # keep track of thumb wheel movement\n        elif feature == SupportedFeature.THUMB_WHEEL:\n            if notification.data[4] <= 0x01:  # when wheel starts, zero out last movement\n                thumb_wheel_displacement = 0\n            thumb_wheel_displacement += signed(notification.data[0:2])\n\n    GLib.idle_add(evaluate_rules, feature, notification, device)\n\n\n_XDG_CONFIG_HOME = os.environ.get(\"XDG_CONFIG_HOME\") or os.path.expanduser(os.path.join(\"~\", \".config\"))\n_file_path = os.path.join(_XDG_CONFIG_HOME, \"solaar\", \"rules.yaml\")\n\nrules = built_in_rules\n\n\ndef _save_config_rule_file(file_name: str = _file_path):\n    # This is a trick to show str/float/int lists in-line (inspired by https://stackoverflow.com/a/14001707)\n    class inline_list(list):\n        pass\n\n    def blockseq_rep(dumper, data):\n        return dumper.represent_sequence(\"tag:yaml.org,2002:seq\", data, flow_style=True)\n\n    yaml.add_representer(inline_list, blockseq_rep)\n\n    def convert(elem):\n        if isinstance(elem, list):\n            if len(elem) == 1 and isinstance(elem[0], (int, str, float)):\n                # All diversion classes that expect a list of scalars also support a single scalar without a list\n                return elem[0]\n            if all(isinstance(c, (int, str, float)) for c in elem):\n                return inline_list([convert(c) for c in elem])\n            return [convert(c) for c in elem]\n        if isinstance(elem, dict):\n            return {k: convert(v) for k, v in elem.items()}\n        if isinstance(elem, NamedInt):\n            return int(elem)\n        return elem\n\n    # YAML format settings\n    dump_settings = {\n        \"encoding\": \"utf-8\",\n        \"explicit_start\": True,\n        \"explicit_end\": True,\n        \"default_flow_style\": False,\n        # 'version': (1, 3),  # it would be printed for every rule\n    }\n    # Save only user-defined rules\n    rules_to_save = sum((r.data()[\"Rule\"] for r in rules.components if r.source == file_name), [])\n    if logger.isEnabledFor(logging.INFO):\n        logger.info(\"saving %d rule(s) to %s\", len(rules_to_save), file_name)\n    try:\n        with open(file_name, \"w\") as f:\n            if rules_to_save:\n                f.write(\"%YAML 1.3\\n\")  # Write version manually\n            dump_data = [r[\"Rule\"] for r in rules_to_save]\n            yaml.dump_all(convert(dump_data), f, **dump_settings)\n    except Exception as e:\n        logger.error(\"failed to save to %s\\n%s\", file_name, e)\n        return False\n    return True\n\n\ndef load_config_rule_file():\n    \"\"\"Loads user configured rules.\"\"\"\n    global rules\n\n    if os.path.isfile(_file_path):\n        rules = _load_rule_config(_file_path)\n\n\ndef _load_rule_config(file_path: str) -> Rule:\n    loaded_rules = []\n    try:\n        with open(file_path) as config_file:\n            loaded_rules = []\n            for loaded_rule in yaml.safe_load_all(config_file):\n                rule = Rule(loaded_rule, source=file_path)\n                if logger.isEnabledFor(logging.DEBUG):\n                    logger.debug(\"load rule: %s\", rule)\n                loaded_rules.append(rule)\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"loaded %d rules from %s\", len(loaded_rules), config_file.name)\n    except Exception as e:\n        logger.error(\"failed to load from %s\\n%s\", file_path, e)\n    return Rule([Rule(loaded_rules, source=file_path), built_in_rules])\n\n\nload_config_rule_file()\n"
  },
  {
    "path": "lib/logitech_receiver/exceptions.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom .common import KwException\n\n\"\"\"Exceptions that may be raised by this API.\"\"\"\n\n\nclass NoReceiver(KwException):\n    \"\"\"Raised when trying to talk through a previously open handle, when the\n    receiver is no longer available. Should only happen if the receiver is\n    physically disconnected from the machine, or its kernel driver module is\n    unloaded.\"\"\"\n\n    pass\n\n\nclass NoSuchDevice(KwException):\n    \"\"\"Raised when trying to reach a device number not paired to the receiver.\"\"\"\n\n    pass\n\n\nclass DeviceUnreachable(KwException):\n    \"\"\"Raised when a request is made to an unreachable (turned off) device.\"\"\"\n\n    pass\n\n\nclass FeatureNotSupported(KwException):\n    \"\"\"Raised when trying to request a feature not supported by the device.\"\"\"\n\n    pass\n\n\nclass FeatureCallError(KwException):\n    \"\"\"Raised if the device replied to a feature call with an error.\"\"\"\n\n    pass\n"
  },
  {
    "path": "lib/logitech_receiver/hidpp10.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nfrom __future__ import annotations\n\nimport logging\n\nfrom typing import Any\n\nfrom typing_extensions import Protocol\n\nfrom . import common\nfrom .common import Battery\nfrom .common import BatteryLevelApproximation\nfrom .common import BatteryStatus\nfrom .common import FirmwareKind\nfrom .hidpp10_constants import NotificationFlag\nfrom .hidpp10_constants import Registers\n\nlogger = logging.getLogger(__name__)\n\n\nclass Device(Protocol):\n    def request(self, request_id, *params):\n        ...\n\n    @property\n    def kind(self) -> Any:\n        ...\n\n    @property\n    def online(self) -> bool:\n        ...\n\n    @property\n    def protocol(self) -> Any:\n        ...\n\n    @property\n    def registers(self) -> list:\n        ...\n\n\ndef read_register(device: Device, register: Registers | int, *params) -> Any:\n    assert device is not None, f\"tried to read register {register:02X} from invalid device {device}\"\n    # support long registers by adding a 2 in front of the register number\n    request_id = 0x8100 | (int(register) & 0x2FF)\n    return device.request(request_id, *params)\n\n\ndef write_register(device: Device, register: Registers | int, *value) -> Any:\n    assert device is not None, f\"tried to write register {register:02X} to invalid device {device}\"\n    # support long registers by adding a 2 in front of the register number\n    request_id = 0x8000 | (int(register) & 0x2FF)\n    return device.request(request_id, *value)\n\n\ndef get_configuration_pending_flags(receiver):\n    assert not receiver.isDevice\n    result = read_register(receiver, Registers.DEVICES_CONFIGURATION)\n    if result is not None:\n        return ord(result[:1])\n\n\ndef set_configuration_pending_flags(receiver, devices):\n    assert not receiver.isDevice\n    result = write_register(receiver, Registers.DEVICES_CONFIGURATION, devices)\n    return result is not None\n\n\nclass Hidpp10:\n    def get_battery(self, device: Device):\n        assert device is not None\n        assert device.kind is not None\n        if not device.online:\n            return\n        \"\"\"Reads a device's battery level, if provided by the HID++ 1.0 protocol.\"\"\"\n        if device.protocol and device.protocol >= 2.0:\n            # let's just assume HID++ 2.0 devices do not provide the battery info in a register\n            return\n\n        for r in (Registers.BATTERY_STATUS, Registers.BATTERY_CHARGE):\n            if r in device.registers:\n                reply = read_register(device, r)\n                if reply:\n                    return parse_battery_status(r, reply)\n                return\n\n        # the descriptor does not tell us which register this device has, try them both\n        reply = read_register(device, Registers.BATTERY_CHARGE)\n        if reply:\n            # remember this for the next time\n            device.registers.append(Registers.BATTERY_CHARGE)\n            return parse_battery_status(Registers.BATTERY_CHARGE, reply)\n\n        reply = read_register(device, Registers.BATTERY_STATUS)\n        if reply:\n            # remember this for the next time\n            device.registers.append(Registers.BATTERY_STATUS)\n            return parse_battery_status(Registers.BATTERY_STATUS, reply)\n\n    def get_firmware(self, device: Device) -> tuple[common.FirmwareInfo] | None:\n        assert device is not None\n\n        firmware = [None, None, None]\n\n        reply = read_register(device, Registers.FIRMWARE, 0x01)\n        if not reply:\n            # won't be able to read any of it now...\n            return\n\n        fw_version = common.strhex(reply[1:3])\n        fw_version = f\"{fw_version[0:2]}.{fw_version[2:4]}\"\n        reply = read_register(device, Registers.FIRMWARE, 0x02)\n        if reply:\n            fw_version += \".B\" + common.strhex(reply[1:3])\n        fw = common.FirmwareInfo(FirmwareKind.Firmware, \"\", fw_version, None)\n        firmware[0] = fw\n\n        reply = read_register(device, Registers.FIRMWARE, 0x04)\n        if reply:\n            bl_version = common.strhex(reply[1:3])\n            bl_version = f\"{bl_version[0:2]}.{bl_version[2:4]}\"\n            bl = common.FirmwareInfo(FirmwareKind.Bootloader, \"\", bl_version, None)\n            firmware[1] = bl\n\n        reply = read_register(device, Registers.FIRMWARE, 0x03)\n        if reply:\n            o_version = common.strhex(reply[1:3])\n            o_version = f\"{o_version[0:2]}.{o_version[2:4]}\"\n            o = common.FirmwareInfo(FirmwareKind.Other, \"\", o_version, None)\n            firmware[2] = o\n\n        if any(firmware):\n            return tuple(f for f in firmware if f)\n\n    def set_3leds(self, device: Device, battery_level=None, charging=None, warning=None):\n        assert device is not None\n        assert device.kind is not None\n        if not device.online:\n            return\n\n        if Registers.THREE_LEDS not in device.registers:\n            return\n\n        if battery_level is not None:\n            if battery_level < BatteryLevelApproximation.CRITICAL:\n                # 1 orange, and force blink\n                v1, v2 = 0x22, 0x00\n                warning = True\n            elif battery_level < BatteryLevelApproximation.LOW:\n                # 1 orange\n                v1, v2 = 0x22, 0x00\n            elif battery_level < BatteryLevelApproximation.GOOD:\n                # 1 green\n                v1, v2 = 0x20, 0x00\n            elif battery_level < BatteryLevelApproximation.FULL:\n                # 2 greens\n                v1, v2 = 0x20, 0x02\n            else:\n                # all 3 green\n                v1, v2 = 0x20, 0x22\n            if warning:\n                # set the blinking flag for the leds already set\n                v1 |= v1 >> 1\n                v2 |= v2 >> 1\n        elif charging:\n            # blink all green\n            v1, v2 = 0x30, 0x33\n        elif warning:\n            # 1 red\n            v1, v2 = 0x02, 0x00\n        else:\n            # turn off all leds\n            v1, v2 = 0x11, 0x11\n\n        write_register(device, Registers.THREE_LEDS, v1, v2)\n\n    def get_notification_flags(self, device: Device):\n        flags = self._get_register(device, Registers.NOTIFICATIONS)\n        if flags is not None:\n            return NotificationFlag(flags)\n\n    def set_notification_flags(self, device: Device, *flag_bits: NotificationFlag):\n        assert device is not None\n\n        # Avoid a call if the device is not online,\n        # or the device does not support registers.\n        if device.kind is not None:\n            # peripherals with protocol >= 2.0 don't support registers\n            if device.protocol and device.protocol >= 2.0:\n                return\n\n        flag_bits = sum(int(b.value) for b in flag_bits)\n        assert flag_bits & 0x00FFFFFF == flag_bits\n        result = write_register(device, Registers.NOTIFICATIONS, common.int2bytes(flag_bits, 3))\n        return result is not None\n\n    def get_device_features(self, device: Device):\n        return self._get_register(device, Registers.MOUSE_BUTTON_FLAGS)\n\n    def _get_register(self, device: Device, register: Registers | int):\n        assert device is not None\n\n        # Avoid a call if the device is not online,\n        # or the device does not support registers.\n        if device.kind is not None:\n            # peripherals with protocol >= 2.0 don't support registers\n            if device.protocol and device.protocol >= 2.0:\n                return\n\n        flags = read_register(device, register)\n        if flags is not None:\n            assert len(flags) == 3\n            return common.bytes2int(flags)\n\n\ndef parse_battery_status(register: Registers | int, reply) -> Battery | None:\n    def status_byte_to_charge(status_byte_: int) -> BatteryLevelApproximation:\n        if status_byte_ == 7:\n            charge_ = BatteryLevelApproximation.FULL\n        elif status_byte_ == 5:\n            charge_ = BatteryLevelApproximation.GOOD\n        elif status_byte_ == 3:\n            charge_ = BatteryLevelApproximation.LOW\n        elif status_byte_ == 1:\n            charge_ = BatteryLevelApproximation.CRITICAL\n        else:\n            # pure 'charging' notifications may come without a status\n            charge_ = BatteryLevelApproximation.EMPTY\n        return charge_\n\n    def status_byte_to_battery_status(status_byte_: int) -> BatteryStatus:\n        if status_byte_ == 0x30:\n            status_text_ = BatteryStatus.DISCHARGING\n        elif status_byte_ == 0x50:\n            status_text_ = BatteryStatus.RECHARGING\n        elif status_byte_ == 0x90:\n            status_text_ = BatteryStatus.FULL\n        else:\n            status_text_ = None\n        return status_text_\n\n    def charging_byte_to_status_text(charging_byte_: int) -> BatteryStatus:\n        if charging_byte_ == 0x00:\n            status_text_ = BatteryStatus.DISCHARGING\n        elif charging_byte_ & 0x21 == 0x21:\n            status_text_ = BatteryStatus.RECHARGING\n        elif charging_byte_ & 0x22 == 0x22:\n            status_text_ = BatteryStatus.FULL\n        else:\n            logger.warning(\"could not parse 0x07 battery status: %02X (level %02X)\", charging_byte_, status_byte)\n            status_text_ = None\n        return status_text_\n\n    if register == Registers.BATTERY_CHARGE:\n        charge = ord(reply[:1])\n        status_byte = ord(reply[2:3]) & 0xF0\n\n        battery_status = status_byte_to_battery_status(status_byte)\n        return Battery(charge, None, battery_status, None)\n\n    if register == Registers.BATTERY_STATUS:\n        status_byte = ord(reply[:1])\n        charging_byte = ord(reply[1:2])\n\n        status_text = charging_byte_to_status_text(charging_byte)\n        charge = status_byte_to_charge(status_byte)\n\n        if charging_byte & 0x03 and status_byte == 0:\n            # some 'charging' notifications may come with no battery level information\n            charge = None\n\n        # Return None for next charge level and voltage as these are not in HID++ 1.0 spec\n        return Battery(charge, None, status_text, None)\n"
  },
  {
    "path": "lib/logitech_receiver/hidpp10_constants.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nfrom __future__ import annotations\n\nfrom enum import IntEnum\nfrom enum import IntFlag\nfrom typing import List\n\nfrom .common import NamedInts\n\n\"\"\"HID constants for HID++ 1.0.\n\nMost of them as defined by the official Logitech HID++ 1.0\ndocumentation, some of them guessed.\n\"\"\"\n\nDEVICE_KIND = NamedInts(\n    unknown=0x00,\n    keyboard=0x01,\n    mouse=0x02,\n    numpad=0x03,\n    presenter=0x04,\n    remote=0x07,\n    trackball=0x08,\n    touchpad=0x09,\n    tablet=0x0A,\n    gamepad=0x0B,\n    joystick=0x0C,\n    headset=0x0D,  # not from Logitech documentation\n    remote_control=0x0E,  # for compatibility with HID++ 2.0\n    receiver=0x0F,  # for compatibility with HID++ 2.0\n)\n\n\nclass PowerSwitchLocation(IntEnum):\n    UNKNOWN = 0x00\n    BASE = 0x01\n    TOP_CASE = 0x02\n    EDGE_OF_TOP_RIGHT_CORNER = 0x03\n    TOP_LEFT_CORNER = 0x05\n    BOTTOM_LEFT_CORNER = 0x06\n    TOP_RIGHT_CORNER = 0x07\n    BOTTOM_RIGHT_CORNER = 0x08\n    TOP_EDGE = 0x09\n    RIGHT_EDGE = 0x0A\n    LEFT_EDGE = 0x0B\n    BOTTOM_EDGE = 0x0C\n\n    @classmethod\n    def location(cls, loc: int) -> PowerSwitchLocation:\n        try:\n            return cls(loc)\n        except ValueError:\n            return cls.UNKNOWN\n\n\nclass NotificationFlag(IntFlag):\n    \"\"\"Some flags are used both by devices and receivers.\n\n    The Logitech documentation mentions that the first and last (third)\n    byte are used for devices while the second is used for the receiver.\n    In practise, the second byte is also used for some device-specific\n    notifications (keyboard illumination level). Do not simply set all\n    notification bits if the software does not support it. For example,\n    enabling keyboard_sleep_raw makes the Sleep key a no-operation\n    unless the software is updated to handle that event.\n\n    Observations:\n    - wireless and software present seen on receivers,\n    reserved_r1b4 as well\n    - the rest work only on devices as far as we can tell right now\n    In the future would be useful to have separate enums for receiver\n    and device notification flags, but right now we don't know enough.\n    Additional flags taken from https://drive.google.com/file/d/0BxbRzx7vEV7eNDBheWY0UHM5dEU/view?usp=sharing\n    \"\"\"\n\n    @classmethod\n    def flag_names(cls, flags) -> List[str]:\n        \"\"\"Extract the names of the flags from the integer.\"\"\"\n        return flags.name.replace(\"_\", \" \").lower().split(\"|\")\n\n    NUMPAD_NUMERICAL_KEYS = 0x800000\n    F_LOCK_STATUS = 0x400000\n    ROLLER_H = 0x200000\n    BATTERY_STATUS = 0x100000  # send battery charge notifications (0x07 or 0x0D)\n    MOUSE_EXTRA_BUTTONS = 0x080000\n    ROLLER_V = 0x040000\n    POWER_KEYS = 0x020000  # system control keys such as Sleep\n    KEYBOARD_MULTIMEDIA_RAW = 0x010000  # consumer controls such as Mute and Calculator\n    MULTI_TOUCH = 0x001000  # notify on multi-touch changes\n    SOFTWARE_PRESENT = 0x000800  # software is controlling part of device behaviour\n    LINK_QUALITY = 0x000400  # notify on link quality changes\n    UI = 0x000200  # notify on UI changes\n    WIRELESS = 0x000100  # notify when the device wireless goes on/off-line\n    CONFIGURATION_COMPLETE = 0x000004\n    VOIP_TELEPHONY = 0x000002\n    THREED_GESTURE = 0x000001\n\n\ndef flags_to_str(flags, fallback: str) -> str:\n    flag_names = []\n    if flags is not None and flags is not False:\n        if flags.value == 0:\n            flag_names = (fallback,)\n        else:\n            flag_names = NotificationFlag.flag_names(flags)\n    return f\"\\n{' ':15}\".join(sorted(flag_names))\n\n\nclass ErrorCode(IntEnum):\n    INVALID_SUB_ID_COMMAND = 0x01\n    INVALID_ADDRESS = 0x02\n    INVALID_VALUE = 0x03\n    CONNECTION_REQUEST_FAILED = 0x04\n    TOO_MANY_DEVICES = 0x05\n    ALREADY_EXISTS = 0x06\n    BUSY = 0x07\n    UNKNOWN_DEVICE = 0x08\n    RESOURCE_ERROR = 0x09\n    REQUEST_UNAVAILABLE = 0x0A\n    UNSUPPORTED_PARAMETER_VALUE = 0x0B\n    WRONG_PIN_CODE = 0x0C\n\n\nclass PairingError(IntEnum):\n    DEVICE_TIMEOUT = 0x01\n    DEVICE_NOT_SUPPORTED = 0x02\n    TOO_MANY_DEVICES = 0x03\n    SEQUENCE_TIMEOUT = 0x06\n\n    @property\n    def label(self) -> str:\n        return self.name.lower().replace(\"_\", \" \")\n\n\nclass BoltPairingError(IntEnum):\n    DEVICE_TIMEOUT = 0x01\n    FAILED = 0x02\n\n    @property\n    def label(self) -> str:\n        return self.name.lower().replace(\"_\", \" \")\n\n\nclass Registers(IntEnum):\n    \"\"\"Known HID registers.\n\n    Devices usually have a (small) sub-set of these. Some registers are only\n    applicable to certain device kinds (e.g. smooth_scroll only applies to mice).\n    \"\"\"\n\n    # Generally applicable\n    NOTIFICATIONS = 0x00\n    FIRMWARE = 0xF1\n\n    # only apply to receivers\n    RECEIVER_CONNECTION = 0x02\n    RECEIVER_PAIRING = 0xB2\n    DEVICES_ACTIVITY = 0x2B3\n    RECEIVER_INFO = 0x2B5\n    BOLT_DEVICE_DISCOVERY = 0xC0\n    BOLT_PAIRING = 0x2C1\n    BOLT_UNIQUE_ID = 0x02FB\n\n    # only apply to devices\n    MOUSE_BUTTON_FLAGS = 0x01\n    KEYBOARD_HAND_DETECTION = 0x01\n    DEVICES_CONFIGURATION = 0x03\n    BATTERY_STATUS = 0x07\n    KEYBOARD_FN_SWAP = 0x09\n    BATTERY_CHARGE = 0x0D\n    KEYBOARD_ILLUMINATION = 0x17\n    THREE_LEDS = 0x51\n    MOUSE_DPI = 0x63\n\n    # notifications\n    PASSKEY_REQUEST_NOTIFICATION = 0x4D\n    PASSKEY_PRESSED_NOTIFICATION = 0x4E\n    DEVICE_DISCOVERY_NOTIFICATION = 0x4F\n    DISCOVERY_STATUS_NOTIFICATION = 0x53\n    PAIRING_STATUS_NOTIFICATION = 0x54\n\n\n# Subregisters for receiver_info register\nclass InfoSubRegisters(IntEnum):\n    SERIAL_NUMBER = 0x01  # not found on many receivers\n    FW_VERSION = 0x02\n    RECEIVER_INFORMATION = 0x03\n    PAIRING_INFORMATION = 0x20  # 0x2N, by connected device\n    EXTENDED_PAIRING_INFORMATION = 0x30  # 0x3N, by connected device\n    DEVICE_NAME = 0x40  # 0x4N, by connected device\n    BOLT_PAIRING_INFORMATION = 0x50  # 0x5N, by connected device\n    BOLT_DEVICE_NAME = 0x60  # 0x6N01, by connected device\n\n\nclass DeviceFeature(IntFlag):\n    \"\"\"Features for devices.\n\n    Flags taken from\n    https://drive.google.com/file/d/0BxbRzx7vEV7eNDBheWY0UHM5dEU/view?usp=sharing\n    \"\"\"\n\n    @classmethod\n    def flag_names(cls, flag_bits: int) -> List[str]:\n        \"\"\"Extract the names of the flags from the integer.\"\"\"\n        indexed = {item.value: item.name for item in cls}\n\n        flag_names = []\n        unknown_bits = flag_bits\n        for k in indexed:\n            # Ensure that the key (flag value) is a power of 2 (a single bit flag)\n            assert bin(k).count(\"1\") == 1\n            if k & flag_bits == k:\n                unknown_bits &= ~k\n                flag_names.append(indexed[k].replace(\"_\", \" \").lower())\n\n        # Yield any remaining unknown bits\n        if unknown_bits != 0:\n            flag_names.append(f\"unknown:{unknown_bits:06X}\")\n        return flag_names\n\n    RESERVED1 = 0x010000\n    SPECIAL_BUTTONS = 0x020000\n    ENHANCED_KEY_USAGE = 0x040000\n    FAST_FW_REV = 0x080000\n    RESERVED2 = 0x100000\n    RESERVED3 = 0x200000\n    SCROLL_ACCEL = 0x400000\n    BUTTONS_CONTROL_RESOLUTION = 0x800000\n    INHIBIT_LOCK_KEY_SOUND = 0x000001\n    RESERVED4 = 0x000002\n    MX_AIR_3D_ENGINE = 0x000004\n    HOST_CONTROL_LEDS = 0x000008\n    RESERVED5 = 0x000010\n    RESERVED6 = 0x000020\n    RESERVED7 = 0x000040\n    RESERVED8 = 0x000080\n"
  },
  {
    "path": "lib/logitech_receiver/hidpp20.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nfrom __future__ import annotations\n\nimport logging\nimport socket\nimport struct\nimport threading\n\nfrom collections import UserDict\nfrom enum import Flag\nfrom enum import IntEnum\nfrom typing import Any\nfrom typing import Dict\nfrom typing import Generator\nfrom typing import Optional\nfrom typing import Tuple\n\nimport yaml\n\nfrom solaar.i18n import _\nfrom typing_extensions import Protocol\n\nfrom . import common\nfrom . import exceptions\nfrom . import hidpp10_constants\nfrom . import special_keys\nfrom .common import Battery\nfrom .common import BatteryLevelApproximation\nfrom .common import BatteryStatus\nfrom .common import FirmwareKind\nfrom .common import NamedInt\nfrom .hidpp20_constants import DEVICE_KIND\nfrom .hidpp20_constants import ChargeLevel\nfrom .hidpp20_constants import ChargeType\nfrom .hidpp20_constants import ErrorCode\nfrom .hidpp20_constants import FeatureFlag\nfrom .hidpp20_constants import GestureId\nfrom .hidpp20_constants import ParamId\nfrom .hidpp20_constants import SupportedFeature\n\nlogger = logging.getLogger(__name__)\n\nFixedBytes5 = bytes\n\nKIND_MAP = {kind: hidpp10_constants.DEVICE_KIND[str(kind)] for kind in DEVICE_KIND}\n\n\nclass Device(Protocol):\n    def feature_request(self, feature, function=0x00, *params, no_reply=False) -> Any:\n        ...\n\n    @property\n    def features(self) -> Any:\n        ...\n\n    @property\n    def _gestures(self) -> Any:\n        ...\n\n    @property\n    def _backlight(self) -> Any:\n        ...\n\n    @property\n    def _profiles(self) -> Any:\n        ...\n\n\n# pfps: Consider adding a class method that sanitizes inputs by removing unknown bits.\n\n\nclass KeyFlag(Flag):\n    \"\"\"Capabilities and desired software handling for a control.\n\n    Ref: https://drive.google.com/file/d/10imcbmoxTJ1N510poGdsviEhoFfB_Ua4/view\n    We treat bytes 4 and 8 of `getCidInfo` as a single bitfield.\n    \"\"\"\n\n    UNUSED_8000 = 0x8000\n    UNUSED_4000 = 0x4000\n    UNUSED_2000 = 0x2000\n    UNUSED_1000 = 0x1000\n    RAW_WHEEL = 0x800\n    ANALYTICS_KEY_EVENTS = 0x400\n    FORCE_RAW_XY = 0x200\n    RAW_XY = 0x100\n    VIRTUAL = 0x80\n    PERSISTENTLY_DIVERTABLE = 0x40\n    DIVERTABLE = 0x20\n    REPROGRAMMABLE = 0x10\n    FN_SENSITIVE = 0x08\n    NONSTANDARD = 0x04\n    IS_FN = 0x02\n    MSE = 0x01\n\n\nclass MappingFlag(Flag):\n    \"\"\"Flags describing the reporting method of a control.\n\n    We treat bytes 2 and 5 of `get/setCidReporting` as a single bitfield\n    \"\"\"\n\n    UNUSED_4000 = 0x4000\n    UNUSED_1000 = 0x1000\n    RAW_WHEEL = 0x400\n    UNKNOWN_200 = 0x200  # seen on a Wireless Mouse M510 WPID 4004\n    ANALYTICS_KEY_EVENTS_REPORTING = 0x100\n    FORCE_RAW_XY_DIVERTED = 0x40\n    RAW_XY_DIVERTED = 0x10\n    PERSISTENTLY_DIVERTED = 0x04\n    DIVERTED = 0x01\n\n\nclass ChargeStatus(Flag):\n    CHARGING = 0x00\n    FULL = 0x01\n    NOT_CHARGING = 0x02\n    ERROR = 0x07\n\n\nclass FeaturesArray(dict):\n    def __init__(self, device):\n        assert device is not None\n        self.supported = True  # Actually don't know whether it is supported yet\n        self.device = device\n        self.inverse = {}\n        self.version = {}\n        self.flags = {}\n        self.count = 0\n\n    def _check(self) -> bool:\n        if not self.device.online:\n            return False\n        if self.supported is False:\n            return False\n        if self.device.protocol and self.device.protocol < 2.0:\n            self.supported = False\n            return False\n        if self.count > 0:\n            return True\n        reply = self.device.request(0x0000, struct.pack(\"!H\", SupportedFeature.FEATURE_SET))\n        if reply is not None:\n            fs_index = reply[0]\n            if fs_index:\n                count = self.device.request(fs_index << 8)\n                if count is None:\n                    logger.warning(\"FEATURE_SET found, but failed to read features count\")\n                    return False\n                else:\n                    self.count = count[0] + 1  # ROOT feature not included in count\n                    self[SupportedFeature.ROOT] = 0\n                    self[SupportedFeature.FEATURE_SET] = fs_index\n                    return True\n            else:\n                self.supported = False\n        return False\n\n    def get_feature(self, index: int) -> SupportedFeature | None:\n        feature = self.inverse.get(index)\n        if feature is not None:\n            return feature\n        elif self._check():\n            feature = self.inverse.get(index)\n            if feature is not None:\n                return feature\n            response = self.device.feature_request(SupportedFeature.FEATURE_SET, 0x10, index)\n            if response:\n                data = struct.unpack(\"!H\", response[:2])[0]\n                try:\n                    feature = SupportedFeature(data)\n                except ValueError:\n                    feature = f\"unknown:{data:04X}\"\n                self[feature] = index\n                self.version[feature] = response[3]\n                self.flags[feature] = response[2]\n                return feature\n\n    def enumerate(self):  # return all features and their index, ordered by index\n        if self._check():\n            for index in range(self.count):\n                feature = self.get_feature(index)\n                yield feature, index\n\n    def get_feature_version(self, feature: NamedInt) -> Optional[int]:\n        if self[feature]:\n            return self.version.get(feature, 0)\n\n    def get_flags(self, feature: NamedInt) -> Optional[int]:\n        if self[feature]:\n            return self.flags.get(feature, 0)\n\n    def get_hidden(self, feature: NamedInt) -> Optional[bool]:\n        if self[feature]:\n            return self.flags.get(feature, 0) & FeatureFlag.INTERNAL\n        return True\n\n    def __contains__(self, feature: NamedInt) -> bool:\n        try:\n            index = self.__getitem__(feature)\n            return index is not None and index is not False\n        except exceptions.FeatureCallError:\n            return False\n\n    def __getitem__(self, feature: NamedInt) -> Optional[int]:\n        index = super().get(feature)\n        if index is not None:\n            return index\n        elif self._check():\n            index = super().get(feature)\n            if index is not None:\n                return index\n            response = self.device.request(0x0000, struct.pack(\"!H\", feature))\n            if response:\n                index = response[0]\n                self[feature] = index if index else False\n                self.version[feature] = response[2]\n                self.flags[feature] = response[1]\n                return index if index else False\n\n    def __setitem__(self, feature, index):\n        if isinstance(super().get(feature), int):\n            self.inverse.pop(super().get(feature))\n        super().__setitem__(feature, index)\n        if index is not False:\n            self.inverse[index] = feature\n\n    def __delitem__(self, feature):\n        raise ValueError(\"Don't delete features from FeatureArray\")\n\n    def __len__(self) -> int:\n        return self.count\n\n    __bool__ = __nonzero__ = _check\n\n\nclass ReprogrammableKey:\n    \"\"\"Information about a control present on a device with the `REPROG_CONTROLS` feature.\n\n    Read-only properties:\n    - index -- index in the control ID table\n    - key -- the name of this control\n    - default_task -- the native function of this control\n    - flags -- capabilities and desired software handling of the control\n\n    Ref: https://drive.google.com/file/d/0BxbRzx7vEV7eU3VfMnRuRXktZ3M/view\n    \"\"\"\n\n    def __init__(self, device: Device, index: int, cid: int, task_id: int, flags: int):\n        self._device = device\n        self.index = index\n        self._cid = cid\n        self._tid = task_id\n        self._flags = flags\n\n    @property\n    def key(self) -> NamedInt:\n        return special_keys.CONTROL[self._cid]\n\n    @property\n    def default_task(self) -> NamedInt:\n        \"\"\"NOTE: This NamedInt is a bit mixed up, because its value is the Control ID\n        while the name is the Control ID's native task. But this makes more sense\n        than presenting details of controls vs tasks in the interface. The same\n        convention applies to `mapped_to`, `remappable_to`, `remap` in `ReprogrammableKeyV4`.\"\"\"\n        try:\n            task = str(special_keys.Task(self._tid))\n        except ValueError:\n            task = f\"unknown:{self._tid:04X}\"\n        return NamedInt(self._cid, task)\n\n    @property\n    def flags(self) -> KeyFlag:\n        return KeyFlag(self._flags)\n\n\nclass ReprogrammableKeyV4(ReprogrammableKey):\n    \"\"\"Information about a control present on a device with the `REPROG_CONTROLS_V4` feature.\n    Ref (v2): https://lekensteyn.nl/files/logitech/x1b04_specialkeysmsebuttons.html\n    Ref (v4): https://drive.google.com/file/d/10imcbmoxTJ1N510poGdsviEhoFfB_Ua4/view\n    Contains all the functionality of `ReprogrammableKey` plus remapping keys and /diverting/ them\n    in order to handle keypresses in a custom way.\n\n    Additional read-only properties:\n    - pos {int} -- position of this control on the device; 1-16 for FN-keys, otherwise 0\n    - group {int} -- the group this control belongs to; other controls with this group in their\n    `group_mask` can be remapped to this control\n    - group_mask {List[str]} -- this control can be remapped to any control ID in these groups\n    - mapped_to {NamedInt} -- which action this control is mapped to; usually itself\n    - remappable_to {List[NamedInt]} -- list of actions which this control can be remapped to\n    - mapping_flags {List[str]} -- mapping flags set on the control\n    \"\"\"\n\n    def __init__(self, device: Device, index, cid, task_id, flags, pos, group, gmask):\n        ReprogrammableKey.__init__(self, device, index, cid, task_id, flags)\n        self.pos = pos\n        self.group = group\n        self._gmask = gmask\n        self._mapping_flags = None\n        self._mapped_to = None\n\n    @property\n    def group_mask(self) -> Generator[str]:\n        return common.flag_names(special_keys.CIDGroupBit, self._gmask)\n\n    @property\n    def mapped_to(self) -> NamedInt:\n        if self._mapped_to is None:\n            self._getCidReporting()\n        self._device.keys._ensure_all_keys_queried()\n        try:\n            task = str(special_keys.Task(self._device.keys.cid_to_tid[self._mapped_to]))\n        except ValueError:\n            task = f\"Unknown_{self._mapped_to:x}\"\n        return NamedInt(self._mapped_to, task)\n\n    @property\n    def remappable_to(self):\n        self._device.keys._ensure_all_keys_queried()\n        ret = common.UnsortedNamedInts()\n        if self.group_mask:  # only keys with a non-zero gmask are remappable\n            ret[self.default_task] = self.default_task  # it should always be possible to map the key to itself\n            for g in self.group_mask:\n                g = special_keys.CidGroup[str(g)]\n                for tgt_cid in self._device.keys.group_cids[g]:\n                    cid = self._device.keys.cid_to_tid[tgt_cid]\n                    try:\n                        tgt_task = str(special_keys.Task(cid))\n                    except ValueError:\n                        tgt_task = f\"unknown:{cid:04X}\"\n                    tgt_task = NamedInt(tgt_cid, tgt_task)\n                    if tgt_task != self.default_task:  # don't put itself in twice\n                        ret[tgt_task] = tgt_task\n        return ret\n\n    @property\n    def mapping_flags(self) -> MappingFlag:\n        if self._mapping_flags is None:\n            self._getCidReporting()\n        return MappingFlag(self._mapping_flags)\n\n    def set_diverted(self, value: bool) -> None:\n        \"\"\"If set, the control is diverted temporarily and reports presses as HID++ events.\"\"\"\n        flags = {MappingFlag.DIVERTED: value}\n        self._setCidReporting(flags=flags)\n\n    def set_persistently_diverted(self, value: bool) -> None:\n        \"\"\"If set, the control is diverted permanently and reports presses as HID++ events.\"\"\"\n        flags = {MappingFlag.PERSISTENTLY_DIVERTED: value}\n        self._setCidReporting(flags=flags)\n\n    def set_rawXY_reporting(self, value: bool) -> None:\n        \"\"\"If set, the mouse temporarily reports all its raw XY events while this control is pressed as HID++ events.\"\"\"\n        flags = {MappingFlag.RAW_XY_DIVERTED: value}\n        self._setCidReporting(flags=flags)\n\n    def remap(self, to: NamedInt):\n        \"\"\"Temporarily remaps this control to another action.\"\"\"\n        self._setCidReporting(remap=int(to))\n\n    def _getCidReporting(self):\n        try:\n            mapped_data = self._device.feature_request(\n                SupportedFeature.REPROG_CONTROLS_V4,\n                0x20,\n                *tuple(struct.pack(\"!H\", self._cid)),\n            )\n            if mapped_data:\n                cid, mapping_flags_1, mapped_to = struct.unpack(\"!HBH\", mapped_data[:5])\n                if cid != self._cid and logger.isEnabledFor(logging.WARNING):\n                    logger.warning(\n                        f\"REPROG_CONTROLS_V4 endpoint getCidReporting on device {self._device} replied \"\n                        + f\"with a different control ID ({cid}) than requested ({self._cid}).\"\n                    )\n                self._mapped_to = mapped_to if mapped_to != 0 else self._cid\n                if len(mapped_data) > 5:\n                    (mapping_flags_2,) = struct.unpack(\"!B\", mapped_data[5:6])\n                else:\n                    mapping_flags_2 = 0\n                self._mapping_flags = mapping_flags_1 | (mapping_flags_2 << 8)\n            else:\n                raise exceptions.FeatureCallError(msg=\"No reply from device.\")\n        except exceptions.FeatureCallError:  # if the key hasn't ever been configured only produce a warning\n            if logger.isEnabledFor(logging.WARNING):\n                logger.warning(\n                    f\"Feature Call Error in _getCidReporting on device {self._device} for cid {self._cid} - use defaults\"\n                )\n            # Clear flags and set mapping target to self\n            self._mapping_flags = 0\n            self._mapped_to = self._cid\n\n    def _setCidReporting(self, flags: Dict[NamedInt, bool] = None, remap: int = 0):\n        \"\"\"Sends a `setCidReporting` request with the given parameters.\n\n        Raises an exception if the parameters are invalid.\n\n        Parameters\n        ----------\n        flags\n            A dictionary of which mapping flags to set/unset.\n        remap\n            Which control ID to remap to; or 0 to keep current mapping.\n        \"\"\"\n        flags = flags if flags else {}  # See flake8 B006\n\n        # The capability required to set a given reporting flag.\n        FLAG_TO_CAPABILITY = {\n            MappingFlag.DIVERTED: KeyFlag.DIVERTABLE,\n            MappingFlag.PERSISTENTLY_DIVERTED: KeyFlag.PERSISTENTLY_DIVERTABLE,\n            MappingFlag.ANALYTICS_KEY_EVENTS_REPORTING: KeyFlag.ANALYTICS_KEY_EVENTS,\n            MappingFlag.FORCE_RAW_XY_DIVERTED: KeyFlag.FORCE_RAW_XY,\n            MappingFlag.RAW_XY_DIVERTED: KeyFlag.RAW_XY,\n        }\n\n        bfield = 0\n        for mapping_flag, activated in flags.items():\n            key_flag = FLAG_TO_CAPABILITY[mapping_flag]\n            if activated and key_flag not in self.flags:\n                raise exceptions.FeatureNotSupported(\n                    msg=f'Tried to set mapping flag \"{mapping_flag}\" on control \"{self.key}\" '\n                    + f'which does not support \"{key_flag}\" on device {self._device}.'\n                )\n            bfield |= mapping_flag.value if activated else 0\n            bfield |= mapping_flag.value << 1  # The 'Xvalid' bit\n            if self._mapping_flags:  # update flags if already read\n                if activated:\n                    self._mapping_flags |= mapping_flag.value\n                else:\n                    self._mapping_flags &= ~mapping_flag.value\n\n        if remap != 0 and remap not in self.remappable_to:\n            raise exceptions.FeatureNotSupported(\n                msg=f'Tried to remap control \"{self.key}\" to a control ID {remap} which it is not remappable to '\n                + f\"on device {self._device}.\"\n            )\n        if remap != 0:  # update mapping if changing (even if not already read)\n            self._mapped_to = remap\n\n        pkt = tuple(struct.pack(\"!HBH\", self._cid, bfield & 0xFF, remap))\n        # TODO: to fully support version 4 of REPROG_CONTROLS_V4, append `(bfield >> 8) & 0xff` here.\n        # But older devices might behave oddly given that byte, so we don't send it.\n        ret = self._device.feature_request(SupportedFeature.REPROG_CONTROLS_V4, 0x30, *pkt)\n        if ret is None or struct.unpack(\"!BBBBB\", ret[:5]) != pkt and logger.isEnabledFor(logging.DEBUG):\n            logger.debug(f\"REPROG_CONTROLS_v4 setCidReporting on device {self._device} didn't echo request packet.\")\n\n\nclass PersistentRemappableAction:\n    def __init__(self, device, index, cid, actionId, remapped, modifierMask, cidStatus):\n        self._device = device\n        self.index = index\n        self._cid = cid\n        self.actionId = actionId\n        self.remapped = remapped\n        self._modifierMask = modifierMask\n        self.cidStatus = cidStatus\n\n    @property\n    def key(self) -> NamedInt:\n        return special_keys.CONTROL[self._cid]\n\n    @property\n    def actionType(self) -> NamedInt:\n        return special_keys.ACTIONID[self.actionId]\n\n    @property\n    def action(self):\n        if self.actionId == special_keys.ACTIONID.Empty:\n            return None\n        elif self.actionId == special_keys.ACTIONID.Key:\n            return f\"Key: {str(self.modifiers)}{str(self.remapped)}\"\n        elif self.actionId == special_keys.ACTIONID.Mouse:\n            return f\"Mouse Button: {str(self.remapped)}\"\n        elif self.actionId == special_keys.ACTIONID.Xdisp:\n            return f\"X Displacement {str(self.remapped)}\"\n        elif self.actionId == special_keys.ACTIONID.Ydisp:\n            return f\"Y Displacement {str(self.remapped)}\"\n        elif self.actionId == special_keys.ACTIONID.Vscroll:\n            return f\"Vertical Scroll {str(self.remapped)}\"\n        elif self.actionId == special_keys.ACTIONID.Hscroll:\n            return f\"Horizontal Scroll: {str(self.remapped)}\"\n        elif self.actionId == special_keys.ACTIONID.Consumer:\n            return f\"Consumer: {str(self.remapped)}\"\n        elif self.actionId == special_keys.ACTIONID.Internal:\n            return f\"Internal Action {str(self.remapped)}\"\n        elif self.actionId == special_keys.ACTIONID.Internal:\n            return f\"Power {str(self.remapped)}\"\n        else:\n            return \"Unknown\"\n\n    @property\n    def modifiers(self):\n        return special_keys.modifiers[self._modifierMask]\n\n    @property\n    def data_bytes(self):\n        return (\n            common.int2bytes(self.actionId, 1) + common.int2bytes(self.remapped, 2) + common.int2bytes(self._modifierMask, 1)\n        )\n\n    def remap(self, data_bytes):\n        cid = common.int2bytes(self._cid, 2)\n        if common.bytes2int(data_bytes) == special_keys.KEYS_Default:  # map back to default\n            self._device.feature_request(SupportedFeature.PERSISTENT_REMAPPABLE_ACTION, 0x50, cid, 0xFF)\n            self._device.remap_keys._query_key(self.index)\n            return self._device.remap_keys.keys[self.index].data_bytes\n        else:\n            self.actionId, self.remapped, self._modifierMask = struct.unpack(\"!BHB\", data_bytes)\n            self.cidStatus = 0x01\n            self._device.feature_request(SupportedFeature.PERSISTENT_REMAPPABLE_ACTION, 0x40, cid, 0xFF, data_bytes)\n            return True\n\n\nclass KeysArray:\n    \"\"\"A sequence of key mappings supported by a HID++ 2.0 device.\"\"\"\n\n    def __init__(self, device, count, version):\n        assert device is not None\n        self.device = device\n        self.lock = threading.Lock()\n        if SupportedFeature.REPROG_CONTROLS_V4 in self.device.features:\n            self.keyversion = SupportedFeature.REPROG_CONTROLS_V4\n        elif SupportedFeature.REPROG_CONTROLS_V2 in self.device.features:\n            self.keyversion = SupportedFeature.REPROG_CONTROLS_V2\n        else:\n            if logger.isEnabledFor(logging.ERROR):\n                logger.error(f\"Trying to read keys on device {device} which has no REPROG_CONTROLS(_VX) support.\")\n            self.keyversion = None\n        self.keys = [None] * count\n\n    def _ensure_all_keys_queried(self):\n        \"\"\"The retrieval of key information is lazy, but for certain functionality\n        we need to know all keys. This function makes sure that's the case.\"\"\"\n        with self.lock:  # don't want two threads doing this\n            for i, k in enumerate(self.keys):\n                if k is None:\n                    self._query_key(i)\n\n    def __getitem__(self, index):\n        if isinstance(index, int):\n            if index < 0 or index >= len(self.keys):\n                raise IndexError(index)\n\n            if self.keys[index] is None:\n                self._query_key(index)\n\n            return self.keys[index]\n\n        elif isinstance(index, slice):\n            indices = index.indices(len(self.keys))\n            return [self.__getitem__(i) for i in range(*indices)]\n\n    def index(self, value):\n        self._ensure_all_keys_queried()\n        for index, k in enumerate(self.keys):\n            if k is not None and int(value) == int(k.key):\n                return index\n\n    def __iter__(self):\n        for k in range(0, len(self.keys)):\n            yield self.__getitem__(k)\n\n    def __len__(self):\n        return len(self.keys)\n\n\nclass KeysArrayV2(KeysArray):\n    def __init__(self, device: Device, count, version=1):\n        super().__init__(device, count, version)\n        \"\"\"The mapping from Control IDs to their native Task IDs.\n        For example, Control \"Left Button\" is mapped to Task \"Left Click\".\n        When remapping controls, we point the control we want to remap\n        at a target Control ID rather than a target Task ID. This has the\n        effect of performing the native task of the target control,\n        even if the target itself is also remapped. So remapping\n        is not recursive.\"\"\"\n        self.cid_to_tid = {}\n        \"\"\"The mapping from Control ID groups to Controls IDs that belong to it.\n        A key k can only be remapped to targets in groups within k.group_mask.\"\"\"\n        self.group_cids = {g: [] for g in special_keys.CidGroup}\n\n    def _query_key(self, index: int):\n        if index < 0 or index >= len(self.keys):\n            raise IndexError(index)\n        keydata = self.device.feature_request(SupportedFeature.REPROG_CONTROLS, 0x10, index)\n        if keydata:\n            cid, task_id, flags = struct.unpack(\"!HHB\", keydata[:5])\n            self.keys[index] = ReprogrammableKey(self.device, index, cid, task_id, flags)\n            self.cid_to_tid[cid] = task_id\n        elif logger.isEnabledFor(logging.WARNING):\n            logger.warning(f\"Key with index {index} was expected to exist but device doesn't report it.\")\n\n\nclass KeysArrayV4(KeysArrayV2):\n    def __init__(self, device, count):\n        super().__init__(device, count, 4)\n\n    def _query_key(self, index: int):\n        if index < 0 or index >= len(self.keys):\n            raise IndexError(index)\n        keydata = self.device.feature_request(SupportedFeature.REPROG_CONTROLS_V4, 0x10, index)\n        if keydata:\n            cid, task_id, flags1, pos, group, gmask, flags2 = struct.unpack(\"!HHBBBBB\", keydata[:9])\n            flags = flags1 | (flags2 << 8)\n            self.keys[index] = ReprogrammableKeyV4(self.device, index, cid, task_id, flags, pos, group, gmask)\n            self.cid_to_tid[cid] = task_id\n            if group != 0:  # 0 = does not belong to a group\n                self.group_cids[special_keys.CidGroup(group)].append(cid)\n        elif logger.isEnabledFor(logging.WARNING):\n            logger.warning(f\"Key with index {index} was expected to exist but device doesn't report it.\")\n\n\n# we are only interested in the current host, so use 0xFF for the host throughout\nclass KeysArrayPersistent(KeysArray):\n    def __init__(self, device, count):\n        super().__init__(device, count, 5)\n        self._capabilities = None\n\n    @property\n    def capabilities(self):\n        if self._capabilities is None and self.device.online:\n            capabilities = self.device.feature_request(SupportedFeature.PERSISTENT_REMAPPABLE_ACTION, 0x00)\n            assert capabilities, \"Oops, persistent remappable key capabilities cannot be retrieved!\"\n            self._capabilities = struct.unpack(\"!H\", capabilities[:2])[0]  # flags saying what the mappings are possible\n        return self._capabilities\n\n    def _query_key(self, index: int):\n        if index < 0 or index >= len(self.keys):\n            raise IndexError(index)\n        keydata = self.device.feature_request(SupportedFeature.PERSISTENT_REMAPPABLE_ACTION, 0x20, index, 0xFF)\n        if keydata:\n            key = struct.unpack(\"!H\", keydata[:2])[0]\n            mapped_data = self.device.feature_request(\n                SupportedFeature.PERSISTENT_REMAPPABLE_ACTION,\n                0x30,\n                key >> 8,\n                key & 0xFF,\n                0xFF,\n            )\n            if mapped_data:\n                _ignore, _ignore, actionId, remapped, modifiers, status = struct.unpack(\"!HBBHBB\", mapped_data[:8])\n            else:\n                actionId = remapped = modifiers = status = 0\n            actionId = special_keys.ACTIONID[actionId]\n            if actionId == special_keys.ACTIONID.Key:\n                remapped = special_keys.USB_HID_KEYCODES[remapped]\n            elif actionId == special_keys.ACTIONID.Mouse:\n                remapped = special_keys.MOUSE_BUTTONS[remapped]\n            elif actionId == special_keys.ACTIONID.Hscroll:\n                try:\n                    remapped = special_keys.HorizontalScroll(remapped)\n                except ValueError:\n                    remapped = f\"unknown horizontal scroll:{remapped:04X}\"\n            elif actionId == special_keys.ACTIONID.Consumer:\n                remapped = special_keys.HID_CONSUMERCODES[remapped]\n            elif actionId == special_keys.ACTIONID.Empty:  # purge data from empty value\n                remapped = modifiers = 0\n            self.keys[index] = PersistentRemappableAction(\n                self.device,\n                index,\n                key,\n                actionId,\n                remapped,\n                modifiers,\n                status,\n            )\n        elif logger.isEnabledFor(logging.WARNING):\n            logger.warning(f\"Key with index {index} was expected to exist but device doesn't report it.\")\n\n\nclass SubParam:\n    __slots__ = (\"id\", \"length\", \"minimum\", \"maximum\", \"widget\")\n\n    def __init__(self, id, length, minimum=None, maximum=None, widget=None):\n        self.id = id\n        self.length = length\n        self.minimum = minimum if minimum is not None else 0\n        self.maximum = maximum if maximum is not None else ((1 << 8 * length) - 1)\n        self.widget = widget if widget is not None else \"Scale\"\n\n    def __str__(self):\n        return self.id\n\n    def __repr__(self):\n        return self.id\n\n\nSUB_PARAM = {  # (byte count, minimum, maximum)\n    ParamId.EXTRA_CAPABILITIES: None,  # ignore\n    ParamId.PIXEL_ZONE: (  # TODO: replace min and max with the correct values\n        SubParam(\"left\", 2, 0x0000, 0xFFFF, \"SpinButton\"),\n        SubParam(\"bottom\", 2, 0x0000, 0xFFFF, \"SpinButton\"),\n        SubParam(\"width\", 2, 0x0000, 0xFFFF, \"SpinButton\"),\n        SubParam(\"height\", 2, 0x0000, 0xFFFF, \"SpinButton\"),\n    ),\n    ParamId.RATIO_ZONE: (  # TODO: replace min and max with the correct values\n        SubParam(\"left\", 1, 0x00, 0xFF, \"SpinButton\"),\n        SubParam(\"bottom\", 1, 0x00, 0xFF, \"SpinButton\"),\n        SubParam(\"width\", 1, 0x00, 0xFF, \"SpinButton\"),\n        SubParam(\"height\", 1, 0x00, 0xFF, \"SpinButton\"),\n    ),\n    ParamId.SCALE_FACTOR: (SubParam(\"scale\", 2, 0x002E, 0x01FF, \"Scale\"),),\n}\n\n\nclass SpecGesture(IntEnum):\n    \"\"\"Spec IDs for feature GESTURE_2.\"\"\"\n\n    DVI_FIELD_WIDTH = 1\n    FIELD_WIDTHS = 2\n    PERIOD_UNIT = 3\n    RESOLUTION = 4\n    MULTIPLIER = 5\n    SENSOR_SIZE = 6\n    FINGER_WIDTH_AND_HEIGHT = 7\n    FINGER_MAJOR_MINOR_AXIS = 8\n    FINGER_FORCE = 9\n    ZONE = 10\n\n    def __str__(self):\n        return f\"{self.name.replace('_', ' ').lower()}\"\n\n\nclass ActionId(IntEnum):\n    \"\"\"Action IDs for feature GESTURE_2.\"\"\"\n\n    MOVE_POINTER = 1\n    SCROLL_HORIZONTAL = 2\n    WHEEL_SCROLLING = 3\n    SCROLL_VERTICAL = 4\n    SCROLL_OR_PAGE_XY = 5\n    SCROLL_OR_PAGE_HORIZONTAL = 6\n    PAGE_SCREEN = 7\n    DRAG = 8\n    SECONDARY_DRAG = 9\n    ZOOM = 10\n    SCROLL_HORIZONTAL_ONLY = 11\n    SCROLL_VERTICAL_ONLY = 12\n\n\nclass Gesture:\n    def __init__(self, device, low, high, next_index, next_diversion_index):\n        self._device = device\n        self.id = low\n        self.gesture = GestureId(low)\n        self.can_be_enabled = high & 0x01\n        self.can_be_diverted = high & 0x02\n        self.show_in_ui = high & 0x04\n        self.desired_software_default = high & 0x08\n        self.persistent = high & 0x10\n        self.default_enabled = high & 0x20\n        self.index = next_index if self.can_be_enabled or self.default_enabled else None\n        self.diversion_index = next_diversion_index if self.can_be_diverted else None\n        self._enabled = None\n        self._diverted = None\n\n    def _offset_mask(self, index):  # offset and mask\n        if index is not None:\n            offset = index >> 3  # 8 gestures per byte\n            mask = 0x1 << (index % 8)\n            return offset, mask\n        else:\n            return None, None\n\n    def enable_offset_mask(self):\n        return self._offset_mask(self.index)\n\n    def diversion_offset_mask(self):\n        return self._offset_mask(self.diversion_index)\n\n    def enabled(self):  # is the gesture enabled?\n        if self._enabled is None and self.index is not None:\n            offset, mask = self.enable_offset_mask()\n            result = self._device.feature_request(SupportedFeature.GESTURE_2, 0x10, offset, 0x01, mask)\n            self._enabled = bool(result[0] & mask) if result else None\n        return self._enabled\n\n    def set(self, enable):  # enable or disable the gesture\n        if not self.can_be_enabled:\n            return None\n        if self.index is not None:\n            offset, mask = self.enable_offset_mask()\n            reply = self._device.feature_request(\n                SupportedFeature.GESTURE_2, 0x20, offset, 0x01, mask, mask if enable else 0x00\n            )\n            return reply\n\n    def diverted(self):  # is the gesture diverted?\n        if self._diverted is None and self.diversion_index is not None:\n            offset, mask = self.diversion_offset_mask()\n            result = self._device.feature_request(SupportedFeature.GESTURE_2, 0x30, offset, 0x01, mask)\n            self._diverted = bool(result[0] & mask) if result else None\n        return self._diverted\n\n    def divert(self, diverted):  # divert or undivert the gesture\n        if not self.can_be_diverted:\n            return None\n        if self.diversion_index is not None:\n            offset, mask = self.diversion_offset_mask()\n            reply = self._device.feature_request(\n                SupportedFeature.GESTURE_2,\n                0x40,\n                offset,\n                0x01,\n                mask,\n                mask if diverted else 0x00,\n            )\n            return reply\n\n    def as_int(self):\n        return self.gesture\n\n    def __int__(self):\n        return self.id\n\n    def __repr__(self):\n        return f\"<Gesture {self.gesture} index={self.index} diversion_index={self.diversion_index}>\"\n\n    # allow a gesture to be used as a settings reader/writer to enable and disable the gesture\n    read = enabled\n    write = set\n\n\nclass Param:\n    def __init__(self, device, low: int, high, next_param_index):\n        self._device = device\n        self.id = low\n        self.param = ParamId(low)\n        self.size = high & 0x0F\n        self.show_in_ui = bool(high & 0x1F)\n        self._value = None\n        self._default_value = None\n        self.index = next_param_index\n\n    @property\n    def sub_params(self):\n        return SUB_PARAM.get(self.id, None)\n\n    @property\n    def value(self):\n        return self._value if self._value is not None else self.read()\n\n    def read(self):  # returns the bytes for the parameter\n        result = self._device.feature_request(SupportedFeature.GESTURE_2, 0x70, self.index, 0xFF)\n        if result:\n            self._value = common.bytes2int(result[: self.size])\n            return self._value\n\n    @property\n    def default_value(self):\n        if self._default_value is None:\n            self._default_value = self._read_default()\n        return self._default_value\n\n    def _read_default(self):\n        result = self._device.feature_request(SupportedFeature.GESTURE_2, 0x60, self.index, 0xFF)\n        if result:\n            self._default_value = common.bytes2int(result[: self.size])\n            return self._default_value\n\n    def write(self, bytes):\n        self._value = bytes\n        return self._device.feature_request(SupportedFeature.GESTURE_2, 0x80, self.index, bytes, 0xFF)\n\n    def __str__(self):\n        return str(self.param)\n\n    def __int__(self):\n        return self.id\n\n\nclass Spec:\n    def __init__(self, device, low: int, high):\n        self._device = device\n        self.id = low\n        try:\n            self.spec = SpecGesture(low)\n        except ValueError:\n            self.spec = f\"unknown:{low:04X}\"\n        self.byte_count = high & 0x0F\n        self._value = None\n\n    @property\n    def value(self):\n        if self._value is None:\n            self._value = self.read()\n        return self._value\n\n    def read(self):\n        try:\n            value = self._device.feature_request(SupportedFeature.GESTURE_2, 0x50, self.id, 0xFF)\n        except exceptions.FeatureCallError:  # some calls produce an error (notably spec 5 multiplier on K400Plus)\n            if logger.isEnabledFor(logging.WARNING):\n                logger.warning(\n                    f\"Feature Call Error reading Gesture Spec on device {self._device} for spec {self.id} - use None\"\n                )\n            return None\n        return common.bytes2int(value[: self.byte_count])\n\n    def __repr__(self):\n        return f\"[{self.spec}={self.value}]\"\n\n\nclass Gestures:\n    \"\"\"Information about the gestures that a device supports.\n    Right now only some information fields are supported.\n    WARNING: Assumes that parameters are always global, which is not the case.\n    \"\"\"\n\n    def __init__(self, device):\n        self.device = device\n        self.gestures = {}\n        self.params = {}\n        self.specs = {}\n        index = 0\n        next_gesture_index = next_divsn_index = next_param_index = 0\n        field_high = 0x00\n        while field_high != 0x01:  # end of fields\n            # retrieve the next eight fields\n            fields = device.feature_request(SupportedFeature.GESTURE_2, 0x00, index >> 8, index & 0xFF)\n            if not fields:\n                break\n            for offset in range(8):\n                field_high = fields[offset * 2]\n                field_low = fields[offset * 2 + 1]\n                if field_high == 0x1:  # end of fields\n                    break\n                elif field_high & 0x80:\n                    gesture = Gesture(device, field_low, field_high, next_gesture_index, next_divsn_index)\n                    next_gesture_index = next_gesture_index if gesture.index is None else next_gesture_index + 1\n                    next_divsn_index = next_divsn_index if gesture.diversion_index is None else next_divsn_index + 1\n                    self.gestures[gesture.gesture] = gesture\n                elif field_high & 0xF0 == 0x30 or field_high & 0xF0 == 0x20:\n                    param = Param(device, field_low, field_high, next_param_index)\n                    next_param_index = next_param_index + 1\n                    self.params[param.param] = param\n                elif field_high == 0x04:\n                    if field_low != 0x00:\n                        logger.error(f\"Unimplemented GESTURE_2 grouping {field_low} {field_high} found.\")\n                elif field_high & 0xF0 == 0x40:\n                    spec = Spec(device, field_low, field_high)\n                    self.specs[spec.spec] = spec\n                else:\n                    logger.warning(f\"Unimplemented GESTURE_2 field {field_low} {field_high} found.\")\n                index += 1\n\n    def gesture(self, gesture):\n        return self.gestures.get(gesture, None)\n\n    def gesture_enabled(self, gesture):  # is the gesture enabled?\n        g = self.gestures.get(gesture, None)\n        return g.enabled() if g else None\n\n    def enable_gesture(self, gesture):\n        g = self.gestures.get(gesture, None)\n        return g.set(True) if g else None\n\n    def disable_gesture(self, gesture):\n        g = self.gestures.get(gesture, None)\n        return g.set(False) if g else None\n\n    def param(self, param):\n        return self.params.get(param, None)\n\n    def get_param(self, param):\n        g = self.params.get(param, None)\n        return g.read() if g else None\n\n    def set_param(self, param, value):\n        g = self.params.get(param, None)\n        return g.write(value) if g else None\n\n\nclass Backlight:\n    \"\"\"Information about the current settings of x1982 Backlight2 v3, but also works for previous versions\"\"\"\n\n    def __init__(self, device):\n        response = device.feature_request(SupportedFeature.BACKLIGHT2, 0x00)\n        if not response:\n            raise exceptions.FeatureCallError(msg=\"No reply from device.\")\n        self.device = device\n        self.enabled, self.options, supported, effects, self.level, self.dho, self.dhi, self.dpow = struct.unpack(\n            \"<BBBHBHHH\", response[:12]\n        )\n        self.auto_supported = supported & 0x08\n        self.temp_supported = supported & 0x10\n        self.perm_supported = supported & 0x20\n        self.mode = (self.options >> 3) & 0x03\n\n    def write(self):\n        self.options = (self.options & 0x07) | (self.mode << 3)\n        level = self.level if self.mode == 0x3 else 0\n        data_bytes = struct.pack(\"<BBBBHHH\", self.enabled, self.options, 0xFF, level, self.dho, self.dhi, self.dpow)\n        return self.device.feature_request(SupportedFeature.BACKLIGHT2, 0x10, data_bytes)\n\n\nclass LEDParam:\n    color = \"color\"\n    speed = \"speed\"\n    period = \"period\"\n    intensity = \"intensity\"\n    ramp = \"ramp\"\n    form = \"form\"\n    saturation = \"saturation\"\n\n\nclass LedRampChoice(IntEnum):\n    DEFAULT = 0\n    YES = 1\n    NO = 2\n\n\nclass LedFormChoices(IntEnum):\n    DEFAULT = 0\n    SINE = 1\n    SQUARE = 2\n    TRIANGLE = 3\n    SAWTOOTH = 4\n    SHARKFIN = 5\n    EXPONENTIAL = 6\n\n\nLEDParamSize = {\n    LEDParam.color: 3,\n    LEDParam.speed: 1,\n    LEDParam.period: 2,\n    LEDParam.intensity: 1,\n    LEDParam.ramp: 1,\n    LEDParam.form: 1,\n    LEDParam.saturation: 1,\n}\n# not implemented from x8070 Wave=4, Stars=5, Press=6, Audio=7\n# not implemented from x8071 Custom=12, Kitt=13, HSVPulsing=20,\n# WaveC=22, RippleC=23, SignatureActive=24, SignaturePassive=25\nLEDEffects = {\n    0x00: [NamedInt(0x00, _(\"Disabled\")), {}],\n    0x01: [NamedInt(0x01, _(\"Static\")), {LEDParam.color: 0, LEDParam.ramp: 3}],\n    0x02: [NamedInt(0x02, _(\"Pulse\")), {LEDParam.color: 0, LEDParam.speed: 3}],\n    0x03: [NamedInt(0x03, _(\"Cycle\")), {LEDParam.period: 5, LEDParam.intensity: 7}],\n    0x08: [NamedInt(0x08, _(\"Boot\")), {}],\n    0x09: [NamedInt(0x09, _(\"Demo\")), {}],\n    0x0A: [\n        NamedInt(0x0A, _(\"Breathe\")),\n        {LEDParam.color: 0, LEDParam.period: 3, LEDParam.form: 5, LEDParam.intensity: 6},\n    ],\n    0x0B: [NamedInt(0x0B, _(\"Ripple\")), {LEDParam.color: 0, LEDParam.period: 4}],\n    0x0E: [NamedInt(0x0E, _(\"Decomposition\")), {LEDParam.period: 6, LEDParam.intensity: 8}],\n    0x0F: [NamedInt(0x0F, _(\"Signature1\")), {LEDParam.period: 5, LEDParam.intensity: 7}],\n    0x10: [NamedInt(0x10, _(\"Signature2\")), {LEDParam.period: 5, LEDParam.intensity: 7}],\n    0x15: [NamedInt(0x15, _(\"CycleS\")), {LEDParam.saturation: 1, LEDParam.period: 6, LEDParam.intensity: 8}],\n}\n\n\nclass LEDEffectSetting:  # an effect plus its parameters\n    def __init__(self, **kwargs):\n        self.ID = None\n        for key, val in kwargs.items():\n            setattr(self, key, val)\n\n    @classmethod\n    def from_bytes(cls, bytes, options=None):\n        ID = next((ze.ID for ze in options if ze.index == bytes[0]), None) if options is not None else bytes[0]\n        effect = LEDEffects[ID] if ID in LEDEffects else None\n        args = {\"ID\": effect[0] if effect else None}\n        if effect:\n            for p, b in effect[1].items():\n                args[str(p)] = common.bytes2int(bytes[1 + b : 1 + b + LEDParamSize[p]])\n        else:\n            args[\"bytes\"] = bytes\n        return cls(**args)\n\n    def to_bytes(self, options=None):\n        ID = self.ID\n        if ID is None:\n            return self.bytes if hasattr(self, \"bytes\") else b\"\\xff\" * 11\n        else:\n            bs = [0] * 10\n            for p, b in LEDEffects[ID][1].items():\n                bs[b : b + LEDParamSize[p]] = common.int2bytes(getattr(self, str(p), 0), LEDParamSize[p])\n            if options is not None:\n                ID = next((ze.index for ze in options if ze.ID == ID), None)\n            result = common.int2bytes(ID, 1) + bytes(bs)\n            return result\n\n    @classmethod\n    def from_yaml(cls, loader, node):\n        return cls(**loader.construct_mapping(node))\n\n    @classmethod\n    def to_yaml(cls, dumper, data):\n        return dumper.represent_mapping(\"!LEDEffectSetting\", data.__dict__, flow_style=True)\n\n    def __eq__(self, other):\n        return isinstance(other, self.__class__) and self.to_bytes() == other.to_bytes()\n\n    def __str__(self):\n        return yaml.dump(self, width=float(\"inf\")).rstrip(\"\\n\")\n\n\nyaml.SafeLoader.add_constructor(\"!LEDEffectSetting\", LEDEffectSetting.from_yaml)\nyaml.add_representer(LEDEffectSetting, LEDEffectSetting.to_yaml)\n\n\nclass LEDEffectInfo:  # an effect that a zone can do\n    def __init__(self, feature, function, device, zindex, eindex):\n        info = device.feature_request(feature, function, zindex, eindex, 0x00)\n        self.zindex, self.index, self.ID, self.capabilities, self.period = struct.unpack(\"!BBHHH\", info[0:8])\n\n    def __str__(self):\n        return f\"LEDEffectInfo({self.zindex}, {self.index}, {self.ID}, {self.capabilities: x}, {self.period})\"\n\n\nLEDZoneLocations = common.NamedInts()\nLEDZoneLocations[0x00] = _(\"Unknown Location\")\nLEDZoneLocations[0x01] = _(\"Primary\")\nLEDZoneLocations[0x02] = _(\"Logo\")\nLEDZoneLocations[0x03] = _(\"Left Side\")\nLEDZoneLocations[0x04] = _(\"Right Side\")\nLEDZoneLocations[0x05] = _(\"Combined\")\nLEDZoneLocations[0x06] = _(\"Primary 1\")\nLEDZoneLocations[0x07] = _(\"Primary 2\")\nLEDZoneLocations[0x08] = _(\"Primary 3\")\nLEDZoneLocations[0x09] = _(\"Primary 4\")\nLEDZoneLocations[0x0A] = _(\"Primary 5\")\nLEDZoneLocations[0x0B] = _(\"Primary 6\")\n\n\nclass LEDZoneInfo:  # effects that a zone can do\n    def __init__(self, feature, function, offset, effect_function, device, index):\n        info = device.feature_request(feature, function, index, 0xFF, 0x00)\n        self.location, self.count = struct.unpack(\"!HB\", info[1 + offset : 4 + offset])\n        self.index = index\n        self.location = LEDZoneLocations[self.location] if LEDZoneLocations[self.location] else self.location\n        self.effects = []\n        for i in range(0, self.count):\n            self.effects.append(LEDEffectInfo(feature, effect_function, device, index, i))\n\n    def to_command(self, setting):\n        for i in range(0, len(self.effects)):\n            e = self.effects[i]\n            if e.ID == setting.ID:\n                return common.int2bytes(self.index, 1) + common.int2bytes(i, 1) + setting.to_bytes()[1:]\n        return None\n\n    def __str__(self):\n        return f\"LEDZoneInfo({self.index}, {self.location}, {[str(z) for z in self.effects]}\"\n\n\nclass LEDEffectsInfo:  # effects that the LEDs can do, using COLOR_LED_EFFECTS\n    def __init__(self, device):\n        self.device = device\n        info = device.feature_request(SupportedFeature.COLOR_LED_EFFECTS, 0x00)\n        self.count, _, capabilities = struct.unpack(\"!BHH\", info[0:5])\n        self.readable = capabilities & 0x1\n        self.zones = []\n        for i in range(0, self.count):\n            self.zones.append(LEDZoneInfo(SupportedFeature.COLOR_LED_EFFECTS, 0x10, 0, 0x20, device, i))\n\n    def to_command(self, index, setting):\n        return self.zones[index].to_command(setting)\n\n    def __str__(self):\n        zones = \"\\n\".join([str(z) for z in self.zones])\n        return f\"LEDEffectsInfo({self.device}, readable {self.readable}\\n{zones})\"\n\n\nclass RGBEffectsInfo(LEDEffectsInfo):  # effects that the LEDs can do using RGB_EFFECTS\n    def __init__(self, device):\n        self.device = device\n        info = device.feature_request(SupportedFeature.RGB_EFFECTS, 0x00, 0xFF, 0xFF, 0x00)\n        _, _, self.count, _, capabilities = struct.unpack(\"!BBBHH\", info[0:7])\n        self.readable = capabilities & 0x1\n        self.zones = []\n        for i in range(0, self.count):\n            self.zones.append(LEDZoneInfo(SupportedFeature.RGB_EFFECTS, 0x00, 1, 0x00, device, i))\n\n\nclass ButtonBehavior(IntEnum):\n    MACRO_EXECUTE = 0x0\n    MACRO_STOP = 0x1\n    MACRO_STOP_ALL = 0x2\n    SEND = 0x8\n    FUNCTION = 0x9\n\n\nclass ButtonMappingType(IntEnum):\n    NO_ACTION = 0x0\n    BUTTON = 0x1\n    MODIFIER_AND_KEY = 0x2\n    CONSUMER_KEY = 0x3\n\n\nclass ButtonFunctions(IntEnum):\n    NO_ACTION = 0x0\n    TILT_LEFT = 0x1\n    TILT_RIGHT = 0x2\n    NEXT_DPI = 0x3\n    PREVIOUS_DPI = 0x4\n    CYCLE_DPI = 0x5\n    DEFAULT_DPI = 0x6\n    SHIFT_DPI = 0x7\n    NEXT_PROFILE = 0x8\n    PREVIOUS_PROFILE = 0x9\n    CYCLE_PROFILE = 0xA\n    G_SHIFT = 0xB\n    BATTERY_STATUS = 0xC\n    PROFILE_SELECT = 0xD\n    MODE_SWITCH = 0xE\n    HOST_BUTTON = 0xF\n    SCROLL_DOWN = 0x10\n    SCROLL_UP = 0x11\n\n\nButtonButtons = special_keys.MOUSE_BUTTONS\nButtonModifiers = special_keys.modifiers\nButtonKeys = special_keys.USB_HID_KEYCODES\nButtonConsumerKeys = special_keys.HID_CONSUMERCODES\n\n\nclass Button:\n    \"\"\"A button mapping\"\"\"\n\n    def __init__(self, **kwargs):\n        self.behavior = None\n        for key, val in kwargs.items():\n            setattr(self, key, val)\n\n    @classmethod\n    def from_yaml(cls, loader, node):\n        args = loader.construct_mapping(node)\n        return cls(**args)\n\n    @classmethod\n    def to_yaml(cls, dumper, data):\n        return dumper.represent_mapping(\"!Button\", data.__dict__, flow_style=True)\n\n    @classmethod\n    def from_bytes(cls, bytes_) -> Button:\n        behavior = bytes_[0] >> 4\n        if behavior == ButtonBehavior.MACRO_EXECUTE or behavior == ButtonBehavior.MACRO_STOP:\n            sector = ((bytes_[0] & 0x0F) << 8) + bytes_[1]\n            address = (bytes_[2] << 8) + bytes_[3]\n            result = cls(behavior=behavior, sector=sector, address=address)\n        elif behavior == ButtonBehavior.SEND:\n            try:\n                mapping_type = ButtonMappingType(bytes_[1]).value\n                if mapping_type == ButtonMappingType.BUTTON:\n                    value = ButtonButtons[(bytes_[2] << 8) + bytes_[3]]\n                    result = cls(behavior=behavior, type=mapping_type, value=value)\n                elif mapping_type == ButtonMappingType.MODIFIER_AND_KEY:\n                    modifiers = bytes_[2]\n                    value = ButtonKeys[bytes_[3]]\n                    result = cls(behavior=behavior, type=mapping_type, modifiers=modifiers, value=value)\n                elif mapping_type == ButtonMappingType.CONSUMER_KEY:\n                    value = ButtonConsumerKeys[(bytes_[2] << 8) + bytes_[3]]\n                    result = cls(behavior=behavior, type=mapping_type, value=value)\n                elif mapping_type == ButtonMappingType.NO_ACTION:\n                    result = cls(behavior=behavior, type=mapping_type)\n            except Exception:\n                pass\n        elif behavior == ButtonBehavior.FUNCTION:\n            second_byte = bytes_[1]\n            try:\n                btn_func = ButtonFunctions(second_byte).value\n            except ValueError:\n                btn_func = second_byte\n            data = bytes_[3]\n            result = cls(behavior=behavior, value=btn_func, data=data)\n        else:\n            result = cls(behavior=bytes_[0] >> 4, bytes=bytes_)\n        return result\n\n    def to_bytes(self):\n        bytes = common.int2bytes(self.behavior << 4, 1) if self.behavior is not None else None\n        if self.behavior == ButtonBehavior.MACRO_EXECUTE.value or self.behavior == ButtonBehavior.MACRO_STOP.value:\n            bytes = common.int2bytes((self.behavior << 12) + self.sector, 2) + common.int2bytes(self.address, 2)\n        elif self.behavior == ButtonBehavior.SEND.value:\n            bytes += common.int2bytes(self.type, 1)\n            if self.type == ButtonMappingType.BUTTON:\n                bytes += common.int2bytes(self.value, 2)\n            elif self.type == ButtonMappingType.MODIFIER_AND_KEY:\n                bytes += common.int2bytes(self.modifiers, 1)\n                bytes += common.int2bytes(self.value, 1)\n            elif self.type == ButtonMappingType.CONSUMER_KEY:\n                bytes += common.int2bytes(self.value, 2)\n            elif self.type == ButtonMappingType.NO_ACTION:\n                bytes += b\"\\xff\\xff\"\n        elif self.behavior == ButtonBehavior.FUNCTION:\n            data = common.int2bytes(self.data, 1) if self.data else b\"\\x00\"\n            bytes += common.int2bytes(self.value, 1) + b\"\\xff\" + data\n        else:\n            bytes = self.bytes if self.bytes else b\"\\xff\\xff\\xff\\xff\"\n        return bytes\n\n    def __repr__(self):\n        return \"%s{%s}\" % (\n            self.__class__.__name__,\n            \", \".join([f\"{str(key)}:{str(val)}\" for key, val in self.__dict__.items()]),\n        )\n\n\nyaml.SafeLoader.add_constructor(\"!Button\", Button.from_yaml)\nyaml.add_representer(Button, Button.to_yaml)\n\n\nclass OnboardProfile:\n    \"\"\"A single onboard profile\"\"\"\n\n    def __init__(self, **kwargs):\n        for key, val in kwargs.items():\n            setattr(self, key, val)\n\n    @classmethod\n    def from_yaml(cls, loader, node):\n        args = loader.construct_mapping(node)\n        return cls(**args)\n\n    @classmethod\n    def to_yaml(cls, dumper, data):\n        return dumper.represent_mapping(\"!OnboardProfile\", data.__dict__)\n\n    @classmethod\n    def from_bytes(cls, sector, enabled, buttons, gbuttons, bytes):\n        return cls(\n            sector=sector,\n            enabled=enabled,\n            report_rate=bytes[0],\n            resolution_default_index=bytes[1],\n            resolution_shift_index=bytes[2],\n            resolutions=[struct.unpack(\"<H\", bytes[i * 2 + 3 : i * 2 + 5])[0] for i in range(0, 5)],\n            red=bytes[13],\n            green=bytes[14],\n            blue=bytes[15],\n            power_mode=bytes[16],\n            angle_snap=bytes[17],\n            write_count=struct.unpack(\"<H\", bytes[18:20])[0],\n            reserved=bytes[20:28],\n            ps_timeout=struct.unpack(\"<H\", bytes[28:30])[0],\n            po_timeout=struct.unpack(\"<H\", bytes[30:32])[0],\n            buttons=[Button.from_bytes(bytes[32 + i * 4 : 32 + i * 4 + 4]) for i in range(0, buttons)],\n            gbuttons=[Button.from_bytes(bytes[96 + i * 4 : 96 + i * 4 + 4]) for i in range(0, gbuttons)],\n            name=bytes[160:208].decode(\"utf-16le\").rstrip(\"\\x00\").rstrip(\"\\uffff\"),\n            lighting=[LEDEffectSetting.from_bytes(bytes[208 + i * 11 : 219 + i * 11]) for i in range(0, 4)],\n        )\n\n    @classmethod\n    def from_dev(cls, dev, i, sector, s, enabled, buttons, gbuttons):\n        bytes = OnboardProfiles.read_sector(dev, sector, s)\n        return cls.from_bytes(sector, enabled, buttons, gbuttons, bytes)\n\n    def to_bytes(self, length):\n        bytes = common.int2bytes(self.report_rate, 1)\n        bytes += common.int2bytes(self.resolution_default_index, 1) + common.int2bytes(self.resolution_shift_index, 1)\n        bytes += b\"\".join([self.resolutions[i].to_bytes(2, \"little\") for i in range(0, 5)])\n        bytes += common.int2bytes(self.red, 1) + common.int2bytes(self.green, 1) + common.int2bytes(self.blue, 1)\n        bytes += common.int2bytes(self.power_mode, 1) + common.int2bytes(self.angle_snap, 1)\n        bytes += self.write_count.to_bytes(2, \"little\") + self.reserved\n        bytes += self.ps_timeout.to_bytes(2, \"little\") + self.po_timeout.to_bytes(2, \"little\")\n        for i in range(0, 16):\n            bytes += self.buttons[i].to_bytes() if i < len(self.buttons) else b\"\\xff\\xff\\xff\\xff\"\n        for i in range(0, 16):\n            bytes += self.gbuttons[i].to_bytes() if i < len(self.gbuttons) else b\"\\xff\\xff\\xff\\xff\"\n        if self.name == \"\":\n            bytes += b\"\\xff\" * 48\n        else:\n            bytes += self.name[0:24].ljust(24, \"\\x00\").encode(\"utf-16le\")\n        for i in range(0, 4):\n            bytes += self.lighting[i].to_bytes()\n        while len(bytes) < length - 2:\n            bytes += b\"\\xff\"\n        bytes += common.int2bytes(common.crc16(bytes), 2)\n        return bytes\n\n    def dump(self):\n        print(f\"     Onboard Profile: {self.name}\")\n        print(f\"       Report Rate {self.report_rate} ms\")\n        print(f\"       DPI Resolutions {self.resolutions}\")\n        print(f\"       Default Resolution Index {self.res_index}, Shift Resolution Index {self.res_shift_index}\")\n        print(f\"       Colors {self.red} {self.green} {self.blue}\")\n        print(f\"       Power {self.power_mode}, Angle Snapping {self.angle_snap}\")\n        for i in range(0, len(self.buttons)):\n            if self.buttons[i].behavior is not None:\n                print(\"       BUTTON\", i + 1, self.buttons[i])\n        for i in range(0, len(self.gbuttons)):\n            if self.gbuttons[i].behavior is not None:\n                print(\"       G-BUTTON\", i + 1, self.gbuttons[i])\n\n\nyaml.SafeLoader.add_constructor(\"!OnboardProfile\", OnboardProfile.from_yaml)\nyaml.add_representer(OnboardProfile, OnboardProfile.to_yaml)\n\nOnboardProfilesVersion = 3\n\n\n# Doesn't handle macros\nclass OnboardProfiles:\n    \"\"\"The entire onboard profiles information\"\"\"\n\n    def __init__(self, **kwargs):\n        for key, val in kwargs.items():\n            setattr(self, key, val)\n\n    @classmethod\n    def from_yaml(cls, loader, node):\n        args = loader.construct_mapping(node)\n        return cls(**args)\n\n    @classmethod\n    def to_yaml(cls, dumper, data):\n        return dumper.represent_mapping(\"!OnboardProfiles\", data.__dict__)\n\n    @classmethod\n    def get_profile_headers(cls, device) -> list[tuple[int, int]]:\n        \"\"\"Returns profile headers.\n\n        Returns\n        -------\n        list[tuple[int, int]]\n            Tuples contain (sector, enabled).\n        \"\"\"\n        i = 0\n        headers = []\n        chunk = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x50, 0, 0, 0, i)\n        s = 0x00\n        if chunk[0:4] == b\"\\x00\\x00\\x00\\x00\" or chunk[0:4] == b\"\\xff\\xff\\xff\\xff\":  # look in ROM instead\n            chunk = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x50, 0x01, 0, 0, i)\n            s = 0x01\n        while chunk[0:2] != b\"\\xff\\xff\":\n            sector, enabled = struct.unpack(\"!HB\", chunk[0:3])\n            headers.append((sector, enabled))\n            i += 1\n            chunk = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x50, s, 0, 0, i * 4)\n        return headers\n\n    @classmethod\n    def from_device(cls, device):\n        if not device.online:  # wake the device up if necessary\n            device.ping()\n        response = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x00)\n        memory, profile, _macro = struct.unpack(\"!BBB\", response[0:3])\n        if memory != 0x01 or profile > 0x05:\n            return\n        count, oob, buttons, sectors, size, shift = struct.unpack(\"!BBBBHB\", response[3:10])\n        gbuttons = buttons if (shift & 0x3 == 0x2) else 0\n        headers = OnboardProfiles.get_profile_headers(device)\n        profiles = {}\n        for i, (sector, enabled) in enumerate(headers, start=1):\n            profiles[i] = OnboardProfile.from_dev(device, i, sector, size, enabled, buttons, gbuttons)\n        return cls(\n            version=OnboardProfilesVersion,\n            name=device.name,\n            count=count,\n            buttons=buttons,\n            gbuttons=gbuttons,\n            sectors=sectors,\n            size=size,\n            profiles=profiles,\n        )\n\n    def to_bytes(self):\n        bytes = b\"\"\n        for i in range(1, len(self.profiles) + 1):\n            profiles_sector = common.int2bytes(self.profiles[i].sector, 2)\n            profiles_enabled = common.int2bytes(self.profiles[i].enabled, 1)\n            bytes += profiles_sector + profiles_enabled + b\"\\x00\"\n        bytes += b\"\\xff\\xff\\x00\\x00\"  # marker after last profile\n        while len(bytes) < self.size - 2:  # leave room for CRC\n            bytes += b\"\\xff\"\n        bytes += common.int2bytes(common.crc16(bytes), 2)\n        return bytes\n\n    @classmethod\n    def read_sector(cls, dev, sector, s):  # doesn't check for valid sector or size\n        bytes = b\"\"\n        o = 0\n        while o < s - 15:\n            chunk = dev.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x50, sector >> 8, sector & 0xFF, o >> 8, o & 0xFF)\n            bytes += chunk\n            o += 16\n        chunk = dev.feature_request(\n            SupportedFeature.ONBOARD_PROFILES,\n            0x50,\n            sector >> 8,\n            sector & 0xFF,\n            (s - 16) >> 8,\n            (s - 16) & 0xFF,\n        )\n        bytes += chunk[16 + o - s :]  # the last chunk has to be read in an awkward way\n        return bytes\n\n    @classmethod\n    def write_sector(cls, device, s, bs):  # doesn't check for valid sector or size\n        rbs = OnboardProfiles.read_sector(device, s, len(bs))\n        if rbs[:-2] == bs[:-2]:\n            return False\n        device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x60, s >> 8, s & 0xFF, 0, 0, len(bs) >> 8, len(bs) & 0xFF)\n        o = 0\n        while o < len(bs) - 1:\n            device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x70, bs[o : o + 16])\n            o += 16\n        device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x80)\n        return True\n\n    def write(self, device):\n        try:\n            written = 1 if OnboardProfiles.write_sector(device, 0, self.to_bytes()) else 0\n        except Exception as e:\n            logger.warning(\"Exception writing onboard profile control sector\")\n            raise e\n        for p in self.profiles.values():\n            try:\n                if p.sector >= self.sectors:\n                    raise Exception(f\"Sector {p.sector} not a writable sector\")\n                written += 1 if OnboardProfiles.write_sector(device, p.sector, p.to_bytes(self.size)) else 0\n            except Exception as e:\n                logger.warning(f\"Exception writing onboard profile sector {p.sector}\")\n                raise e\n        return written\n\n    def show(self):\n        print(yaml.dump(self))\n\n\nyaml.SafeLoader.add_constructor(\"!OnboardProfiles\", OnboardProfiles.from_yaml)\nyaml.add_representer(OnboardProfiles, OnboardProfiles.to_yaml)\n\n\ndef feature_request(device, feature, function=0x00, *params, no_reply=False):\n    if device.online and device.features:\n        if feature in device.features:\n            feature_index = device.features[feature]\n            return device.request((feature_index << 8) + (function & 0xFF), *params, no_reply=no_reply)\n\n\nclass Hidpp20:\n    def get_firmware(self, device) -> tuple[common.FirmwareInfo] | None:\n        \"\"\"Reads a device's firmware info.\n\n        :returns: a list of FirmwareInfo tuples, ordered by firmware layer.\n        \"\"\"\n        count = device.feature_request(SupportedFeature.DEVICE_FW_VERSION)\n        if count:\n            count = ord(count[:1])\n\n            fw = []\n            for index in range(0, count):\n                fw_info = device.feature_request(SupportedFeature.DEVICE_FW_VERSION, 0x10, index)\n                if fw_info:\n                    level = ord(fw_info[:1]) & 0x0F\n                    if level == 0 or level == 1:\n                        name, version_major, version_minor, build = struct.unpack(\"!3sBBH\", fw_info[1:8])\n                        version = f\"{version_major:02X}.{version_minor:02X}\"\n                        if build:\n                            version += f\".B{build:04X}\"\n                        extras = fw_info[9:].rstrip(b\"\\x00\") or None\n                        fw_info = common.FirmwareInfo(FirmwareKind(level), name.decode(\"ascii\"), version, extras)\n                    elif level == FirmwareKind.Hardware:\n                        fw_info = common.FirmwareInfo(FirmwareKind.Hardware, \"\", str(ord(fw_info[1:2])), None)\n                    else:\n                        fw_info = common.FirmwareInfo(FirmwareKind.Other, \"\", \"\", None)\n\n                    fw.append(fw_info)\n            return tuple(fw)\n\n    def get_ids(self, device):\n        \"\"\"Reads a device's ids (unit and model numbers)\"\"\"\n        ids = device.feature_request(SupportedFeature.DEVICE_FW_VERSION)\n        if ids:\n            unitId = ids[1:5]\n            modelId = ids[7:13]\n            transport_bits = ord(ids[6:7])\n            offset = 0\n            tid_map = {}\n            for transport, flag in [(\"btid\", 0x1), (\"btleid\", 0x02), (\"wpid\", 0x04), (\"usbid\", 0x08)]:\n                if transport_bits & flag:\n                    tid_map[transport] = modelId[offset : offset + 2].hex().upper()\n                    offset = offset + 2\n            return unitId.hex().upper(), modelId.hex().upper(), tid_map\n\n    def get_kind(self, device: Device):\n        \"\"\"Reads a device's type.\n\n        :see DEVICE_KIND:\n        :returns: a string describing the device type, or ``None`` if the device is\n        not available or does not support the ``DEVICE_NAME`` feature.\n        \"\"\"\n        kind = device.feature_request(SupportedFeature.DEVICE_NAME, 0x20)\n        if kind:\n            kind = ord(kind[:1])\n            try:\n                return KIND_MAP[DEVICE_KIND[kind]]\n            except Exception:\n                return None\n\n    def get_name(self, device: Device):\n        \"\"\"Reads a device's name.\n\n        :returns: a string with the device name, or ``None`` if the device is not\n        available or does not support the ``DEVICE_NAME`` feature.\n        \"\"\"\n        name_length = device.feature_request(SupportedFeature.DEVICE_NAME)\n        if name_length:\n            name_length = ord(name_length[:1])\n\n            name = b\"\"\n            while len(name) < name_length:\n                fragment = device.feature_request(SupportedFeature.DEVICE_NAME, 0x10, len(name))\n                if fragment:\n                    name += fragment[: name_length - len(name)]\n                else:\n                    logger.error(\"failed to read whole name of %s (expected %d chars)\", device, name_length)\n                    return None\n\n            return name.decode(\"utf-8\")\n\n    def get_friendly_name(self, device: Device):\n        \"\"\"Reads a device's friendly name.\n\n        :returns: a string with the device name, or ``None`` if the device is not\n        available or does not support the ``DEVICE_NAME`` feature.\n        \"\"\"\n        name_length = device.feature_request(SupportedFeature.DEVICE_FRIENDLY_NAME)\n        if name_length:\n            name_length = ord(name_length[:1])\n\n            name = b\"\"\n            while len(name) < name_length:\n                fragment = device.feature_request(SupportedFeature.DEVICE_FRIENDLY_NAME, 0x10, len(name))\n                if fragment:\n                    name += fragment[1 : name_length - len(name) + 1]\n                else:\n                    logger.error(\"failed to read whole name of %s (expected %d chars)\", device, name_length)\n                    return None\n\n            return name.decode(\"utf-8\")\n\n    def get_battery_status(self, device: Device):\n        report = device.feature_request(SupportedFeature.BATTERY_STATUS)\n        if report:\n            return decipher_battery_status(report)\n\n    def get_battery_unified(self, device: Device):\n        report = device.feature_request(SupportedFeature.UNIFIED_BATTERY, 0x10)\n        if report is not None:\n            return decipher_battery_unified(report)\n\n    def get_battery_voltage(self, device: Device):\n        report = device.feature_request(SupportedFeature.BATTERY_VOLTAGE)\n        if report is not None:\n            return decipher_battery_voltage(report)\n\n    def get_adc_measurement(self, device: Device):\n        try:  # this feature call produces an error for headsets that are connected but inactive\n            report = device.feature_request(SupportedFeature.ADC_MEASUREMENT)\n            if report is not None:\n                return decipher_adc_measurement(report)\n        except exceptions.FeatureCallError:\n            return SupportedFeature.ADC_MEASUREMENT if SupportedFeature.ADC_MEASUREMENT in device.features else None\n\n    def get_battery(self, device, feature):\n        \"\"\"Return battery information - feature, approximate level, next, charging, voltage\n        or battery feature if there is one but it is not responding or None for no battery feature\"\"\"\n\n        if feature is not None:\n            battery_function = battery_functions.get(feature, None)\n            if battery_function:\n                result = battery_function(self, device)\n                if result:\n                    return result\n        else:\n            for battery_function in battery_functions.values():\n                result = battery_function(self, device)\n                if result:\n                    return result\n        return 0\n\n    def get_keys(self, device: Device):\n        # TODO: add here additional variants for other REPROG_CONTROLS\n        count = None\n        if device.features and SupportedFeature.REPROG_CONTROLS_V2 in device.features:\n            count = device.feature_request(SupportedFeature.REPROG_CONTROLS_V2)\n            return KeysArrayV2(device, ord(count[:1]))\n        elif device.features and SupportedFeature.REPROG_CONTROLS_V4 in device.features:\n            count = device.feature_request(SupportedFeature.REPROG_CONTROLS_V4)\n            return KeysArrayV4(device, ord(count[:1]))\n        return None\n\n    def get_remap_keys(self, device: Device):\n        count = device.feature_request(SupportedFeature.PERSISTENT_REMAPPABLE_ACTION, 0x10)\n        if count:\n            return KeysArrayPersistent(device, ord(count[:1]))\n\n    def get_gestures(self, device: Device):\n        if getattr(device, \"_gestures\", None) is not None:\n            return device._gestures\n        if SupportedFeature.GESTURE_2 in device.features:\n            return Gestures(device)\n\n    def get_backlight(self, device: Device):\n        if getattr(device, \"_backlight\", None) is not None:\n            return device._backlight\n        if SupportedFeature.BACKLIGHT2 in device.features:\n            return Backlight(device)\n\n    def get_force_buttons(self, device: Device):\n        if getattr(device, \"_force_buttons\", None) is not None:\n            return device._force_buttons\n        if SupportedFeature.FORCE_SENSING_BUTTON in device.features:\n            return ForceSensingButtonArray(device)\n\n    def get_profiles(self, device: Device):\n        if getattr(device, \"_profiles\", None) is not None:\n            return device._profiles\n        if SupportedFeature.ONBOARD_PROFILES in device.features:\n            return OnboardProfiles.from_device(device)\n\n    def get_mouse_pointer_info(self, device: Device):\n        pointer_info = device.feature_request(SupportedFeature.MOUSE_POINTER)\n        if pointer_info:\n            dpi, flags = struct.unpack(\"!HB\", pointer_info[:3])\n            acceleration = (\"none\", \"low\", \"med\", \"high\")[flags & 0x3]\n            suggest_os_ballistics = (flags & 0x04) != 0\n            suggest_vertical_orientation = (flags & 0x08) != 0\n            return {\n                \"dpi\": dpi,\n                \"acceleration\": acceleration,\n                \"suggest_os_ballistics\": suggest_os_ballistics,\n                \"suggest_vertical_orientation\": suggest_vertical_orientation,\n            }\n\n    def get_vertical_scrolling_info(self, device: Device):\n        vertical_scrolling_info = device.feature_request(SupportedFeature.VERTICAL_SCROLLING)\n        if vertical_scrolling_info:\n            roller, ratchet, lines = struct.unpack(\"!BBB\", vertical_scrolling_info[:3])\n            roller_type = (\n                \"reserved\",\n                \"standard\",\n                \"reserved\",\n                \"3G\",\n                \"micro\",\n                \"normal touch pad\",\n                \"inverted touch pad\",\n                \"reserved\",\n            )[roller]\n            return {\"roller\": roller_type, \"ratchet\": ratchet, \"lines\": lines}\n\n    def get_hi_res_scrolling_info(self, device: Device):\n        hi_res_scrolling_info = device.feature_request(SupportedFeature.HI_RES_SCROLLING)\n        if hi_res_scrolling_info:\n            mode, resolution = struct.unpack(\"!BB\", hi_res_scrolling_info[:2])\n            return mode, resolution\n\n    def get_pointer_speed_info(self, device: Device):\n        pointer_speed_info = device.feature_request(SupportedFeature.POINTER_SPEED)\n        if pointer_speed_info:\n            pointer_speed_hi, pointer_speed_lo = struct.unpack(\"!BB\", pointer_speed_info[:2])\n            # if pointer_speed_lo > 0:\n            #     pointer_speed_lo = pointer_speed_lo\n            return pointer_speed_hi + pointer_speed_lo / 256\n\n    def get_lowres_wheel_status(self, device: Device):\n        lowres_wheel_status = device.feature_request(SupportedFeature.LOWRES_WHEEL)\n        if lowres_wheel_status:\n            wheel_flag = struct.unpack(\"!B\", lowres_wheel_status[:1])[0]\n            wheel_reporting = (\"HID\", \"HID++\")[wheel_flag & 0x01]\n            return wheel_reporting\n\n    def get_hires_wheel(self, device: Device):\n        caps = device.feature_request(SupportedFeature.HIRES_WHEEL, 0x00)\n        mode = device.feature_request(SupportedFeature.HIRES_WHEEL, 0x10)\n        ratchet = device.feature_request(SupportedFeature.HIRES_WHEEL, 0x030)\n\n        if caps and mode and ratchet:\n            # Parse caps\n            multi, flags = struct.unpack(\"!BB\", caps[:2])\n\n            has_invert = (flags & 0x08) != 0\n            has_ratchet = (flags & 0x04) != 0\n\n            # Parse mode\n            wheel_mode, reserved = struct.unpack(\"!BB\", mode[:2])\n\n            target = (wheel_mode & 0x01) != 0\n            res = (wheel_mode & 0x02) != 0\n            inv = (wheel_mode & 0x04) != 0\n\n            # Parse Ratchet switch\n            ratchet_mode, reserved = struct.unpack(\"!BB\", ratchet[:2])\n\n            ratchet = (ratchet_mode & 0x01) != 0\n\n            return multi, has_invert, has_ratchet, inv, res, target, ratchet\n\n    def get_new_fn_inversion(self, device: Device):\n        state = device.feature_request(SupportedFeature.NEW_FN_INVERSION, 0x00)\n        if state:\n            inverted, default_inverted = struct.unpack(\"!BB\", state[:2])\n            inverted = (inverted & 0x01) != 0\n            default_inverted = (default_inverted & 0x01) != 0\n            return inverted, default_inverted\n\n    def get_host_names(self, device: Device):\n        state = device.feature_request(SupportedFeature.HOSTS_INFO, 0x00)\n        host_names = {}\n        if state:\n            capability_flags, _ignore, numHosts, currentHost = struct.unpack(\"!BBBB\", state[:4])\n            if capability_flags & 0x01:  # device can get host names\n                for host in range(0, numHosts):\n                    hostinfo = device.feature_request(SupportedFeature.HOSTS_INFO, 0x10, host)\n                    _ignore, status, _ignore, _ignore, nameLen, _ignore = struct.unpack(\"!BBBBBB\", hostinfo[:6])\n                    name = \"\"\n                    remaining = nameLen\n                    while remaining > 0:\n                        name_piece = device.feature_request(SupportedFeature.HOSTS_INFO, 0x30, host, nameLen - remaining)\n                        if name_piece:\n                            name += name_piece[2 : 2 + min(remaining, 14)].decode()\n                            remaining = max(0, remaining - 14)\n                        else:\n                            remaining = 0\n                    host_names[host] = (bool(status), name)\n            if host_names:  # update the current host's name if it doesn't match the system name\n                hostname = socket.gethostname().partition(\".\")[0]\n                if host_names[currentHost][1] != hostname:\n                    self.set_host_name(device, hostname, host_names[currentHost][1])\n                    host_names[currentHost] = (host_names[currentHost][0], hostname)\n        return host_names\n\n    def set_host_name(self, device: Device, name, currentName=\"\"):\n        name = bytearray(name, \"utf-8\")\n        currentName = bytearray(currentName, \"utf-8\")\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"Setting host name to %s\", name)\n        state = device.feature_request(SupportedFeature.HOSTS_INFO, 0x00)\n        if state:\n            flags, _ignore, _ignore, currentHost = struct.unpack(\"!BBBB\", state[:4])\n            if flags & 0x02:\n                hostinfo = device.feature_request(SupportedFeature.HOSTS_INFO, 0x10, currentHost)\n                _ignore, _ignore, _ignore, _ignore, _ignore, maxNameLen = struct.unpack(\"!BBBBBB\", hostinfo[:6])\n                if name[:maxNameLen] == currentName[:maxNameLen] and False:\n                    return True\n                length = min(maxNameLen, len(name))\n                chunk = 0\n                while chunk < length:\n                    response = device.feature_request(\n                        SupportedFeature.HOSTS_INFO, 0x40, currentHost, chunk, name[chunk : chunk + 14]\n                    )\n                    if not response:\n                        return False\n                    chunk += 14\n            return True\n\n    def get_onboard_mode(self, device: Device):\n        state = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x20)\n\n        if state:\n            mode = struct.unpack(\"!B\", state[:1])[0]\n            return mode\n\n    def set_onboard_mode(self, device: Device, mode):\n        state = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x10, mode)\n        return state\n\n    def get_polling_rate(self, device: Device):\n        state = device.feature_request(SupportedFeature.REPORT_RATE, 0x10)\n        if state:\n            rate = struct.unpack(\"!B\", state[:1])[0]\n            return f\"{str(rate)}ms\"\n        else:\n            rates = [\"8ms\", \"4ms\", \"2ms\", \"1ms\", \"500us\", \"250us\", \"125us\"]\n            state = device.feature_request(SupportedFeature.EXTENDED_ADJUSTABLE_REPORT_RATE, 0x20)\n            if state:\n                rate = struct.unpack(\"!B\", state[:1])[0]\n                return rates[rate]\n\n    def get_remaining_pairing(self, device: Device):\n        result = device.feature_request(SupportedFeature.REMAINING_PAIRING, 0x0)\n        if result:\n            result = struct.unpack(\"!B\", result[:1])[0]\n            SupportedFeature._fallback = lambda x: f\"unknown:{x:04X}\"\n            return result\n\n    def config_change(self, device: Device, configuration, no_reply=False):\n        return device.feature_request(SupportedFeature.CONFIG_CHANGE, 0x10, configuration, no_reply=no_reply)\n\n\nbattery_functions = {\n    SupportedFeature.BATTERY_STATUS: Hidpp20.get_battery_status,\n    SupportedFeature.BATTERY_VOLTAGE: Hidpp20.get_battery_voltage,\n    SupportedFeature.UNIFIED_BATTERY: Hidpp20.get_battery_unified,\n    SupportedFeature.ADC_MEASUREMENT: Hidpp20.get_adc_measurement,\n}\n\n\ndef decipher_battery_status(report: FixedBytes5) -> Tuple[Any, Battery]:\n    battery_discharge_level, battery_discharge_next_level, battery_status = struct.unpack(\"!BBB\", report[:3])\n    if battery_discharge_level == 0:\n        battery_discharge_level = None\n    try:\n        status = BatteryStatus(battery_status)\n    except ValueError:\n        status = None\n        logger.debug(f\"Unknown battery status byte 0x{battery_status:02X}\")\n    if logger.isEnabledFor(logging.DEBUG):\n        logger.debug(\n            \"battery status %s%% charged, next %s%%, status %s\", battery_discharge_level, battery_discharge_next_level, status\n        )\n    return SupportedFeature.BATTERY_STATUS, Battery(battery_discharge_level, battery_discharge_next_level, status, None)\n\n\ndef decipher_battery_voltage(report: bytes):\n    voltage, flags = struct.unpack(\">HB\", report[:3])\n    status = BatteryStatus.DISCHARGING\n    charge_sts = ErrorCode.UNKNOWN\n    charge_lvl = ChargeLevel.AVERAGE\n    charge_type = ChargeType.STANDARD\n    if flags & (1 << 7):\n        status = BatteryStatus.RECHARGING\n        charge_sts = ChargeStatus(flags & 0x03)\n    if charge_sts is None:\n        charge_sts = ErrorCode.UNKNOWN\n    elif isinstance(charge_sts, ChargeStatus) and ChargeStatus.FULL in charge_sts:\n        charge_lvl = ChargeLevel.FULL\n        status = BatteryStatus.FULL\n    if flags & (1 << 3):\n        charge_type = ChargeType.FAST\n    elif flags & (1 << 4):\n        charge_type = ChargeType.SLOW\n        status = BatteryStatus.SLOW_RECHARGE\n    elif flags & (1 << 5):\n        charge_lvl = ChargeLevel.CRITICAL\n    charge_level = estimate_battery_level_percentage(voltage)\n    if charge_level:\n        charge_lvl = charge_level\n    if logger.isEnabledFor(logging.DEBUG):\n        logger.debug(\n            \"battery voltage %d mV, charging %s, status %d = %s, level %s, type %s\",\n            voltage,\n            status,\n            (flags & 0x03),\n            charge_sts,\n            charge_lvl,\n            charge_type,\n        )\n    return SupportedFeature.BATTERY_VOLTAGE, Battery(charge_lvl, None, status, voltage)\n\n\ndef decipher_battery_unified(report) -> tuple[SupportedFeature, Battery]:\n    discharge, level, status_byte, _ignore = struct.unpack(\"!BBBB\", report[:4])\n    try:\n        status = BatteryStatus(status_byte)\n    except ValueError:\n        status = None\n        logger.debug(f\"Unknown battery status byte 0x{status_byte:02X}\")\n    if logger.isEnabledFor(logging.DEBUG):\n        logger.debug(\"battery unified %s%% charged, level %s, charging %s\", discharge, level, status)\n\n    if level == 8:\n        approx_level = BatteryLevelApproximation.FULL\n    elif level == 4:\n        approx_level = BatteryLevelApproximation.GOOD\n    elif level == 2:\n        approx_level = BatteryLevelApproximation.LOW\n    elif level == 1:\n        approx_level = BatteryLevelApproximation.CRITICAL\n    else:\n        approx_level = BatteryLevelApproximation.EMPTY\n\n    return SupportedFeature.UNIFIED_BATTERY, Battery(discharge if discharge else approx_level, None, status, None)\n\n\ndef decipher_adc_measurement(report) -> tuple[SupportedFeature, Battery]:\n    # partial implementation - needs mapping to levels\n    adc_voltage, flags = struct.unpack(\"!HB\", report[:3])\n    charge_level = estimate_battery_level_percentage(adc_voltage)\n    if flags & 0x01:\n        status = BatteryStatus.RECHARGING if flags & 0x02 else BatteryStatus.DISCHARGING\n        return SupportedFeature.ADC_MEASUREMENT, Battery(charge_level, None, status, adc_voltage)\n\n\ndef estimate_battery_level_percentage(value_millivolt: int) -> int | None:\n    \"\"\"Estimate battery level percentage based on battery voltage.\n\n    Uses linear approximation to estimate the battery level in percent.\n\n    Parameters\n    ----------\n    value_millivolt\n        Measured battery voltage in millivolt.\n    \"\"\"\n    battery_voltage_to_percentage = [\n        (4186, 100),\n        (4067, 90),\n        (3989, 80),\n        (3922, 70),\n        (3859, 60),\n        (3811, 50),\n        (3778, 40),\n        (3751, 30),\n        (3717, 20),\n        (3671, 10),\n        (3646, 5),\n        (3579, 2),\n        (3500, 0),\n    ]\n\n    if value_millivolt >= battery_voltage_to_percentage[0][0]:\n        return battery_voltage_to_percentage[0][1]\n    if value_millivolt <= battery_voltage_to_percentage[-1][0]:\n        return battery_voltage_to_percentage[-1][1]\n\n    for i in range(len(battery_voltage_to_percentage) - 1):\n        v_high, p_high = battery_voltage_to_percentage[i]\n        v_low, p_low = battery_voltage_to_percentage[i + 1]\n        if v_low <= value_millivolt <= v_high:\n            # Linear interpolation\n            percent = p_low + (p_high - p_low) * (value_millivolt - v_low) / (v_high - v_low)\n            return round(percent)\n    return 0\n\n\nclass ForceSensingButton:\n    \"\"\"A button that has a force value at which to trigger the button\"\"\"\n\n    @classmethod\n    def create(cls, device, number: int):\n        buttondata = device.feature_request(SupportedFeature.FORCE_SENSING_BUTTON, 0x10, number)\n        buttoncurrent = device.feature_request(SupportedFeature.FORCE_SENSING_BUTTON, 0x20, number)\n        if buttondata is not None and buttoncurrent is not None:\n            changeable, default, max_value, min_value = struct.unpack(\"!HHHH\", buttondata[:8])\n            changeable = changeable & 0x01\n            current = struct.unpack(\"!H\", buttoncurrent[:2])[0]\n            return cls(device, number, changeable, default, max_value, min_value, current)\n\n    def __init__(self, device, number: int, changeable: bool, default: int, max_value: int, min_value: int, current: int):\n        self._device = device\n        self.number = number\n        self.changeable = changeable\n        self.default = default\n        self.min_value = min_value\n        self.max_value = max_value\n        self._current = current\n\n    def get_current(self) -> int:\n        return self._current\n\n    def set_current(self, current: int) -> None:\n        if not self.changeable:\n            logger.warning(f\"FORCE_SENSING_BUTTON on device {self._device} does not allow changing force.\")\n        if self.min_value <= current <= self.max_value:\n            ret = self._device.feature_request(\n                SupportedFeature.FORCE_SENSING_BUTTON, 0x30, struct.pack(\"!BH\", self.number, current)\n            )\n        if ret is None and logger.isEnabledFor(logging.DEBUG):\n            logger.debug(f\"FORCE_SENSING_BUTTON setButtonConfig on device {self._device} didn't respond.\")\n\n    def acceptable_current(self, value: int) -> bool:\n        return self.min_value <= value <= self.max_value\n\n\nclass ForceSensingButtonArray(UserDict):\n    \"\"\"A map of buttons supporting force sensing\"\"\"\n\n    def __new__(cls, device: Device):\n        assert device is not None\n        count = device.feature_request(SupportedFeature.FORCE_SENSING_BUTTON, 0x00)\n        if count:\n            instance = super().__new__(cls)\n            instance._count = ord(count[:1])\n            return instance\n\n    def __init__(self, device: Device):\n        super().__init__(self)\n        self.device = device\n        for index in range(0, self._count):\n            self[index] = None\n\n    def __getitem__(self, index: int):\n        item = super().__getitem__(index)\n        if item is None:\n            self.query_key(index)\n        return super().__getitem__(index)\n\n    def query_key(self, index):\n        if index not in self:\n            raise IndexError(index)\n        button = ForceSensingButton.create(self.device, index)\n        if button:\n            self[index] = button\n            return button\n\n    def query(self):\n        for index in self:\n            button = ForceSensingButton.create(self.device, index)\n            if button:\n                self[index] = button\n        return self\n\n    # interface for single force button\n    def get_current(self):\n        return self[0].get_current()\n\n    def set_current(self, current: int) -> None:\n        self[0].set_current(current)\n\n    def acceptable(self, value: int) -> bool:\n        return self[0].acceptable(value)\n\n    def acceptable_current_key(self, index: int, value: int) -> bool:\n        return self[index].acceptable(value)\n"
  },
  {
    "path": "lib/logitech_receiver/hidpp20_constants.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nfrom enum import IntEnum\nfrom enum import IntFlag\n\nfrom .common import NamedInts\n\n# <FeaturesSupported.xml sed '/LD_FID_/{s/.*LD_FID_/\\t/;s/\"[ \\t]*Id=\"/=/;s/\" \\/>/,/p}' | sort -t= -k2\n# additional features names taken from https://github.com/cvuchener/hidpp and\n# https://github.com/Logitech/cpg-docs/tree/master/hidpp20\n\"\"\"Possible features available on a Logitech device.\n\nA particular device might not support all these features, and may support other\nunknown features as well.\n\"\"\"\n\n\nclass SupportedFeature(IntEnum):\n    ROOT = 0x0000\n    FEATURE_SET = 0x0001\n    FEATURE_INFO = 0x0002\n    # Common\n    DEVICE_FW_VERSION = 0x0003\n    DEVICE_UNIT_ID = 0x0004\n    DEVICE_NAME = 0x0005\n    DEVICE_GROUPS = 0x0006\n    DEVICE_FRIENDLY_NAME = 0x0007\n    KEEP_ALIVE = 0x0008\n    PROPERTY_ACCESS = 0x0011\n    CONFIG_CHANGE = 0x0020\n    CRYPTO_ID = 0x0021\n    TARGET_SOFTWARE = 0x0030\n    WIRELESS_SIGNAL_STRENGTH = 0x0080\n    DFUCONTROL_LEGACY = 0x00C0\n    DFUCONTROL_UNSIGNED = 0x00C1\n    DFUCONTROL_SIGNED = 0x00C2\n    DFUCONTROL = 0x00C3\n    DFU = 0x00D0\n    BATTERY_STATUS = 0x1000\n    BATTERY_VOLTAGE = 0x1001\n    UNIFIED_BATTERY = 0x1004\n    CHARGING_CONTROL = 0x1010\n    LED_CONTROL = 0x1300\n    FORCE_PAIRING = 0x1500\n    GENERIC_TEST = 0x1800\n    DEVICE_RESET = 0x1802\n    OOBSTATE = 0x1805\n    CONFIG_DEVICE_PROPS = 0x1806\n    CHANGE_HOST = 0x1814\n    HOSTS_INFO = 0x1815\n    BLE_PRO_PRE_PAIRING = 0x1816\n    BACKLIGHT = 0x1981\n    BACKLIGHT2 = 0x1982\n    BACKLIGHT3 = 0x1983\n    ILLUMINATION = 0x1990\n    FORCE_SENSING_BUTTON = 0x19C0\n    HAPTIC = 0x19B0\n    PRESENTER_CONTROL = 0x1A00\n    SENSOR_3D = 0x1A01\n    REPROG_CONTROLS = 0x1B00\n    REPROG_CONTROLS_V2 = 0x1B01\n    REPROG_CONTROLS_V2_2 = 0x1B02  # LogiOptions 2.10.73 features.xml\n    REPROG_CONTROLS_V3 = 0x1B03\n    REPROG_CONTROLS_V4 = 0x1B04\n    FULL_KEY_CUSTOMIZATION = 0x1B05\n    CONTROL_LIST = 0x1B10\n    SWITCH_SWAPABILITY = 0x1B20\n    DEVICE_MODE = 0x1B30\n    REPORT_HID_USAGE = 0x1BC0\n    PERSISTENT_REMAPPABLE_ACTION = 0x1C00\n    WIRELESS_DEVICE_STATUS = 0x1D4B\n    REMAINING_PAIRING = 0x1DF0\n    ENABLE_HIDDEN_FEATURES = 0x1E00\n    FIRMWARE_PROPERTIES = 0x1F1F\n    ADC_MEASUREMENT = 0x1F20\n    # Mouse\n    LEFT_RIGHT_SWAP = 0x2001\n    SWAP_BUTTON_CANCEL = 0x2005\n    POINTER_AXIS_ORIENTATION = 0x2006\n    VERTICAL_SCROLLING = 0x2100\n    SMART_SHIFT = 0x2110\n    SMART_SHIFT_ENHANCED = 0x2111\n    HI_RES_SCROLLING = 0x2120\n    HIRES_WHEEL = 0x2121\n    LOWRES_WHEEL = 0x2130\n    THUMB_WHEEL = 0x2150\n    MOUSE_POINTER = 0x2200\n    ADJUSTABLE_DPI = 0x2201\n    EXTENDED_ADJUSTABLE_DPI = 0x2202\n    POINTER_SPEED = 0x2205\n    ANGLE_SNAPPING = 0x2230\n    SURFACE_TUNING = 0x2240\n    XY_STATS = 0x2250\n    WHEEL_STATS = 0x2251\n    HYBRID_TRACKING = 0x2400\n    # Keyboard\n    FN_INVERSION = 0x40A0\n    NEW_FN_INVERSION = 0x40A2\n    K375S_FN_INVERSION = 0x40A3\n    ENCRYPTION = 0x4100\n    LOCK_KEY_STATE = 0x4220\n    SOLAR_DASHBOARD = 0x4301\n    KEYBOARD_LAYOUT = 0x4520\n    KEYBOARD_DISABLE_KEYS = 0x4521\n    KEYBOARD_DISABLE_BY_USAGE = 0x4522\n    KEYBOARD_DISABLE_CONTROLS = 0x4523\n    DUALPLATFORM = 0x4530\n    MULTIPLATFORM = 0x4531\n    KEYBOARD_LAYOUT_2 = 0x4540\n    CROWN = 0x4600\n    # Touchpad\n    TOUCHPAD_FW_ITEMS = 0x6010\n    TOUCHPAD_SW_ITEMS = 0x6011\n    TOUCHPAD_WIN8_FW_ITEMS = 0x6012\n    TAP_ENABLE = 0x6020\n    TAP_ENABLE_EXTENDED = 0x6021\n    CURSOR_BALLISTIC = 0x6030\n    TOUCHPAD_RESOLUTION = 0x6040\n    TOUCHPAD_RAW_XY = 0x6100\n    TOUCHMOUSE_RAW_POINTS = 0x6110\n    TOUCHMOUSE_6120 = 0x6120\n    GESTURE = 0x6500\n    GESTURE_2 = 0x6501\n    # Gaming Devices\n    GKEY = 0x8010\n    MKEYS = 0x8020\n    MR = 0x8030\n    BRIGHTNESS_CONTROL = 0x8040\n    LOGI_MODIFIERS = 0x8051\n    REPORT_RATE = 0x8060\n    EXTENDED_ADJUSTABLE_REPORT_RATE = 0x8061\n    COLOR_LED_EFFECTS = 0x8070\n    RGB_EFFECTS = 0x8071\n    RPM_INDICATOR = 0x807A\n    RPM_LED_PATTERN = 0x807B\n    PER_KEY_LIGHTING = 0x8080\n    PER_KEY_LIGHTING_V2 = 0x8081\n    MODE_STATUS = 0x8090\n    LEGACY_AXIS_RESPONSE_CURVE = 0x80A3\n    AXIS_RESPONSE_CURVE = 0x80A4\n    BANDED_AXIS = 0x80B1\n    COMBINED_PEDALS = 0x80D0\n    BUNNY_HOPPING = 0x80E0\n    ONBOARD_PROFILES = 0x8100\n    PROFILE_MANAGEMENT = 0x8101\n    MOUSE_BUTTON_SPY = 0x8110\n    LATENCY_MONITORING = 0x8111\n    GAMING_ATTACHMENTS = 0x8120\n    FORCE_FEEDBACK = 0x8123\n    DUAL_CLUTCH = 0x8127\n    WHEEL_CENTER_POSITION = 0x812C\n    DISPLAY_GAME_DATA = 0x8130\n    CENTER_SPRING = 0x8131\n    AXIS_MAPPING = 0x8132\n    GLOBAL_DAMPING = 0x8133\n    BRAKE_FORCE = 0x8134\n    PEDAL_STATUS = 0x8135\n    TORQUE_LIMIT = 0x8136\n    CONFIGURATION_PROFILES = 0x8137\n    OPERATING_RANGE = 0x8138\n    TRUE_FORCE = 0x8139\n    FFB_FILTER = 0x8140\n    # Headsets\n    SIDETONE = 0x8300\n    EQUALIZER = 0x8310\n    HEADSET_OUT = 0x8320\n    # Fake features for Solaar internal use\n    MOUSE_GESTURE = 0xFE00\n\n    def __str__(self):\n        return self.name.replace(\"_\", \" \")\n\n\nclass FeatureFlag(IntFlag):\n    \"\"\"Single bit flags.\"\"\"\n\n    INTERNAL = 0x20\n    HIDDEN = 0x40\n    OBSOLETE = 0x80\n\n\nDEVICE_KIND = NamedInts(\n    keyboard=0x00,\n    remote_control=0x01,\n    numpad=0x02,\n    mouse=0x03,\n    touchpad=0x04,\n    trackball=0x05,\n    presenter=0x06,\n    receiver=0x07,\n)\n\n\nclass OnboardMode(IntEnum):\n    MODE_NO_CHANGE = 0x00\n    MODE_ONBOARD = 0x01\n    MODE_HOST = 0x02\n\n\nclass ChargeLevel(IntEnum):\n    AVERAGE = 50\n    FULL = 90\n    CRITICAL = 5\n\n\nclass ChargeType(IntEnum):\n    STANDARD = 0x00\n    FAST = 0x01\n    SLOW = 0x02\n\n\nclass ErrorCode(IntEnum):\n    UNKNOWN = 0x01\n    INVALID_ARGUMENT = 0x02\n    OUT_OF_RANGE = 0x03\n    HARDWARE_ERROR = 0x04\n    LOGITECH_ERROR = 0x05\n    INVALID_FEATURE_INDEX = 0x06\n    INVALID_FUNCTION = 0x07\n    BUSY = 0x08\n    UNSUPPORTED = 0x09\n\n\nclass GestureId(IntEnum):\n    \"\"\"Gesture IDs for feature GESTURE_2.\"\"\"\n\n    TAP_1_FINGER = 1  # task Left_Click\n    TAP_2_FINGER = 2  # task Right_Click\n    TAP_3_FINGER = 3\n    CLICK_1_FINGER = 4  # task Left_Click\n    CLICK_2_FINGER = 5  # task Right_Click\n    CLICK_3_FINGER = 6\n    DOUBLE_TAP_1_FINGER = 10\n    DOUBLE_TAP_2_FINGER = 11\n    DOUBLE_TAP_3_FINGER = 12\n    TRACK_1_FINGER = 20  # action MovePointer\n    TRACKING_ACCELERATION = 21\n    TAP_DRAG_1_FINGER = 30  # action Drag\n    TAP_DRAG_2_FINGER = 31  # action SecondaryDrag\n    DRAG_3_FINGER = 32\n    TAP_GESTURES = 33  # group all tap gestures under a single UI setting\n    FN_CLICK_GESTURE_SUPPRESSION = 34  # suppresses Tap and Edge gestures, toggled by Fn+Click\n    SCROLL_1_FINGER = 40  # action ScrollOrPageXY / ScrollHorizontal\n    SCROLL_2_FINGER = 41  # action ScrollOrPageXY / ScrollHorizontal\n    SCROLL_2_FINGER_HORIZONTAL = 42  # action ScrollHorizontal\n    SCROLL_2_FINGER_VERTICAL = 43  # action WheelScrolling\n    SCROLL_2_FINGER_STATELESS = 44\n    NATURAL_SCROLLING = 45  # affects native HID wheel reporting by gestures, not when diverted\n    THUMBWHEEL = (46,)  # action WheelScrolling\n    V_SCROLL_INTERTIA = 48\n    V_SCROLL_BALLISTICS = 49\n    SWIPE_2_FINGER_HORIZONTAL = 50  # action PageScreen\n    SWIPE_3_FINGER_HORIZONTAL = 51  # action PageScreen\n    SWIPE_4_FINGER_HORIZONTAL = 52  # action PageScreen\n    SWIPE_3_FINGER_VERTICAL = 53\n    SWIPE_4_FINGER_VERTICAL = 54\n    LEFT_EDGE_SWIPE_1_FINGER = 60\n    RIGHT_EDGE_SWIPE_1_FINGER = 61\n    BOTTOM_EDGE_SWIPE_1_FINGER = 62\n    TOP_EDGE_SWIPE_1_FINGER = 63\n    LEFT_EDGE_SWIPE_1_FINGER_2 = 64  # task HorzScrollNoRepeatSet\n    RIGHT_EDGE_SWIPE_1_FINGER_2 = 65\n    BOTTOM_EDGE_SWIPE_1_FINGER_2 = 66\n    TOP_EDGE_SWIPE_1_FINGER_2 = 67\n    LEFT_EDGE_SWIPE_2_FINGER = 70\n    RIGHT_EDGE_SWIPE_2_FINGER = 71\n    BottomEdgeSwipe2Finger = 72\n    BOTTOM_EDGE_SWIPE_2_FINGER = 72\n    TOP_EDGE_SWIPE_2_FINGER = 73\n    ZOOM_2_FINGER = 80  # action Zoom\n    ZOOM_2_FINGER_PINCH = 81  # ZoomBtnInSet\n    ZOOM_2_FINGER_SPREAD = 82  # ZoomBtnOutSet\n    ZOOM_3_FINGER = 83\n    ZOOM_2_FINGER_STATELESS = 84\n    TWO_FINGERS_PRESENT = 85\n    ROTATE_2_FINGER = 87\n    FINGER_1 = 90\n    FINGER_2 = 91\n    FINGER_3 = 92\n    FINGER_4 = 93\n    FINGER_5 = 94\n    FINGER_6 = 95\n    FINGER_7 = 96\n    FINGER_8 = 97\n    FINGER_9 = 98\n    FINGER_10 = 99\n    DEVICE_SPECIFIC_RAW_DATA = 100\n\n\nclass ParamId(IntEnum):\n    \"\"\"Param Ids for feature GESTURE_2\"\"\"\n\n    EXTRA_CAPABILITIES = 1  # not suitable for use\n    PIXEL_ZONE = 2  # 4 2-byte integers, left, bottom, width, height; pixels\n    RATIO_ZONE = 3  # 4 bytes, left, bottom, width, height; unit 1/240 pad size\n    SCALE_FACTOR = 4  # 2-byte integer, with 256 as normal scale\n\n\nHapticWaveForms = NamedInts(\n    SHARP_STATE_CHANGE=0x00,\n    DAMP_STATE_CHANGE=0x01,\n    SHARP_COLLISION=0x02,\n    DAMP_COLLISION=0x03,\n    SUBTLE_COLLISION=0x04,\n    HAPPY_ALERT=0x05,\n    ANGRY_ALERT=0x06,\n    COMPLETED=0x07,\n    SQUARE=0x08,\n    WAVE=0x09,\n    FIREWORK=0x0A,\n    MAD=0x0B,\n    KNOCK=0x0C,\n    JINGLE=0x0D,\n    RINGING=0xE,\n    WHISPER_COLLISION=0x1B,\n)\n"
  },
  {
    "path": "lib/logitech_receiver/i18n.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n# Translation support for the Logitech receivers library\n\nimport gettext\n\n_ = gettext.gettext\nngettext = gettext.ngettext\n\n# A few common strings, not always accessible as such in the code.\n\n_DUMMY = (\n    # approximative battery levels\n    _(\"empty\"),\n    _(\"critical\"),\n    _(\"low\"),\n    _(\"average\"),\n    _(\"good\"),\n    _(\"full\"),\n    # battery charging statuses\n    _(\"discharging\"),\n    _(\"recharging\"),\n    _(\"charging\"),\n    _(\"not charging\"),\n    _(\"almost full\"),\n    _(\"charged\"),\n    _(\"slow recharge\"),\n    _(\"invalid battery\"),\n    _(\"thermal error\"),\n    _(\"error\"),\n    _(\"standard\"),\n    _(\"fast\"),\n    _(\"slow\"),\n    # pairing errors\n    _(\"device timeout\"),\n    _(\"device not supported\"),\n    _(\"too many devices\"),\n    _(\"sequence timeout\"),\n    # firmware kinds\n    _(\"Firmware\"),\n    _(\"Bootloader\"),\n    _(\"Hardware\"),\n    _(\"Other\"),\n    # common button and task names (from special_keys.py)\n    _(\"Left Button\"),\n    _(\"Right Button\"),\n    _(\"Middle Button\"),\n    _(\"Back Button\"),\n    _(\"Forward Button\"),\n    _(\"Mouse Gesture Button\"),\n    _(\"Smart Shift\"),\n    _(\"DPI Switch\"),\n    _(\"Left Tilt\"),\n    _(\"Right Tilt\"),\n    _(\"Left Click\"),\n    _(\"Right Click\"),\n    _(\"Mouse Middle Button\"),\n    _(\"Mouse Back Button\"),\n    _(\"Mouse Forward Button\"),\n    _(\"Gesture Button Navigation\"),\n    _(\"Mouse Scroll Left Button\"),\n    _(\"Mouse Scroll Right Button\"),\n    # key/button statuses\n    _(\"pressed\"),\n    _(\"released\"),\n)\n"
  },
  {
    "path": "lib/logitech_receiver/listener.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport logging\nimport queue\nimport threading\n\nfrom . import base\nfrom . import exceptions\n\nlogger = logging.getLogger(__name__)\n\n\nclass _ThreadedHandle:\n    \"\"\"A thread-local wrapper with different open handles for each thread.\n    Closing a ThreadedHandle will close all handles.\n    \"\"\"\n\n    __slots__ = (\"path\", \"_local\", \"_handles\", \"_listener\")\n\n    def __init__(self, listener, path, handle):\n        assert listener is not None\n        assert path is not None\n        assert handle is not None\n        assert isinstance(handle, int)\n\n        self._listener = listener\n        self.path = path\n        self._local = threading.local()\n        # take over the current handle for the thread doing the replacement\n        self._local.handle = handle\n        self._handles = [handle]\n\n    def _open(self):\n        handle = base.open_path(self.path)\n        if handle is None:\n            logger.error(\"%r failed to open new handle\", self)\n        else:\n            # if logger.isEnabledFor(logging.DEBUG):\n            #     logger.debug(\"%r opened new handle %d\", self, handle)\n            self._local.handle = handle\n            self._handles.append(handle)\n            return handle\n\n    def close(self):\n        if self._local:\n            self._local = None\n            handles, self._handles = self._handles, []\n            if logger.isEnabledFor(logging.DEBUG):\n                logger.debug(\"%r closing %s\", self, handles)\n            for h in handles:\n                base.close(h)\n\n    @property\n    def notifications_hook(self):\n        if self._listener:\n            assert isinstance(self._listener, threading.Thread)\n            if threading.current_thread() == self._listener:\n                return self._listener._notifications_hook\n\n    def __del__(self):\n        self._listener = None\n        self.close()\n\n    def __index__(self):\n        if self._local:\n            try:\n                return self._local.handle\n            except Exception:\n                return self._open()\n        else:\n            return -1\n\n    __int__ = __index__\n\n    def __str__(self):\n        if self._local:\n            return str(int(self))\n\n    def __repr__(self):\n        return f\"<_ThreadedHandle({self.path})>\"\n\n    def __bool__(self):\n        return bool(self._local)\n\n    __nonzero__ = __bool__\n\n\n# How long to wait during a read for the next packet, in seconds.\n# Ideally this should be rather long (10s ?), but the read is blocking and this means that when the thread\n# is signalled to stop, it would take a while for it to acknowledge it.\n# Forcibly closing the file handle on another thread does _not_ interrupt the read on Linux systems.\n_EVENT_READ_TIMEOUT = 1.0  # in seconds\n\n\nclass EventsListener(threading.Thread):\n    \"\"\"Listener thread for notifications from the Unifying Receiver.\n    Incoming packets will be passed to the callback function in sequence.\n    \"\"\"\n\n    def __init__(self, receiver, notifications_callback):\n        try:\n            path_name = receiver.path.split(\"/\")[2]\n        except IndexError:\n            path_name = receiver.path\n        super().__init__(name=f\"{self.__class__.__name__}:{path_name}\")\n        self.daemon = True\n        self._active = False\n        self.receiver = receiver\n        self._queued_notifications = queue.Queue(16)\n        self._notifications_callback = notifications_callback\n\n    def run(self):\n        self._active = True\n        # replace the handle with a threaded one\n        self.receiver.handle = _ThreadedHandle(self, self.receiver.path, self.receiver.handle)\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"started with %s (%d)\", self.receiver, int(self.receiver.handle))\n        self.has_started()\n\n        if self.receiver.isDevice:  # ping (wired or BT) devices to see if they are really online\n            if self.receiver.ping():\n                self.receiver.changed(active=True, reason=\"initialization\")\n\n        while self._active:\n            if self._queued_notifications.empty():\n                try:\n                    n = base.read(self.receiver.handle, _EVENT_READ_TIMEOUT)\n                except exceptions.NoReceiver:\n                    logger.warning(\"%s disconnected\", self.receiver.name)\n                    self.receiver.close()\n                    break\n                if n:\n                    n = base.make_notification(*n)\n            else:\n                n = self._queued_notifications.get()  # deliver any queued notifications\n            if n:\n                try:\n                    self._notifications_callback(n)\n                except Exception:\n                    logger.exception(\"processing %s\", n)\n\n        del self._queued_notifications\n        self.has_stopped()\n\n    def stop(self):\n        \"\"\"Tells the listener to stop as soon as possible.\"\"\"\n        self._active = False\n\n    def has_started(self):\n        \"\"\"Called right after the thread has started, and before it starts\n        reading notification packets.\"\"\"\n        pass\n\n    def has_stopped(self):\n        \"\"\"Called right before the thread stops.\"\"\"\n        pass\n\n    def _notifications_hook(self, n):\n        # Only consider unhandled notifications that were sent from this thread,\n        # i.e. triggered by a callback handling a previous notification.\n        assert threading.current_thread() == self\n        if self._active:  # and threading.current_thread() == self:\n            # if logger.isEnabledFor(logging.DEBUG):\n            #     logger.debug(\"queueing unhandled %s\", n)\n            if not self._queued_notifications.full():\n                self._queued_notifications.put(n)\n\n    def __bool__(self):\n        return bool(self._active and self.receiver)\n\n    __nonzero__ = __bool__\n"
  },
  {
    "path": "lib/logitech_receiver/notifications.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n\"\"\"Handles incoming events from the receiver/devices, updating the\nobject as appropriate.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nimport struct\nimport threading\nimport typing\n\nfrom solaar.i18n import _\n\nfrom . import base\nfrom . import common\nfrom . import diversion\nfrom . import hidpp10\nfrom . import hidpp10_constants\nfrom . import hidpp20\nfrom . import settings_templates\nfrom .common import Alert\nfrom .common import BatteryStatus\nfrom .common import Notification\nfrom .hidpp10_constants import Registers\nfrom .hidpp20_constants import SupportedFeature\n\nif typing.TYPE_CHECKING:\n    from .base import HIDPPNotification\n    from .device import Device\n    from .receiver import Receiver\n\nlogger = logging.getLogger(__name__)\n\nNotificationHandler = typing.Callable[[\"Receiver\", \"HIDPPNotification\"], bool]\n\n_hidpp10 = hidpp10.Hidpp10()\n_hidpp20 = hidpp20.Hidpp20()\n\nnotification_lock = threading.Lock()\n\n\ndef process(device: Device | Receiver, notification: HIDPPNotification):\n    \"\"\"Handle incoming events (notification) from device or receiver.\"\"\"\n    assert device\n    assert notification\n\n    if not device.isDevice:\n        return process_receiver_notification(device, notification)\n    return process_device_notification(device, notification)\n\n\ndef process_receiver_notification(receiver: Receiver, notification: HIDPPNotification) -> bool | None:\n    \"\"\"Process event messages from receivers.\"\"\"\n    event_handler_mapping: dict[int, NotificationHandler] = {\n        Notification.PAIRING_LOCK: handle_pairing_lock,\n        Registers.DEVICE_DISCOVERY_NOTIFICATION: handle_device_discovery,\n        Registers.DISCOVERY_STATUS_NOTIFICATION: handle_discovery_status,\n        Registers.PAIRING_STATUS_NOTIFICATION: handle_pairing_status,\n        Registers.PASSKEY_PRESSED_NOTIFICATION: handle_passkey_pressed,\n        Registers.PASSKEY_REQUEST_NOTIFICATION: handle_passkey_request,\n    }\n\n    try:\n        handler_func = event_handler_mapping[notification.sub_id]\n        return handler_func(receiver, notification)\n    except KeyError:\n        pass\n\n    assert notification.sub_id in [\n        Notification.CONNECT_DISCONNECT,\n        Notification.DJ_PAIRING,\n        Notification.CONNECTED,\n        Notification.RAW_INPUT,\n        Notification.POWER,\n    ]\n\n    logger.warning(f\"{receiver}: unhandled notification {notification}\")\n\n\ndef process_device_notification(device: Device, notification: HIDPPNotification):\n    \"\"\"Process event messages from devices.\"\"\"\n\n    # incoming packets with SubId >= 0x80 are supposedly replies from HID++ 1.0 requests, should never get here\n    assert notification.sub_id & 0x80 == 0\n\n    if notification.sub_id == Notification.NO_OPERATION:\n        # dispose it\n        return False\n\n    # Allow the device object to handle the notification using custom per-device state.\n    handling_ret = device.handle_notification(notification)\n    if handling_ret is not None:\n        return handling_ret\n\n    # 0x40 to 0x7F appear to be HID++ 1.0 or DJ notifications\n    if notification.sub_id >= 0x40:\n        if notification.report_id == base.DJ_MESSAGE_ID:\n            return _process_dj_notification(device, notification)\n        else:\n            return _process_hidpp10_notification(device, notification)\n\n    # These notifications are from the device itself, so it must be active\n    device.online = True\n    # At this point, we need to know the device's protocol, otherwise it's possible to not know how to handle it.\n    assert device.protocol is not None\n\n    # some custom battery events for HID++ 1.0 devices\n    if device.protocol < 2.0:\n        return _process_hidpp10_custom_notification(device, notification)\n\n    # assuming 0x00 to 0x3F are feature (HID++ 2.0) notifications\n    if not device.features:\n        logger.warning(\"%s: feature notification but features not set up: %02X %s\", device, notification.sub_id, notification)\n        return False\n\n    return _process_feature_notification(device, notification)\n\n\ndef _process_dj_notification(device: Device, notification: HIDPPNotification):\n    if logger.isEnabledFor(logging.DEBUG):\n        logger.debug(\"%s (%s) DJ %s\", device, device.protocol, notification)\n\n    if notification.sub_id == Notification.CONNECT_DISCONNECT:\n        # do all DJ paired notifications also show up as HID++ 1.0 notifications?\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"%s: ignoring DJ unpaired: %s\", device, notification)\n        return True\n\n    if notification.sub_id == Notification.DJ_PAIRING:\n        # do all DJ paired notifications also show up as HID++ 1.0 notifications?\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"%s: ignoring DJ paired: %s\", device, notification)\n        return True\n\n    if notification.sub_id == Notification.CONNECTED:\n        connected = not notification.address & 0x01\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"%s: DJ connection: %s %s\", device, connected, notification)\n        device.changed(active=connected, alert=Alert.NONE, reason=_(\"connected\") if connected else _(\"disconnected\"))\n        return True\n\n    logger.warning(\"%s: unrecognized DJ %s\", device, notification)\n\n\ndef _process_hidpp10_custom_notification(device: Device, notification: HIDPPNotification):\n    if logger.isEnabledFor(logging.DEBUG):\n        logger.debug(\"%s (%s) custom notification %s\", device, device.protocol, notification)\n\n    if notification.sub_id in (Registers.BATTERY_STATUS, Registers.BATTERY_CHARGE):\n        assert notification.data[-1:] == b\"\\x00\"\n        data = chr(notification.address).encode() + notification.data\n        device.set_battery_info(hidpp10.parse_battery_status(notification.sub_id, data))\n        return True\n\n    logger.warning(\"%s: unrecognized %s\", device, notification)\n\n\ndef _process_hidpp10_notification(device: Device, notification: HIDPPNotification):\n    if notification.sub_id == Notification.CONNECT_DISCONNECT:  # device unpairing\n        if notification.address == 0x02:\n            # device un-paired\n            device.wpid = None\n            if device.number in device.receiver:\n                del device.receiver[device.number]\n            device.changed(active=False, alert=Alert.ALL, reason=_(\"unpaired\"))\n        ##            device.status = None\n        else:\n            logger.warning(\"%s: disconnection with unknown type %02X: %s\", device, notification.address, notification)\n        return True\n\n    if notification.sub_id == Notification.DJ_PAIRING:  # device connection (and disconnection)\n        flags = ord(notification.data[:1]) & 0xF0\n        if notification.address == 0x02:  # very old 27 MHz protocol\n            wpid = \"00\" + common.strhex(notification.data[2:3])\n            link_established = True\n            link_encrypted = bool(flags & 0x80)\n        elif notification.address > 0x00:  # all other protocols are supposed to be almost the same\n            wpid = common.strhex(notification.data[2:3] + notification.data[1:2])\n            link_established = not (flags & 0x40)\n            link_encrypted = bool(flags & 0x20) or notification.address == 0x10  # Bolt protocol always encrypted\n        else:\n            logger.warning(\n                \"%s: connection notification with unknown protocol %02X: %s\", device.number, notification.address, notification\n            )\n            return True\n        if wpid != device.wpid:\n            logger.warning(\"%s wpid mismatch, got %s\", device, wpid)\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\n                \"%s: protocol %s connection notification: software=%s, encrypted=%s, link=%s, payload=%s\",\n                device,\n                notification.address,\n                bool(flags & 0x10),\n                link_encrypted,\n                link_established,\n                bool(flags & 0x80),\n            )\n        device.link_encrypted = link_encrypted\n        if not link_established and device.receiver:\n            hidpp10.set_configuration_pending_flags(device.receiver, 0xFF)\n        device.changed(active=link_established)\n        return True\n\n    if notification.sub_id == Notification.RAW_INPUT:\n        # raw input event? just ignore it\n        # if notification.address == 0x01, no idea what it is, but they keep on coming\n        # if notification.address == 0x03, appears to be an actual input event, because they only come when input happents\n        return True\n\n    if notification.sub_id == Notification.POWER:\n        if notification.address == 0x01:\n            if logger.isEnabledFor(logging.DEBUG):\n                logger.debug(\"%s: device powered on\", device)\n            reason = device.status_string() or _(\"powered on\")\n            device.changed(active=True, alert=Alert.NOTIFICATION, reason=reason)\n        else:\n            logger.warning(\"%s: unknown %s\", device, notification)\n        return True\n\n    logger.warning(\"%s: unrecognized %s\", device, notification)\n\n\ndef _process_feature_notification(device: Device, notification: HIDPPNotification):\n    old_present, device.present = device.present, True  # the device is generating a feature notification so it must be present\n    try:\n        feature = device.features.get_feature(notification.sub_id)\n    except IndexError:\n        logger.warning(\"%s: notification from invalid feature index %02X: %s\", device, notification.sub_id, notification)\n        return False\n\n    if logger.isEnabledFor(logging.DEBUG):\n        logger.debug(\n            \"%s: notification for feature %s, report %s, data %s\",\n            device,\n            feature,\n            notification.address >> 4,\n            common.strhex(notification.data),\n        )\n\n    if feature == SupportedFeature.BATTERY_STATUS:\n        if notification.address == 0x00:\n            device.set_battery_info(hidpp20.decipher_battery_status(notification.data)[1])\n        elif notification.address == 0x10:\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"%s: spurious BATTERY status %s\", device, notification)\n        else:\n            logger.warning(\"%s: unknown BATTERY %s\", device, notification)\n\n    elif feature == SupportedFeature.BATTERY_VOLTAGE:\n        if notification.address == 0x00:\n            device.set_battery_info(hidpp20.decipher_battery_voltage(notification.data)[1])\n        else:\n            logger.warning(\"%s: unknown VOLTAGE %s\", device, notification)\n\n    elif feature == SupportedFeature.UNIFIED_BATTERY:\n        if notification.address == 0x00:\n            device.set_battery_info(hidpp20.decipher_battery_unified(notification.data)[1])\n        else:\n            logger.warning(\"%s: unknown UNIFIED BATTERY %s\", device, notification)\n\n    elif feature == SupportedFeature.ADC_MEASUREMENT:\n        if notification.address == 0x00:\n            result = hidpp20.decipher_adc_measurement(notification.data)\n            if result:  # if good data and  the device was not present then a push is needed\n                device.set_battery_info(result[1])\n                device.changed(active=True, alert=Alert.NONE, reason=_(\"ADC measurement notification\"), push=not old_present)\n            else:  # this feature is also used to signal device becoming inactive\n                device.present = False  # exception to device presence\n                device.changed(active=False)\n        else:\n            logger.warning(\"%s: unknown ADC MEASUREMENT %s\", device, notification)\n\n    elif feature == SupportedFeature.SOLAR_DASHBOARD:\n        if notification.data[5:9] == b\"GOOD\":\n            charge, lux, adc = struct.unpack(\"!BHH\", notification.data[:5])\n            # guesstimate the battery voltage, emphasis on 'guess'\n            # status_text = '%1.2fV' % (adc * 2.67793237653 / 0x0672)\n            status_text = BatteryStatus.DISCHARGING\n            if notification.address == 0x00:\n                device.set_battery_info(common.Battery(charge, None, status_text, None))\n            elif notification.address == 0x10:\n                if lux > 200:\n                    status_text = BatteryStatus.RECHARGING\n                device.set_battery_info(common.Battery(charge, None, status_text, None, lux))\n            elif notification.address == 0x20:\n                if logger.isEnabledFor(logging.DEBUG):\n                    logger.debug(\"%s: Light Check button pressed\", device)\n                device.changed(alert=Alert.SHOW_WINDOW)\n                # first cancel any reporting\n                # device.feature_request(SupportedFeature.SOLAR_DASHBOARD)\n                # trigger a new report chain\n                reports_count = 15\n                reports_period = 2  # seconds\n                device.feature_request(SupportedFeature.SOLAR_DASHBOARD, 0x00, reports_count, reports_period)\n            else:\n                logger.warning(\"%s: unknown SOLAR CHARGE %s\", device, notification)\n        else:\n            logger.warning(\"%s: SOLAR CHARGE not GOOD? %s\", device, notification)\n\n    elif feature == SupportedFeature.WIRELESS_DEVICE_STATUS:\n        if notification.address == 0x00:\n            if logger.isEnabledFor(logging.DEBUG):\n                logger.debug(\"wireless status: %s\", notification)\n            reason = \"powered on\" if notification.data[2] == 1 else None\n            if notification.data[1] == 1:  # device is asking for software reconfiguration so need to change status\n                alert = Alert.NONE\n                device.changed(active=True, alert=alert, reason=reason, push=True)\n        else:\n            logger.warning(\"%s: unknown WIRELESS %s\", device, notification)\n\n    elif feature == SupportedFeature.TOUCHMOUSE_RAW_POINTS:\n        if notification.address == 0x00:\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"%s: TOUCH MOUSE points %s\", device, notification)\n        elif notification.address == 0x10:\n            touch = ord(notification.data[:1])\n            button_down = bool(touch & 0x02)\n            mouse_lifted = bool(touch & 0x01)\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"%s: TOUCH MOUSE status: button_down=%s mouse_lifted=%s\", device, button_down, mouse_lifted)\n        else:\n            logger.warning(\"%s: unknown TOUCH MOUSE %s\", device, notification)\n\n    # TODO: what are REPROG_CONTROLS_V{2,3}?\n    elif feature == SupportedFeature.REPROG_CONTROLS:\n        if notification.address == 0x00:\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"%s: reprogrammable key: %s\", device, notification)\n        else:\n            logger.warning(\"%s: unknown REPROG_CONTROLS %s\", device, notification)\n\n    elif feature == SupportedFeature.BACKLIGHT2:\n        if notification.address == 0x00:\n            level = struct.unpack(\"!B\", notification.data[1:2])[0]\n            if device.setting_callback:\n                device.setting_callback(device, settings_templates.Backlight2Level, [level])\n\n    elif feature == SupportedFeature.REPROG_CONTROLS_V4:\n        if notification.address == 0x00:\n            if logger.isEnabledFor(logging.DEBUG):\n                cid1, cid2, cid3, cid4 = struct.unpack(\"!HHHH\", notification.data[:8])\n                logger.debug(\"%s: diverted controls pressed: 0x%x, 0x%x, 0x%x, 0x%x\", device, cid1, cid2, cid3, cid4)\n        elif notification.address == 0x10:\n            if logger.isEnabledFor(logging.DEBUG):\n                dx, dy = struct.unpack(\"!hh\", notification.data[:4])\n                logger.debug(\"%s: rawXY dx=%i dy=%i\", device, dx, dy)\n        elif notification.address == 0x20:\n            if logger.isEnabledFor(logging.DEBUG):\n                logger.debug(\"%s: received analyticsKeyEvents\", device)\n        elif logger.isEnabledFor(logging.INFO):\n            logger.info(\"%s: unknown REPROG_CONTROLS_V4 %s\", device, notification)\n\n    elif feature == SupportedFeature.HIRES_WHEEL:\n        if notification.address == 0x00:\n            if logger.isEnabledFor(logging.INFO):\n                flags, delta_v = struct.unpack(\">bh\", notification.data[:3])\n                high_res = (flags & 0x10) != 0\n                periods = flags & 0x0F\n                logger.info(\"%s: WHEEL: res: %d periods: %d delta V:%-3d\", device, high_res, periods, delta_v)\n        elif notification.address == 0x10:\n            ratchet = notification.data[0]\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"%s: WHEEL: ratchet: %d\", device, ratchet)\n            if ratchet < 2:  # don't process messages with unusual ratchet values\n                if device.setting_callback:\n                    device.setting_callback(device, settings_templates.ScrollRatchet, [2 if ratchet else 1])\n        else:\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"%s: unknown WHEEL %s\", device, notification)\n\n    elif feature == SupportedFeature.ONBOARD_PROFILES:\n        if notification.address > 0x10:\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"%s: unknown ONBOARD PROFILES %s\", device, notification)\n        else:\n            if notification.address == 0x00:\n                profile_sector = struct.unpack(\"!H\", notification.data[:2])[0]\n                if profile_sector:\n                    settings_templates.profile_change(device, profile_sector)\n            elif notification.address == 0x10:\n                resolution_index = struct.unpack(\"!B\", notification.data[:1])[0]\n                profile_sector = struct.unpack(\"!H\", device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x40)[:2])[0]\n                if device.setting_callback:\n                    for profile in device.profiles.profiles.values() if device.profiles else []:\n                        if profile.sector == profile_sector:\n                            device.setting_callback(\n                                device, settings_templates.AdjustableDpi, [profile.resolutions[resolution_index]]\n                            )\n                            break\n\n    elif feature == SupportedFeature.BRIGHTNESS_CONTROL:\n        if notification.address > 0x10:\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"%s: unknown BRIGHTNESS CONTROL %s\", device, notification)\n        else:\n            if notification.address == 0x00:\n                brightness = struct.unpack(\"!H\", notification.data[:2])[0]\n                device.setting_callback(device, settings_templates.BrightnessControl, [brightness])\n            elif notification.address == 0x10:\n                brightness = notification.data[0] & 0x01\n                if brightness:\n                    brightness = struct.unpack(\"!H\", device.feature_request(SupportedFeature.BRIGHTNESS_CONTROL, 0x10)[:2])[0]\n                device.setting_callback(device, settings_templates.BrightnessControl, [brightness])\n\n    diversion.process_notification(device, notification, feature)\n    return True\n\n\ndef handle_pairing_lock(receiver: Receiver, notification: HIDPPNotification) -> bool:\n    receiver.pairing.lock_open = bool(notification.address & 0x01)\n    reason = _(\"pairing lock is open\") if receiver.pairing.lock_open else _(\"pairing lock is closed\")\n    if logger.isEnabledFor(logging.INFO):\n        logger.info(\"%s: %s\", receiver, reason)\n    receiver.pairing.error = None\n    if receiver.pairing.lock_open:\n        receiver.pairing.new_device = None\n    pair_error = ord(notification.data[:1])\n    if pair_error:\n        error_string = hidpp10_constants.PairingError(pair_error).label\n        receiver.pairing.error = error_string\n        receiver.pairing.new_device = None\n        logger.warning(\"pairing error %d: %s\", pair_error, error_string)\n    receiver.changed(reason=reason)\n    return True\n\n\ndef handle_discovery_status(receiver: Receiver, notification: HIDPPNotification) -> bool:\n    with notification_lock:\n        receiver.pairing.discovering = notification.address == 0x00\n        reason = _(\"discovery lock is open\") if receiver.pairing.discovering else _(\"discovery lock is closed\")\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"%s: %s\", receiver, reason)\n        receiver.pairing.error = None\n        if receiver.pairing.discovering:\n            receiver.pairing.counter = receiver.pairing.device_address = None\n            receiver.pairing.device_authentication = receiver.pairing.device_name = None\n        receiver.pairing.device_passkey = None\n        discover_error = ord(notification.data[:1])\n        if discover_error:\n            receiver.pairing.error = discover_string = hidpp10_constants.BoltPairingError(discover_error).label\n            logger.warning(\"bolt discovering error %d: %s\", discover_error, discover_string)\n        receiver.changed(reason=reason)\n        return True\n\n\ndef handle_device_discovery(receiver: Receiver, notification: HIDPPNotification) -> bool:\n    with notification_lock:\n        counter = notification.address + notification.data[0] * 256  # notification counter\n        if receiver.pairing.counter is None:\n            receiver.pairing.counter = counter\n        else:\n            if not receiver.pairing.counter == counter:\n                return None\n        if notification.data[1] == 0:\n            receiver.pairing.device_kind = notification.data[3]\n            receiver.pairing.device_address = notification.data[6:12]\n            receiver.pairing.device_authentication = notification.data[14]\n        elif notification.data[1] == 1:\n            receiver.pairing.device_name = notification.data[3 : 3 + notification.data[2]].decode(\"utf-8\")\n        return True\n\n\ndef handle_pairing_status(receiver: Receiver, notification: HIDPPNotification) -> bool:\n    with notification_lock:\n        receiver.pairing.device_passkey = None\n        receiver.pairing.lock_open = notification.address == 0x00\n        reason = _(\"pairing lock is open\") if receiver.pairing.lock_open else _(\"pairing lock is closed\")\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"%s: %s\", receiver, reason)\n        receiver.pairing.error = None\n        if not receiver.pairing.lock_open:\n            receiver.pairing.counter = None\n            receiver.pairing.device_address = None\n            receiver.pairing.device_authentication = None\n            receiver.pairing.device_name = None\n        pair_error = notification.data[0]\n        if receiver.pairing.lock_open:\n            receiver.pairing.new_device = None\n        elif notification.address == 0x02 and not pair_error:\n            receiver.pairing.new_device = receiver.register_new_device(notification.data[7])\n        if pair_error:\n            receiver.pairing.error = error_string = hidpp10_constants.BoltPairingError(pair_error).label\n            receiver.pairing.new_device = None\n            logger.warning(\"pairing error %d: %s\", pair_error, error_string)\n        receiver.changed(reason=reason)\n        return True\n\n\ndef handle_passkey_request(receiver: Receiver, notification: HIDPPNotification) -> bool:\n    with notification_lock:\n        receiver.pairing.device_passkey = notification.data[0:6].decode(\"utf-8\")\n        return True\n\n\ndef handle_passkey_pressed(_receiver: Receiver, _hidpp_notification: HIDPPNotification) -> bool:\n    return True\n"
  },
  {
    "path": "lib/logitech_receiver/receiver.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom __future__ import annotations\n\nimport errno\nimport logging\nimport time\nimport typing\n\nfrom dataclasses import dataclass\nfrom typing import Callable\nfrom typing import Optional\nfrom typing import Protocol\n\nfrom solaar.i18n import _\nfrom solaar.i18n import ngettext\n\nfrom . import exceptions\nfrom . import hidpp10\nfrom . import hidpp10_constants\nfrom .common import Alert\nfrom .common import Notification\nfrom .device import Device\nfrom .hidpp10_constants import InfoSubRegisters\nfrom .hidpp10_constants import NotificationFlag\nfrom .hidpp10_constants import Registers\n\nif typing.TYPE_CHECKING:\n    from logitech_receiver import common\n\n    from .base import HIDPPNotification\n\nlogger = logging.getLogger(__name__)\n\n_hidpp10 = hidpp10.Hidpp10()\n\n\nclass LowLevelInterface(Protocol):\n    def open_path(self, path):\n        ...\n\n    def find_paired_node_wpid(self, receiver_path: str, index: int):\n        ...\n\n    def ping(self, handle, number, long_message=False):\n        ...\n\n    def request(self, handle, devnumber, request_id, *params, **kwargs):\n        ...\n\n    def close(self, handle):\n        ...\n\n\n@dataclass\nclass Pairing:\n    \"\"\"Information about the current or most recent pairing\"\"\"\n\n    lock_open: bool = False\n    discovering: bool = False\n    counter: Optional[int] = None\n    device_address: Optional[bytes] = None\n    device_authentication: Optional[int] = None\n    device_kind: Optional[int] = None\n    device_name: Optional[str] = None\n    device_passkey: Optional[str] = None\n    new_device: Optional[Device] = None\n    error: Optional[any] = None\n\n\ndef extract_serial(response: bytes) -> str:\n    \"\"\"Extracts serial number from receiver response.\"\"\"\n    return response.hex().upper()\n\n\ndef extract_max_devices(response: bytes) -> int:\n    \"\"\"Extracts maximum number of supported devices from response.\"\"\"\n    max_devices = response[6]\n    return int(max_devices)\n\n\ndef extract_remaining_pairings(response: bytes) -> int:\n    ps = ord(response[2:3])\n    remaining_pairings = ps - 5 if ps >= 5 else -1\n    return int(remaining_pairings)\n\n\ndef extract_codename(response: bytes) -> str:\n    codename = response[2 : 2 + ord(response[1:2])]\n    return codename.decode(\"ascii\")\n\n\ndef extract_power_switch_location(response: bytes) -> str:\n    \"\"\"Extracts power switch location from response.\"\"\"\n    index = response[9] & 0x0F\n    return hidpp10_constants.PowerSwitchLocation.location(index).name.lower()\n\n\ndef extract_connection_count(response: bytes) -> int:\n    \"\"\"Extract connection count from receiver response.\"\"\"\n    return ord(response[1:2])\n\n\ndef extract_wpid(response: bytes) -> str:\n    \"\"\"Extract wpid from receiver response.\"\"\"\n    return response.hex().upper()\n\n\ndef extract_polling_rate(response: bytes) -> int:\n    \"\"\"Returns polling rate in milliseconds.\"\"\"\n    return int(response[2])\n\n\ndef extract_device_kind(response: int) -> str:\n    return hidpp10_constants.DEVICE_KIND[response]\n\n\nclass Receiver:\n    \"\"\"A generic Receiver instance, mostly implementing the interface used on Unifying, Nano, and LightSpeed receivers\"\n    The paired devices are available through the sequence interface.\n    \"\"\"\n\n    read_register: Callable = hidpp10.read_register\n    write_register: Callable = hidpp10.write_register\n    number = 0xFF\n    kind = None\n\n    def __init__(\n        self,\n        low_level: LowLevelInterface,\n        receiver_kind,\n        product_info,\n        handle,\n        path,\n        product_id,\n        setting_callback=None,\n    ):\n        assert handle\n        self.low_level = low_level\n        self.isDevice = False  # some devices act as receiver so we need a property to distinguish them\n        self.handle = handle\n        self.path = path\n        self.product_id = product_id\n        self.setting_callback = setting_callback  # for changes to settings\n        self.status_callback = None  # for changes to other potentially visible aspects\n        self.receiver_kind = receiver_kind\n        self.serial = None\n        self.max_devices = None\n        self._firmware = None\n        self._remaining_pairings = None\n        self._devices = {}\n        self.name = product_info.get(\"name\", \"Receiver\")\n        self.may_unpair = product_info.get(\"may_unpair\", False)\n        self.re_pairs = product_info.get(\"re_pairs\", False)\n        self.notification_flags = None\n        self.pairing = Pairing()\n        self.initialize(product_info)\n        hidpp10.set_configuration_pending_flags(self, 0xFF)\n\n    def initialize(self, product_info: dict):\n        # read the receiver information subregister, so we can find out max_devices\n        serial_reply = self.read_register(Registers.RECEIVER_INFO, InfoSubRegisters.RECEIVER_INFORMATION)\n        if serial_reply:\n            self.serial = extract_serial(serial_reply[1:5])\n            self.max_devices = extract_max_devices(serial_reply)\n            if not (1 <= self.max_devices <= 6):\n                self.max_devices = product_info.get(\"max_devices\", 1)\n        else:  # handle receivers that don't have a serial number specially (i.e., c534)\n            self.serial = None\n            self.max_devices = product_info.get(\"max_devices\", 1)\n\n    def close(self):\n        handle, self.handle = self.handle, None\n        for _n, d in self._devices.items():\n            if d:\n                d.close()\n        self._devices.clear()\n        return handle and self.low_level.close(handle)\n\n    def __del__(self):\n        self.close()\n\n    def changed(self, alert=Alert.NOTIFICATION, reason=None):\n        \"\"\"The status of the device had changed, so invoke the status callback\"\"\"\n        if self.status_callback is not None:\n            self.status_callback(self, alert=alert, reason=reason)\n\n    @property\n    def firmware(self) -> tuple[common.FirmwareInfo]:\n        if self._firmware is None and self.handle:\n            self._firmware = _hidpp10.get_firmware(self)\n        return self._firmware\n\n    # how many pairings remain (None for unknown, -1 for unlimited)\n    def remaining_pairings(self, cache=True):\n        if self._remaining_pairings is None or not cache:\n            ps = self.read_register(Registers.RECEIVER_CONNECTION)\n            if ps is not None:\n                self._remaining_pairings = extract_remaining_pairings(ps)\n        return self._remaining_pairings\n\n    def enable_connection_notifications(self, enable=True):\n        \"\"\"Enable or disable device (dis)connection notifications on this\n        receiver.\"\"\"\n        if not self.handle:\n            return False\n\n        if enable:\n            set_flag_bits = NotificationFlag.WIRELESS | NotificationFlag.SOFTWARE_PRESENT\n        else:\n            set_flag_bits = 0\n        ok = _hidpp10.set_notification_flags(self, set_flag_bits)\n        if ok is None:\n            logger.warning(\"%s: failed to %s receiver notifications\", self, \"enable\" if enable else \"disable\")\n            return None\n\n        flag_bits = _hidpp10.get_notification_flags(self)\n        if flag_bits is None:\n            flag_names = None\n        else:\n            flag_names = hidpp10_constants.NotificationFlag.flag_names(flag_bits)\n        if logger.isEnabledFor(logging.INFO):\n            logger.info(\"%s: receiver notifications %s => %s\", self, \"enabled\" if enable else \"disabled\", flag_names)\n        return flag_bits\n\n    def device_codename(self, n):\n        codename = self.read_register(Registers.RECEIVER_INFO, InfoSubRegisters.DEVICE_NAME + n - 1)\n        if codename:\n            return extract_codename(codename)\n\n    def notify_devices(self):\n        \"\"\"Scan all devices.\"\"\"\n        if self.handle:\n            if not self.write_register(Registers.RECEIVER_CONNECTION, 0x02):\n                logger.warning(\"%s: failed to trigger device link notifications\", self)\n\n    def notification_information(self, number, notification: HIDPPNotification) -> tuple[bool, bool, typing.Any, str]:\n        \"\"\"Extract information from unifying-style notification\"\"\"\n        assert notification.address != 0x02\n        online = not bool(notification.data[0] & 0x40)\n        encrypted = bool(notification.data[0] & 0x20) or notification.address == 0x10\n        kind = extract_device_kind(notification.data[0] & 0x0F)\n        wpid = extract_wpid(notification.data[2:3] + notification.data[1:2])\n        return online, encrypted, wpid, kind\n\n    def device_pairing_information(self, n: int) -> dict:\n        \"\"\"Return information from pairing registers (and elsewhere when necessary)\"\"\"\n        polling_rate = \"\"\n        serial = None\n        power_switch = \"(unknown)\"\n        pair_info = self.read_register(Registers.RECEIVER_INFO, InfoSubRegisters.PAIRING_INFORMATION + n - 1)\n        if pair_info:  # a receiver that uses Unifying-style pairing registers\n            wpid = extract_wpid(pair_info[3:5])\n            kind = extract_device_kind(pair_info[7] & 0x0F)\n            polling_rate_ms = extract_polling_rate(pair_info)\n            polling_rate = f\"{polling_rate_ms}ms\"\n        elif not self.receiver_kind == \"unifying\":  # may be an old Nano receiver\n            device_info = self.read_register(Registers.RECEIVER_INFO, 0x04)  # undocumented\n            if device_info:\n                logger.warning(\"using undocumented register for device wpid\")\n                wpid = extract_wpid(device_info[3:5])\n                kind = extract_device_kind(0x00)  # unknown kind\n            else:\n                raise exceptions.NoSuchDevice(number=n, receiver=self, error=\"read pairing information - non-unifying\")\n        else:\n            raise exceptions.NoSuchDevice(number=n, receiver=self, error=\"read pairing information\")\n        pair_info = self.read_register(Registers.RECEIVER_INFO, InfoSubRegisters.EXTENDED_PAIRING_INFORMATION + n - 1)\n        if pair_info:\n            power_switch = extract_power_switch_location(pair_info)\n            serial = extract_serial(pair_info[1:5])\n        else:  # some Nano receivers?\n            pair_info = self.read_register(0x2D5)  # undocumented and questionable\n            if pair_info:\n                logger.warning(\"using undocumented register for device serial number\")\n                serial = extract_serial(pair_info[1:5])\n        return {\"wpid\": wpid, \"kind\": kind, \"polling\": polling_rate, \"serial\": serial, \"power_switch\": power_switch}\n\n    def register_new_device(self, number, notification=None):\n        if self._devices.get(number) is not None:\n            raise IndexError(f\"{self}: device number {int(number)} already registered\")\n\n        assert notification is None or notification.devnumber == number\n        assert notification is None or notification.sub_id == Notification.DJ_PAIRING\n\n        try:\n            time.sleep(0.05)  # let receiver settle\n            info = self.device_pairing_information(number)\n            if notification is not None:\n                online, _e, nwpid, nkind = self.notification_information(number, notification)\n                if info[\"wpid\"] is None:\n                    info[\"wpid\"] = nwpid\n                elif nwpid is not None and info[\"wpid\"] != nwpid:\n                    logger.warning(\"mismatch on device WPID %s %s\", info[\"wpid\"], nwpid)\n                if info[\"kind\"] is None:\n                    info[\"kind\"] = nkind\n                elif nkind is not None and info[\"kind\"] != nkind:\n                    logger.warning(\"mismatch on device kind %s %s\", info[\"kind\"], nkind)\n            else:\n                online = True\n            dev = Device(self.low_level, self, number, online, pairing_info=info, setting_callback=self.setting_callback)\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"%s: found new device %d (%s)\", self, number, dev.wpid)\n            self._devices[number] = dev\n            return dev\n        except exceptions.NoSuchDevice as e:\n            logger.warning(\"register new device failed for %s device %d error %s\", e.receiver, e.number, e.error)\n\n        logger.warning(\"%s: looked for device %d, not found\", self, number)\n        self._devices[number] = None\n\n    def set_lock(self, lock_closed=True, device=0, timeout=0):\n        if self.handle:\n            action = 0x02 if lock_closed else 0x01\n            reply = self.write_register(Registers.RECEIVER_PAIRING, action, device, timeout)\n            if reply:\n                return True\n            logger.warning(\"%s: failed to %s the receiver lock\", self, \"close\" if lock_closed else \"open\")\n\n    def count(self):\n        count = self.read_register(Registers.RECEIVER_CONNECTION)\n        if count is None:\n            return 0\n        return extract_connection_count(count)\n\n    def request(self, request_id, *params):\n        if bool(self):\n            return self.low_level.request(self.handle, 0xFF, request_id, *params)\n\n    def reset_pairing(self):\n        self.pairing = Pairing()\n\n    def __iter__(self):\n        connected_devices = self.count()\n        found_devices = 0\n        for number in range(1, 8):  # some receivers have devices past their max # devices\n            if found_devices >= connected_devices:\n                return\n            if number in self._devices:\n                dev = self._devices[number]\n            else:\n                dev = self.__getitem__(number)\n            if dev is not None:\n                found_devices += 1\n                yield dev\n\n    def __getitem__(self, key):\n        if not bool(self):\n            return None\n\n        dev = self._devices.get(key)\n        if dev is not None:\n            return dev\n\n        if not isinstance(key, int):\n            raise TypeError(\"key must be an integer\")\n        if key < 1 or key > 15:  # some receivers have devices past their max # devices\n            raise IndexError(key)\n\n        return self.register_new_device(key)\n\n    def __delitem__(self, key):\n        self._unpair_device(key, False)\n\n    def _unpair_device(self, key, force=False):\n        key = int(key)\n\n        if self._devices.get(key) is None:\n            raise IndexError(key)\n\n        dev = self._devices[key]\n        if not dev:\n            if key in self._devices:\n                del self._devices[key]\n            return\n\n        if self.re_pairs and not force:\n            # invalidate the device, but these receivers don't unpair per se\n            dev.online = False\n            dev.wpid = None\n            if key in self._devices:\n                del self._devices[key]\n            logger.warning(\"%s removed device %s\", self, dev)\n        else:\n            reply = self._unpair_device_per_receiver(key)\n            if reply:\n                # invalidate the device\n                dev.online = False\n                dev.wpid = None\n                if key in self._devices:\n                    del self._devices[key]\n                if logger.isEnabledFor(logging.INFO):\n                    logger.info(\"%s unpaired device %s\", self, dev)\n            else:\n                logger.error(\"%s failed to unpair device %s\", self, dev)\n                raise Exception(f\"failed to unpair device {dev.name}: {key}\")\n\n    def _unpair_device_per_receiver(self, key):\n        \"\"\"Receiver specific unpairing.\"\"\"\n        return self.write_register(Registers.RECEIVER_PAIRING, 0x03, key)\n\n    def __len__(self):\n        return len([d for d in self._devices.values() if d is not None])\n\n    def __contains__(self, dev):\n        if isinstance(dev, int):\n            return self._devices.get(dev) is not None\n\n        return self.__contains__(dev.number)\n\n    def __eq__(self, other):\n        return other is not None and self.kind == other.kind and self.path == other.path\n\n    def __ne__(self, other):\n        return other is None or self.kind != other.kind or self.path != other.path\n\n    def __hash__(self):\n        return self.path.__hash__()\n\n    def status_string(self):\n        count = len(self)\n        return (\n            _(\"No paired devices.\")\n            if count == 0\n            else ngettext(\"%(count)s paired device.\", \"%(count)s paired devices.\", count) % {\"count\": count}\n        )\n\n    def __str__(self):\n        return \"<%s(%s,%s%s)>\" % (\n            self.name.replace(\" \", \"\"),\n            self.path,\n            \"\" if isinstance(self.handle, int) else \"T\",\n            self.handle,\n        )\n\n    __repr__ = __str__\n\n    __bool__ = __nonzero__ = lambda self: self.handle is not None\n\n\nclass BoltReceiver(Receiver):\n    \"\"\"Bolt receivers use a different pairing prototol and have different pairing registers\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n    def initialize(self, product_info: dict):\n        serial_reply = self.read_register(Registers.BOLT_UNIQUE_ID)\n        self.serial = extract_serial(serial_reply)\n        self.max_devices = product_info.get(\"max_devices\", 1)\n\n    def device_codename(self, n):\n        codename = self.read_register(Registers.RECEIVER_INFO, InfoSubRegisters.BOLT_DEVICE_NAME + n, 0x01)\n        if codename:\n            codename = codename[3 : 3 + min(14, ord(codename[2:3]))]\n            return codename.decode(\"ascii\")\n\n    def device_pairing_information(self, n: int) -> dict:\n        pair_info = self.read_register(Registers.RECEIVER_INFO, InfoSubRegisters.BOLT_PAIRING_INFORMATION + n)\n        if pair_info:\n            wpid = extract_wpid(pair_info[3:4] + pair_info[2:3])\n            kind = extract_device_kind(pair_info[1] & 0x0F)\n            serial = extract_serial(pair_info[4:8])\n            return {\"wpid\": wpid, \"kind\": kind, \"polling\": None, \"serial\": serial, \"power_switch\": \"(unknown)\"}\n        else:\n            raise exceptions.NoSuchDevice(number=n, receiver=self, error=\"can't read Bolt pairing register\")\n\n    def discover(self, cancel=False, timeout=30):\n        \"\"\"Discover Logitech Bolt devices.\"\"\"\n        if self.handle:\n            action = 0x02 if cancel else 0x01\n            reply = self.write_register(Registers.BOLT_DEVICE_DISCOVERY, timeout, action)\n            if reply:\n                return True\n            logger.warning(\"%s: failed to %s device discovery\", self, \"cancel\" if cancel else \"start\")\n\n    def pair_device(self, pair=True, slot=0, address=b\"\\0\\0\\0\\0\\0\\0\", authentication=0x00, entropy=20):\n        \"\"\"Pair a Bolt device.\"\"\"\n        if self.handle:\n            action = 0x01 if pair is True else 0x03 if pair is False else 0x02\n            reply = self.write_register(Registers.BOLT_PAIRING, action, slot, address, authentication, entropy)\n            if reply:\n                return True\n            logger.warning(\"%s: failed to %s device %s\", self, \"pair\" if pair else \"unpair\", address)\n\n    def _unpair_device_per_receiver(self, key):\n        \"\"\"Receiver specific unpairing.\"\"\"\n        return self.write_register(Registers.BOLT_PAIRING, 0x03, key)\n\n\nclass UnifyingReceiver(Receiver):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n\nclass NanoReceiver(Receiver):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n\nclass LightSpeedReceiver(Receiver):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n\nclass Ex100Receiver(Receiver):\n    \"\"\"A very old style receiver, somewhat different from newer receivers\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n    def initialize(self, product_info: dict):\n        self.serial = None\n        self.max_devices = product_info.get(\"max_devices\", 1)\n\n    def notification_information(self, number, notification):\n        \"\"\"Extract information from 27Mz-style notification and device index\"\"\"\n        assert notification.address == 0x02\n        online = True\n        encrypted = bool(notification.data[0] & 0x80)\n        kind = extract_device_kind(_get_kind_from_index(self, number))\n        wpid = \"00\" + extract_wpid(notification.data[2:3])\n        return online, encrypted, wpid, kind\n\n    def device_pairing_information(self, number: int) -> dict:\n        # extract WPID from udev path\n        wpid = self.low_level.find_paired_node_wpid(self.path, number)\n        if not wpid:\n            logger.error(\"Unable to get wpid from udev for device %d of %s\", number, self)\n            raise exceptions.NoSuchDevice(number=number, receiver=self, error=\"Not present 27Mhz device\")\n        kind = extract_device_kind(_get_kind_from_index(self, number))\n        return {\"wpid\": wpid, \"kind\": kind, \"polling\": \"\", \"serial\": None, \"power_switch\": \"(unknown)\"}\n\n\ndef _get_kind_from_index(receiver, index: int) -> int:\n    \"\"\"Get device kind from 27Mhz device index\"\"\"\n    # From drivers/hid/hid-logitech-dj.c\n    if index == 1:  # mouse\n        kind = 2\n    elif index == 2:  # mouse\n        kind = 2\n    elif index == 3:  # keyboard\n        kind = 1\n    elif index == 4:  # numpad\n        kind = 3\n    else:  # unknown device number on 27Mhz receiver\n        logger.error(\"failed to calculate device kind for device %d of %s\", index, receiver)\n        raise exceptions.NoSuchDevice(number=index, receiver=receiver, error=\"Unknown 27Mhz device number\")\n    return kind\n\n\nreceiver_class_mapping = {\n    \"bolt\": BoltReceiver,\n    \"unifying\": UnifyingReceiver,\n    \"lightspeed\": LightSpeedReceiver,\n    \"nano\": NanoReceiver,\n    \"27Mhz\": Ex100Receiver,\n}\n\n\ndef create_receiver(low_level: LowLevelInterface, device_info, setting_callback=None) -> Optional[Receiver]:\n    \"\"\"Opens a Logitech Receiver found attached to the machine, by Linux device path.\"\"\"\n\n    try:\n        handle = low_level.open_path(device_info.path)\n        if handle:\n            usb_id = device_info.product_id\n            if isinstance(usb_id, str):\n                usb_id = int(usb_id, 16)\n            try:\n                product_info = low_level.product_information(usb_id)\n            except ValueError:\n                product_info = {}\n            kind = product_info.get(\"receiver_kind\", \"unknown\")\n            rclass = receiver_class_mapping.get(kind, Receiver)\n            return rclass(\n                low_level,\n                kind,\n                product_info,\n                handle,\n                device_info.path,\n                device_info.product_id,\n                setting_callback,\n            )\n    except OSError as e:\n        logger.exception(\"open %s\", device_info)\n        if e.errno == errno.EACCES:\n            raise e\n    except Exception:\n        logger.exception(\"open %s\", device_info)\n"
  },
  {
    "path": "lib/logitech_receiver/settings.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nfrom __future__ import annotations\n\nimport logging\nimport struct\nimport time\n\nfrom enum import IntEnum\nfrom typing import Any\n\nfrom solaar.i18n import _\n\nfrom . import common\nfrom . import hidpp20_constants\nfrom . import settings_validator\nfrom .common import NamedInt\n\nlogger = logging.getLogger(__name__)\n\nSENSITIVITY_IGNORE = \"ignore\"\n\n\nclass Kind(IntEnum):\n    NONE = 0\n    TOGGLE = 0x01\n    CHOICE = 0x02\n    RANGE = 0x04\n    MAP_CHOICE = 0x0A\n    MULTIPLE_TOGGLE = 0x10\n    PACKED_RANGE = 0x20\n    MULTIPLE_RANGE = 0x40\n    HETERO = 0x80\n    MAP_RANGE = 0x102\n    COLOR = 0x200\n\n\nclass Setting:\n    \"\"\"A setting descriptor. Needs to be instantiated for each specific device.\"\"\"\n\n    name = label = description = \"\"\n    feature = register = kind = None\n    min_version = 0\n    persist = True\n    rw_options = {}\n    validator_class = None\n    validator_options = {}\n    display = True  # display setting in UI\n\n    def __init__(self, device, rw, validator):\n        self._device = device\n        self._rw = rw\n        self._validator = validator\n        self.kind = getattr(self._validator, \"kind\", None)\n        self._value = None\n\n    @classmethod\n    def build(cls, device):\n        assert cls.feature or cls.register, \"Settings require either a feature or a register\"\n        rw_class = cls.rw_class if hasattr(cls, \"rw_class\") else FeatureRW if cls.feature else RegisterRW\n        rw = rw_class(cls.feature if cls.feature else cls.register, **cls.rw_options)\n        p = device.protocol\n        if p == 1.0:  # HID++ 1.0 devices do not support features\n            assert rw.kind == RegisterRW.kind\n        elif p >= 2.0:  # HID++ 2.0 devices do not support registers\n            assert rw.kind == FeatureRW.kind\n        validator_class = cls.validator_class\n        validator = validator_class.build(cls, device, **cls.validator_options)\n        if validator:\n            assert cls.kind is None or cls.kind & validator.kind != 0\n            return cls(device, rw, validator)\n\n    def val_to_string(self, value):\n        return self._validator.to_string(value)\n\n    @property\n    def choices(self):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n\n        return self._validator.choices if self._validator and self._validator.kind & Kind.CHOICE else None\n\n    @property\n    def range(self):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n\n        if self._validator.kind == Kind.RANGE:\n            return self._validator.min_value, self._validator.max_value\n\n    def _pre_read(self, cached, key=None):\n        if self.persist and self._value is None and getattr(self._device, \"persister\", None):\n            # We haven't read a value from the device yet,\n            # maybe we have something in the configuration.\n            self._value = self._device.persister.get(self.name)\n        if cached and self._value is not None:\n            if getattr(self._device, \"persister\", None) and self.name not in self._device.persister:\n                # If this is a new device (or a new setting for an old device),\n                # make sure to save its current value for the next time.\n                self._device.persister[self.name] = self._value if self.persist else None\n\n    def read(self, cached=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n\n        self._pre_read(cached)\n        if cached and self._value is not None:\n            if logger.isEnabledFor(logging.DEBUG):\n                logger.debug(\"%s: cached value %r on %s\", self.name, self._value, self._device)\n            return self._value\n\n        if self._device.online:\n            reply = self._rw.read(self._device)\n            if reply:\n                self._value = self._validator.validate_read(reply)\n            if self._value is not None and self._device.persister and self.name not in self._device.persister:\n                # Don't update the persister if it already has a value,\n                # otherwise the first read might overwrite the value we wanted.\n                self._device.persister[self.name] = self._value if self.persist else None\n            if logger.isEnabledFor(logging.DEBUG):\n                logger.debug(\"%s: read value %r on %s\", self.name, self._value, self._device)\n            return self._value\n\n    def _pre_write(self, save=True):\n        # Remember the value we're trying to set, even if the write fails.\n        # This way even if the device is offline or some other error occurs,\n        # the last value we've tried to write is remembered in the configuration.\n        if self._device.persister and save:\n            self._device.persister[self.name] = self._value if self.persist else None\n\n    def update(self, value, save=True):\n        self._value = value\n        self._pre_write(save)\n\n    def write(self, value, save=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        assert value is not None\n\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: write %r to %s\", self.name, value, self._device)\n\n        if self._device.online:\n            if self._value != value:\n                self.update(value, save)\n\n            current_value = None\n            if self._validator.needs_current_value:\n                # the _validator needs the current value, possibly to merge flag values\n                current_value = self._rw.read(self._device)\n                if logger.isEnabledFor(logging.DEBUG):\n                    logger.debug(\"%s: current value %r on %s\", self.name, current_value, self._device)\n\n            data_bytes = self._validator.prepare_write(value, current_value)\n            if data_bytes is not None:\n                if logger.isEnabledFor(logging.DEBUG):\n                    logger.debug(\"%s: prepare write(%s) => %r\", self.name, value, data_bytes)\n\n                reply = self._rw.write(self._device, data_bytes)\n                if not reply:\n                    # tell whomever is calling that the write failed\n                    return None\n\n            return value\n\n    def acceptable(self, args, current):\n        return self._validator.acceptable(args, current) if self._validator else None\n\n    def compare(self, args, current):\n        return self._validator.compare(args, current) if self._validator else None\n\n    def apply(self):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: apply (%s)\", self.name, self._device)\n        try:\n            value = self.read(self.persist)  # Don't use persisted value if setting doesn't persist\n            if self.persist and value is not None:  # If setting doesn't persist no need to write value just read\n                self.write(value, save=False)\n        except Exception as e:\n            if logger.isEnabledFor(logging.WARNING):\n                logger.warning(\"%s: error applying %s so ignore it (%s): %s\", self.name, self._value, self._device, repr(e))\n\n    def __str__(self):\n        if hasattr(self, \"_value\"):\n            assert hasattr(self, \"_device\")\n            return \"<Setting([%s:%s] %s:%s=%s)>\" % (\n                self._rw.kind,\n                self._validator.kind if self._validator else None,\n                self._device.codename,\n                self.name,\n                self._value,\n            )\n        return f\"<Setting([{self._rw.kind}:{self._validator.kind if self._validator else None}] {self.name})>\"\n\n    __repr__ = __str__\n\n\nclass Settings(Setting):\n    \"\"\"A setting descriptor for multiple choices, being a map from keys to values.\n    Needs to be instantiated for each specific device.\"\"\"\n\n    def read(self, cached=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings read %r from %s\", self.name, self._value, self._device)\n\n        self._pre_read(cached)\n\n        if cached and self._value is not None:\n            return self._value\n\n        if self._device.online:\n            reply_map = {}\n            for key in self._validator.choices:\n                reply = self._rw.read(self._device, key)\n                if reply:\n                    reply_map[int(key)] = self._validator.validate_read(reply, key)\n            self._value = reply_map\n            if getattr(self._device, \"persister\", None) and self.name not in self._device.persister:\n                # Don't update the persister if it already has a value,\n                # otherwise the first read might overwrite the value we wanted.\n                self._device.persister[self.name] = self._value if self.persist else None\n            return self._value\n\n    def read_key(self, key, cached=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        assert key is not None\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings read %r key %r from %s\", self.name, self._value, key, self._device)\n\n        self._pre_read(cached)\n        if cached and self._value is not None:\n            return self._value[int(key)]\n\n        if self._device.online:\n            reply = self._rw.read(self._device, key)\n            if reply:\n                self._value[int(key)] = self._validator.validate_read(reply, key)\n            if getattr(self._device, \"persister\", None) and self.name not in self._device.persister:\n                self._device.persister[self.name] = self._value if self.persist else None\n            return self._value[int(key)]\n\n    def write(self, map, save=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        assert map is not None\n\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings write %r to %s\", self.name, map, self._device)\n\n        if self._device.online:\n            self.update(map, save)\n            for key, value in map.items():\n                data_bytes = self._validator.prepare_write(int(key), value)\n                if data_bytes is not None:\n                    if logger.isEnabledFor(logging.DEBUG):\n                        logger.debug(\"%s: settings prepare map write(%s,%s) => %r\", self.name, key, value, data_bytes)\n                    reply = self._rw.write(self._device, int(key), data_bytes)\n                    if not reply:\n                        return None\n            return map\n\n    def update_key_value(self, key, value, save=True):\n        self._value[int(key)] = value\n        self._pre_write(save)\n\n    def write_key_value(self, key, value, save=True) -> Any | None:\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        assert key is not None\n        assert value is not None\n\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings write key %r value %r to %s\", self.name, key, value, self._device)\n\n        if self._device.online:\n            if not self._value:\n                self.read()\n            try:\n                data_bytes = self._validator.prepare_write(int(key), value)\n                # always need to write to configuration because dictionary is shared and could have changed\n                self.update_key_value(key, value, save)\n            except ValueError:\n                data_bytes = value = None\n            if data_bytes is not None:\n                if logger.isEnabledFor(logging.DEBUG):\n                    logger.debug(\"%s: settings prepare key value write(%s,%s) => %r\", self.name, key, value, data_bytes)\n                reply = self._rw.write(self._device, int(key), data_bytes)\n                if not reply:\n                    return None\n            return value\n\n\nclass LongSettings(Setting):\n    \"\"\"A setting descriptor for multiple choices, being a map from keys to values.\n    Allows multiple write requests, if the options don't fit in 16 bytes.\n    The validator must return a list.\n    Needs to be instantiated for each specific device.\"\"\"\n\n    def read(self, cached=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings read %r from %s\", self.name, self._value, self._device)\n\n        self._pre_read(cached)\n\n        if cached and self._value is not None:\n            return self._value\n\n        if self._device.online:\n            reply_map = {}\n            # Reading one item at a time. This can probably be optimised\n            for item in self._validator.items:\n                r = self._validator.prepare_read_item(item)\n                reply = self._rw.read(self._device, r)\n                if reply:\n                    reply_map[int(item)] = self._validator.validate_read_item(reply, item)\n            self._value = reply_map\n            if getattr(self._device, \"persister\", None) and self.name not in self._device.persister:\n                # Don't update the persister if it already has a value,\n                # otherwise the first read might overwrite the value we wanted.\n                self._device.persister[self.name] = self._value if self.persist else None\n            return self._value\n\n    def read_item(self, item, cached=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        assert item is not None\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings read %r item %r from %s\", self.name, self._value, item, self._device)\n\n        self._pre_read(cached)\n        if cached and self._value is not None:\n            return self._value[int(item)]\n\n        if self._device.online:\n            r = self._validator.prepare_read_item(item)\n            reply = self._rw.read(self._device, r)\n            if reply:\n                self._value[int(item)] = self._validator.validate_read_item(reply, item)\n            if getattr(self._device, \"persister\", None) and self.name not in self._device.persister:\n                self._device.persister[self.name] = self._value if self.persist else None\n            return self._value[int(item)]\n\n    def write(self, map, save=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        assert map is not None\n\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: long settings write %r to %s\", self.name, map, self._device)\n        if self._device.online:\n            self.update(map, save)\n            for item, value in map.items():\n                data_bytes_list = self._validator.prepare_write(self._value)\n                if data_bytes_list is not None:\n                    for data_bytes in data_bytes_list:\n                        if data_bytes is not None:\n                            if logger.isEnabledFor(logging.DEBUG):\n                                logger.debug(\"%s: settings prepare map write(%s,%s) => %r\", self.name, item, value, data_bytes)\n                            reply = self._rw.write(self._device, data_bytes)\n                            if not reply:\n                                return None\n            return map\n\n    def update_key_value(self, key, value, save=True):\n        self._value[int(key)] = value\n        self._pre_write(save)\n\n    def write_key_value(self, item, value, save=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        assert item is not None\n        assert value is not None\n\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: long settings write item %r value %r to %s\", self.name, item, value, self._device)\n\n        if self._device.online:\n            if not self._value:\n                self.read()\n            data_bytes = self._validator.prepare_write_item(item, value)\n            self.update_key_value(item, value, save)\n            if data_bytes is not None:\n                if logger.isEnabledFor(logging.DEBUG):\n                    logger.debug(\"%s: settings prepare item value write(%s,%s) => %r\", self.name, item, value, data_bytes)\n                reply = self._rw.write(self._device, data_bytes)\n                if not reply:\n                    return None\n            return value\n\n\nclass BitFieldSetting(Setting):\n    \"\"\"A setting descriptor for a set of choices represented by one bit each, being a map from options to booleans.\n    Needs to be instantiated for each specific device.\"\"\"\n\n    def read(self, cached=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings read %r from %s\", self.name, self._value, self._device)\n\n        self._pre_read(cached)\n\n        if cached and self._value is not None:\n            return self._value\n\n        if self._device.online:\n            reply_map = {}\n            reply = self._do_read()\n            if reply:\n                reply_map = self._validator.validate_read(reply)\n            self._value = reply_map\n            if getattr(self._device, \"persister\", None) and self.name not in self._device.persister:\n                # Don't update the persister if it already has a value,\n                # otherwise the first read might overwrite the value we wanted.\n                self._device.persister[self.name] = self._value if self.persist else None\n            return self._value\n\n    def _do_read(self):\n        return self._rw.read(self._device)\n\n    def read_key(self, key, cached=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        assert key is not None\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings read %r key %r from %s\", self.name, self._value, key, self._device)\n\n        self._pre_read(cached)\n\n        if cached and self._value is not None:\n            return self._value[int(key)]\n\n        if self._device.online:\n            reply = self._do_read_key(key)\n            if reply:\n                self._value = self._validator.validate_read(reply)\n            if getattr(self._device, \"persister\", None) and self.name not in self._device.persister:\n                self._device.persister[self.name] = self._value if self.persist else None\n            return self._value[int(key)]\n\n    def _do_read_key(self, key):\n        return self._rw.read(self._device, key)\n\n    def write(self, map, save=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        assert map is not None\n\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: bit field settings write %r to %s\", self.name, map, self._device)\n        if self._device.online:\n            self.update(map, save)\n            data_bytes = self._validator.prepare_write(self._value)\n            if data_bytes is not None:\n                if logger.isEnabledFor(logging.DEBUG):\n                    logger.debug(\"%s: settings prepare map write(%s) => %r\", self.name, self._value, data_bytes)\n                # if prepare_write returns a list, write one item at a time\n                seq = data_bytes if isinstance(data_bytes, list) else [data_bytes]\n                for b in seq:\n                    reply = self._rw.write(self._device, b)\n                    if not reply:\n                        return None\n            return map\n\n    def update_key_value(self, key, value, save=True):\n        self._value[int(key)] = value\n        self._pre_write(save)\n\n    def write_key_value(self, key, value, save=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        assert key is not None\n        assert value is not None\n\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: bit field settings write key %r value %r to %s\", self.name, key, value, self._device)\n\n        if self._device.online:\n            if not self._value:\n                self.read()\n            value = bool(value)\n            self.update_key_value(key, value, save)\n\n            data_bytes = self._validator.prepare_write(self._value)\n            if data_bytes is not None:\n                if logger.isEnabledFor(logging.DEBUG):\n                    logger.debug(\"%s: settings prepare key value write(%s,%s) => %r\", self.name, key, str(value), data_bytes)\n                # if prepare_write returns a list, write one item at a time\n                seq = data_bytes if isinstance(data_bytes, list) else [data_bytes]\n                for b in seq:\n                    reply = self._rw.write(self._device, b)\n                    if not reply:\n                        return None\n\n            return value\n\n\nclass BitFieldWithOffsetAndMaskSetting(BitFieldSetting):\n    \"\"\"A setting descriptor for a set of choices represented by one bit each,\n    each one having an offset, being a map from options to booleans.\n    Needs to be instantiated for each specific device.\"\"\"\n\n    def _do_read(self):\n        return {r: self._rw.read(self._device, r) for r in self._validator.prepare_read()}\n\n    def _do_read_key(self, key):\n        r = self._validator.prepare_read_key(key)\n        return {r: self._rw.read(self._device, r)}\n\n\nclass RangeFieldSetting(Setting):\n    \"\"\"A setting descriptor for a set of choices represented by one field each, with map from option names to range(0,n).\n    Needs to be instantiated for each specific device.\"\"\"\n\n    def read(self, cached=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings read %r from %s\", self.name, self._value, self._device)\n        self._pre_read(cached)\n        if cached and self._value is not None:\n            return self._value\n        if self._device.online:\n            reply_map = {}\n            reply = self._do_read()\n            if reply:\n                reply_map = self._validator.validate_read(reply)\n            self._value = reply_map\n            if getattr(self._device, \"persister\", None) and self.name not in self._device.persister:\n                # Don't update the persister if it already has a value,\n                # otherwise the first read might overwrite the value we wanted.\n                self._device.persister[self.name] = self._value if self.persist else None\n            return self._value\n\n    def _do_read(self):\n        return self._rw.read(self._device)\n\n    def read_key(self, key, cached=True):\n        return self.read(cached)[int(key)]\n\n    def write(self, map, save=True):\n        assert hasattr(self, \"_value\")\n        assert hasattr(self, \"_device\")\n        assert map is not None\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: range field setting write %r to %s\", self.name, map, self._device)\n        if self._device.online:\n            self.update(map, save)\n            data_bytes = self._validator.prepare_write(self._value)\n            if data_bytes is not None:\n                if logger.isEnabledFor(logging.DEBUG):\n                    logger.debug(\"%s: range field setting prepare map write(%s) => %r\", self.name, self._value, data_bytes)\n                reply = self._rw.write(self._device, data_bytes)\n                if not reply:\n                    return None\n            elif logger.isEnabledFor(logging.WARNING):\n                logger.warning(\"%s: range field setting no data to write\", self.name)\n            return map\n\n    def write_key_value(self, key, value, save=True):\n        assert key is not None\n        assert value is not None\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: range field setting write key %r value %r to %s\", self.name, key, value, self._device)\n        if self._device.online:\n            if not self._value:\n                self.read()\n            map = self._value\n            map[int(key)] = value\n            self.write(map, save)\n            return value\n\n\n#\n# read/write low-level operators\n#\n\n\nclass RegisterRW:\n    __slots__ = (\"register\",)\n\n    kind = NamedInt(0x01, _(\"register\"))\n\n    def __init__(self, register: int):\n        assert isinstance(register, int)\n        self.register = register\n\n    def read(self, device):\n        return device.read_register(self.register)\n\n    def write(self, device, data_bytes):\n        return device.write_register(self.register, data_bytes)\n\n\nclass FeatureRW:\n    kind = NamedInt(0x02, _(\"feature\"))\n    default_read_fnid = 0x00\n    default_write_fnid = 0x10\n\n    def __init__(\n        self,\n        feature: hidpp20_constants.SupportedFeature,\n        read_fnid=0x00,\n        write_fnid=0x10,\n        prefix=b\"\",\n        suffix=b\"\",\n        read_prefix=b\"\",\n        no_reply=False,\n    ):\n        assert isinstance(feature, hidpp20_constants.SupportedFeature)\n        self.feature = feature\n        self.read_fnid = read_fnid\n        self.write_fnid = write_fnid\n        self.no_reply = no_reply\n        self.prefix = prefix\n        self.suffix = suffix\n        self.read_prefix = read_prefix\n\n    def read(self, device, data_bytes=b\"\"):\n        assert self.feature is not None\n        if self.read_fnid is not None:\n            return device.feature_request(self.feature, self.read_fnid, self.prefix, self.read_prefix, data_bytes)\n        else:\n            return b\"\"\n\n    def write(self, device, data_bytes):\n        assert self.feature is not None\n        write_bytes = self.prefix + (data_bytes.to_bytes(1) if isinstance(data_bytes, int) else data_bytes) + self.suffix\n        reply = device.feature_request(self.feature, self.write_fnid, write_bytes, no_reply=self.no_reply)\n        return reply if not self.no_reply else True\n\n\nclass FeatureRWMap(FeatureRW):\n    kind = NamedInt(0x02, _(\"feature\"))\n    default_read_fnid = 0x00\n    default_write_fnid = 0x10\n    default_key_byte_count = 1\n\n    def __init__(\n        self,\n        feature: hidpp20_constants.SupportedFeature,\n        read_fnid=default_read_fnid,\n        write_fnid=default_write_fnid,\n        key_byte_count=default_key_byte_count,\n        no_reply=False,\n    ):\n        assert isinstance(feature, hidpp20_constants.SupportedFeature)\n        self.feature = feature\n        self.read_fnid = read_fnid\n        self.write_fnid = write_fnid\n        self.key_byte_count = key_byte_count\n        self.no_reply = no_reply\n\n    def read(self, device, key):\n        assert self.feature is not None\n        key_bytes = common.int2bytes(key, self.key_byte_count)\n        return device.feature_request(self.feature, self.read_fnid, key_bytes)\n\n    def write(self, device, key, data_bytes):\n        assert self.feature is not None\n        key_bytes = common.int2bytes(key, self.key_byte_count)\n        reply = device.feature_request(self.feature, self.write_fnid, key_bytes, data_bytes, no_reply=self.no_reply)\n        return reply if not self.no_reply else True\n\n\nclass ActionSettingRW:\n    \"\"\"Special RW class for settings that turn on and off special processing when a key or button is depressed\"\"\"\n\n    def __init__(self, feature, name=\"\", divert_setting_name=\"divert-keys\"):\n        self.feature = feature  # not used?\n        self.name = name\n        self.divert_setting_name = divert_setting_name\n        self.kind = FeatureRW.kind  # pretend to be FeatureRW as required for HID++ 2.0 devices\n        self.device = None\n        self.key = None\n        self.active = False\n        self.pressed = False\n\n    def activate_action(self):  # action to take when setting is activated (write non-false)\n        pass\n\n    def deactivate_action(self):  # action to take when setting is deactivated (write false)\n        pass\n\n    def press_action(self):  # action to take when key is pressed\n        pass\n\n    def release_action(self):  # action to take when key is released\n        pass\n\n    def move_action(self, dx, dy):  # action to take when mouse is moved while key is down\n        pass\n\n    def key_action(self, key):  # acction to take when some other diverted key is pressed\n        pass\n\n    def read(self, device):  # need to return bytes, as if read from device\n        return common.int2bytes(self.key.key, 2) if self.active and self.key else b\"\\x00\\x00\"\n\n    def write(self, device, data_bytes):\n        def handler(device, n):  # Called on notification events from the device\n            if (\n                n.sub_id < 0x40\n                and device.features.get_feature(n.sub_id) == hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4\n            ):\n                if n.address == 0x00:\n                    cids = struct.unpack(\"!HHHH\", n.data[:8])\n                    if not self.pressed and int(self.key.key) in cids:  # trigger key pressed\n                        self.pressed = True\n                        self.press_action()\n                    elif self.pressed:\n                        if int(self.key.key) not in cids:  # trigger key released\n                            self.pressed = False\n                            self.release_action()\n                        else:\n                            for key in cids:\n                                if key and not key == self.key.key:  # some other diverted key pressed\n                                    self.key_action(key)\n                elif n.address == 0x10:\n                    if self.pressed:\n                        dx, dy = struct.unpack(\"!hh\", n.data[:4])\n                        self.move_action(dx, dy)\n\n        divertSetting = next(filter(lambda s: s.name == self.divert_setting_name, device.settings), None)\n        if divertSetting is None:\n            logger.warning(\"setting %s not found on %s\", self.divert_setting_name, device.name)\n            return None\n        self.device = device\n        key = common.bytes2int(data_bytes)\n        if key:  # Enable\n            self.key = next((k for k in device.keys if k.key == key), None)\n            if self.key:\n                self.active = True\n                if divertSetting:\n                    divertSetting.write_key_value(int(self.key.key), 1)\n                    if self.device.setting_callback:\n                        self.device.setting_callback(device, type(divertSetting), [self.key.key, 1])\n                device.add_notification_handler(self.name, handler)\n                self.activate_action()\n            else:\n                logger.error(\"cannot enable %s on %s for key %s\", self.name, device, key)\n        else:  # Disable\n            if self.active:\n                self.active = False\n                if divertSetting:\n                    divertSetting.write_key_value(int(self.key.key), 0)\n                    if self.device.setting_callback:\n                        self.device.setting_callback(device, type(divertSetting), [self.key.key, 0])\n                try:\n                    device.remove_notification_handler(self.name)\n                except Exception:\n                    if logger.isEnabledFor(logging.WARNING):\n                        logger.warning(\"cannot disable %s on %s\", self.name, device)\n                self.deactivate_action()\n        return data_bytes\n\n\nclass RawXYProcessing:\n    \"\"\"Special class for processing RawXY action messages initiated by pressing a key with rawXY diversion capability\"\"\"\n\n    def __init__(self, device, name=\"\"):\n        self.device = device\n        self.name = name\n        self.keys = []  # the keys that can initiate processing\n        self.initiating_key = None  # the key that did initiate processing\n        self.active = False\n        self.feature_offset = device.features[hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4]\n        assert self.feature_offset is not False\n\n    def handler(self, device, n):  # Called on notification events from the device\n        if n.sub_id < 0x40 and device.features.get_feature(n.sub_id) == hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4:\n            if n.address == 0x00:\n                cids = struct.unpack(\"!HHHH\", n.data[:8])\n                ## generalize to list of keys\n                if not self.initiating_key:  # no initiating key pressed\n                    for k in self.keys:\n                        if int(k.key) in cids:  # initiating key that was pressed\n                            self.initiating_key = k\n                    if self.initiating_key:\n                        self.press_action(self.initiating_key)\n                else:\n                    if int(self.initiating_key.key) not in cids:  # initiating key released\n                        self.initiating_key = None\n                        self.release_action()\n                    else:\n                        for key in cids:\n                            if key and key != self.initiating_key.key:\n                                self.key_action(key)\n            elif n.address == 0x10:\n                if self.initiating_key:\n                    dx, dy = struct.unpack(\"!hh\", n.data[:4])\n                    self.move_action(dx, dy)\n\n    def start(self, key):\n        device_key = next((k for k in self.device.keys if k.key == key), None)\n        if device_key:\n            self.keys.append(device_key)\n            if not self.active:\n                self.active = True\n                self.activate_action()\n                self.device.add_notification_handler(self.name, self.handler)\n            device_key.set_rawXY_reporting(True)\n\n    def stop(self, key):  # only stop if this is the active key\n        if self.active:\n            processing_key = next((k for k in self.keys if k.key == key), None)\n            if processing_key:\n                processing_key.set_rawXY_reporting(False)\n                self.keys.remove(processing_key)\n            if not self.keys:\n                try:\n                    self.device.remove_notification_handler(self.name)\n                except Exception:\n                    if logger.isEnabledFor(logging.WARNING):\n                        logger.warning(\"cannot disable %s on %s\", self.name, self.device)\n                self.deactivate_action()\n                self.active = False\n\n    def activate_action(self):  # action to take when processing is activated\n        pass\n\n    def deactivate_action(self):  # action to take when processing is deactivated\n        pass\n\n    def press_action(self, key):  # action to take when an initiating key is pressed\n        pass\n\n    def release_action(self):  # action to take when key is released\n        pass\n\n    def move_action(self, dx, dy):  # action to take when mouse is moved while key is down\n        pass\n\n    def key_action(self, key):  # acction to take when some other diverted key is pressed\n        pass\n\n\ndef apply_all_settings(device):\n    if device.features and hidpp20_constants.SupportedFeature.HIRES_WHEEL in device.features:\n        time.sleep(0.2)  # delay to try to get out of race condition with Linux HID++ driver\n    persister = getattr(device, \"persister\", None)\n    sensitives = persister.get(\"_sensitive\", {}) if persister else {}\n    for s in device.settings:\n        ignore = sensitives.get(s.name, False)\n        if ignore != SENSITIVITY_IGNORE:\n            s.apply()\n\n\nSetting.validator_class = settings_validator.BooleanValidator\n"
  },
  {
    "path": "lib/logitech_receiver/settings_new.py",
    "content": "## Copyright (C) 2025  Solaar contributors\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n## A new way of supporting settings, using a feature-specifi device class to store, read, and write relevant information\n## The setting uses the device class to interact with the device feature.\n## The setting uses a persist class to keep track of the setting.\n\n## Interface:\n\nimport logging\n\nfrom .settings import Kind\n\nlogger = logging.getLogger(__name__)\n\n\nclass Setting:\n    name = None  # Solaar internal name for the setting\n    label = None  # Solaar user name for the setting (translatable)\n    description = None  # Solaar extra desciption for the setting (translatable)\n    feature = None  # Logitech feature that the setting uses\n    min_version = 0  # Minimum version of the feature needed\n    setup = None  # method name on Device class to get the device object\n    get = None  # method name on the device object to get the setting value\n    set = None  # method name on the device object to set the setting value\n    acceptable = None  # method name on the device object to check for acceptable values\n    choices_universe = None  # All possible acceptable keys, for settings with keys\n    kind = Kind.NONE  # What GUI interface to use\n    persist = True  # Whether to remember the setting\n    display = True  # display setting in UI\n    _device = None  # The device that this setting is for\n    _device_object = None  # The object that interacts with the feature for the device\n    _value = None  # Stored value as maintained by Solaar, used for persistence\n\n    def __init__(self, device, device_object):\n        self._device = device\n        self._device_object = device_object\n\n    @classmethod\n    def build(cls, device):\n        cls.check_properties(cls)\n        device_object = getattr(device, cls.setup)()\n        if device_object:\n            setting = cls(device, device_object)\n            return setting\n\n    @classmethod\n    def check_properties(cl, cls):\n        assert cls.name and cls.label and cls.description, \"New settings require a name, label, and description\"\n        assert cls.feature, \"New settings require a feature\"\n        assert cls.setup, \"New settings require a setup device method\"\n        assert cls.get and cls.set and cls.acceptable, \"New settings require get, set, and acceptable methods\"\n\n    def setup_from_class(self, clss):\n        \"\"\"Copy settings methods for a new setting from a settting class\"\"\"\n        self.name = clss.name\n        self.label = clss.label\n        self.description = clss.description\n        self.feature = clss.feature\n        self.min_version = clss.min_version\n        self.setup = clss.setup\n        self.get = clss.get\n        self.set = clss.set\n        self.acceptable = clss.acceptable\n        self.choices_universe = clss.choices_universe\n        self.kind = clss.kind\n        self.persist = clss.persist\n\n    def _pre_read(self, cached):\n        \"\"\"Get information from and save information to the persister\"\"\"\n        # Get the persister map if available and not done already\n        if self.persist and self._value is None and getattr(self._device, \"persister\", None):\n            self._value = self._device.persister.get(self.name)\n        # If this is new save its current value for the next time\n        if cached and self._value is not None:\n            if getattr(self._device, \"persister\", None) and self.name not in self._device.persister:\n                self._device.persister[self.name] = self._value if self.persist else None\n\n    def read(self, cached=True):\n        \"\"\"Get all the data for the setting.  If cached is True the data in the _value can be used.\"\"\"\n        self._pre_read(cached)\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: setting read %r from %s\", self.name, self._value, self._device)\n        if cached and self._value is not None:\n            return self._value\n        if cached:\n            self._value = getattr(self._device_object, self.get)()\n            return self._value\n        if self._device.online:\n            self._value = getattr(self._device_object.query(), self.get)()\n            return self._value\n\n    def write(self, value, save=True):\n        \"\"\"Write the value to the device.  If saved is True also save in the persister\"\"\"\n        pass  ## fill out\n\n    def apply(self):\n        \"\"\"Write saved data to the device, using persisted data if available\"\"\"\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: apply (%s)\", self.name, self._device)\n        value = None\n        try:\n            value = self.read(self.persist)  # Don't use persisted value if setting doesn't persist\n            if self.persist and value is not None:  # If setting doesn't persist no need to write value just read\n                self.write(value, save=False)\n        except Exception as e:\n            if logger.isEnabledFor(logging.WARNING):\n                logger.warning(\"%s: error applying %s so ignore it (%s): %s\", self.name, value, self._device, repr(e))\n\n    @property\n    def range(self):\n        if self.kind == Kind.RANGE:\n            return self.min_value, self.max_value\n\n    def val_to_string(self, value):\n        return str(value)\n\n\n## key mapping from symbols to values????\n\n\nclass Settings(Setting):\n    \"\"\"A setting descriptor for multiple keys.\n    Supported by a class that provides the interface to the device, see ForceSensingButtonArray in hidpp20.py\n    Picks out a field from the mapped device feature objects.\"\"\"\n\n    # setup creates a dictionary with entries for all the keys\n    # _value is a map from keys to values\n    # get, set, and acceptable are methods of dict value objects, not of the device object itself  #### FIX THIS! MAYBE??\n\n    def __init__(self, device, device_object):\n        super().__init__(device, device_object)\n        self._value = {}\n\n    def read(self, cached=True):\n        self._pre_read(cached)\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings read %r from %s\", self.name, self._value, self._device)\n        for key in self._device_object:\n            self.read_key(key, cached)\n        return self._value\n\n    def read_key(self, key, cached=True):\n        \"\"\"Get the data for the key.  If cached is True the data in the device_object can be used.\"\"\"\n        self._pre_read(cached)\n        if key not in self._device_object:\n            logger.error(\"%s: settings illegal read key %r for %s\", self.name, key, self._device)\n            return None\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings key %r read %r from %s\", self.name, key, self._value, self._device)\n        if cached and key in self._value and self._value[key] is not None:\n            return self._value[key]\n        if cached:\n            data = self._device_object[key]\n            self._value[key] = getattr(data, self.get)()\n            return self._value[key]\n        if self._device.online:\n            data = self._device_object.query_key(key)\n            self._value[key] = getattr(data, self.get)()\n            return self._value[key]\n\n    def write(self, value, save=True):\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings read %r from %s\", self.name, self._value, self._device)\n        if isinstance(value, dict):\n            for key, val in value.items():\n                self.write_key_value(key, val, save)\n        else:  # to mimic interface for non-dict setting\n            key = next(iter(self._device_object))\n            self.write_key_value(key, value, save)\n        return value\n\n    def write_key_value(self, key, value, save=True):\n        \"\"\"Write the data for the key.  If saved is True also save in the persister\"\"\"\n        if key not in self._device_object:\n            logger.error(\"%s: settings illegal write key %r for %s\", self.name, key, self._device)\n            return None\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"%s: settings write key %r value %r to %s\", self.name, key, value, self._device)\n        if self._device.online:\n            if self._device_object[key] is None:\n                self.read_key(key)\n            if self._device_object[key] is None:\n                logger.error(\"%s: settings illegal write key %r for %s\", self.name, key, self._device)\n                return None\n            if not getattr(self._device_object[key], self.acceptable)(value):\n                logger.error(\"%s: settings illegal write key %r value %r for %s\", self.name, key, value, self._device)\n                return None\n            self._value[key] = value\n            if self._device.persister and self.persist and save:\n                self._device.persister[self.name][key] = value\n            getattr(self._device_object[key], self.set)(value)\n            return value\n"
  },
  {
    "path": "lib/logitech_receiver/settings_templates.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nfrom __future__ import annotations\n\nimport enum\nimport logging\nimport socket\nimport struct\nimport traceback\n\nfrom time import time\nfrom typing import Callable\nfrom typing import Protocol\n\nfrom solaar.i18n import _\n\nfrom . import base\nfrom . import common\nfrom . import descriptors\nfrom . import desktop_notifications\nfrom . import diversion\nfrom . import exceptions\nfrom . import hidpp20\nfrom . import hidpp20_constants\nfrom . import settings\nfrom . import settings_new\nfrom . import settings_validator\nfrom . import special_keys\nfrom .hidpp10_constants import Registers\nfrom .hidpp20 import KeyFlag\nfrom .hidpp20 import MappingFlag\nfrom .hidpp20_constants import GestureId\nfrom .hidpp20_constants import ParamId\n\nlogger = logging.getLogger(__name__)\n\n_hidpp20 = hidpp20.Hidpp20()\n_F = hidpp20_constants.SupportedFeature\n\n\nclass State(enum.Enum):\n    IDLE = \"idle\"\n    PRESSED = \"pressed\"\n    MOVED = \"moved\"\n\n\n# Setting classes are used to control the settings that the Solaar GUI shows and manipulates.\n# Each setting class has to several class variables:\n# name, which is used as a key when storing information about the setting,\n#   setting classes can have the same name, as long as devices only have one setting with the same name;\n# label, which is shown in the Solaar main window;\n# description, which is shown when the mouse hovers over the setting in the main window;\n# either register or feature, the register or feature that the setting uses;\n# rw_class, the class of the reader/writer (if it is not the standard one),\n# rw_options, a dictionary of options for the reader/writer.\n# validator_class, the class of the validator (default settings.BooleanValidator)\n# validator_options, a dictionary of options for the validator\n# persist (inherited True), which is whether to store the value and apply it when setting up the device.\n#\n# The different setting classes imported from settings.py are for different numbers and kinds of arguments.\n# Setting is for settings with a single value (boolean, number in a range, and symbolic choice).\n# Settings is for settings that are maps from keys to values\n#    and permit reading or writing the entire map or just one key/value pair.\n# The BitFieldSetting class is for settings that have multiple boolean values packed into a bit field.\n# BitFieldWithOffsetAndMaskSetting is similar.\n# The RangeFieldSetting class is for settings that have multiple ranges packed into a byte string.\n# LongSettings is for settings that have an even more complex structure.\n#\n# When settings are created a reader/writer and a validator are created.\n\n# If the setting class has a value for rw_class then an instance of that class is created.\n# Otherwise if the setting has a register then an instance of RegisterRW is created.\n# and if the setting has a feature then an instance of FeatureRW is created.\n# The instance is created with the register or feature as the first argument and rw_options as keyword arguments.\n# RegisterRW doesn't use any options.\n# FeatureRW options include\n#   read_fnid - the feature function (times 16) to read the value (default 0x00),\n#   write_fnid - the feature function (times 16) to write the value (default 0x10),\n#   prefix - a prefix to add to the data being written and the read request (default b''), used for features\n#     that provide and set multiple settings (e.g., to read and write function key inversion for current host)\n#   no_reply - whether to wait for a reply (default false) (USE WITH EXTREME CAUTION).\n#\n# There are three simple validator classes - BooleanV, RangeValidator, and ChoicesValidator\n# BooleanV is for boolean values and is the default.  It takes\n#   true_value is the raw value for true (default 0x01), this can be an integer or a byte string,\n#   false_value is the raw value for false (default 0x00), this can be an integer or a byte string,\n#   mask is used to keep only some bits from a sequence of bits, this can be an integer or a byte string,\n#   read_skip_byte_count is the number of bytes to ignore at the beginning of the read value (default 0),\n#   write_prefix_bytes is a byte string to write before the value (default empty).\n\n# RangeValidator is for an integer in a range.  It takes\n#   byte_count is number of bytes that the value is stored in (defaults to size of max_value).\n#   read_skip_byte_count is as for BooleanV\n#   write_prefix_bytes is as for BooleanV\n# RangeValidator uses min_value and max_value from the setting class as minimum and maximum.\n\n# ChoicesValidator is for symbolic choices.  It takes one positional and three keyword arguments:\n#   choices is a list of named integers that are the valid choices,\n#   byte_count is the number of bytes for the integer (default size of largest choice integer),\n#   read_skip_byte_count is as for BooleanV,\n#   write_prefix_bytes is as for BooleanV.\n# Settings that use ChoicesValidator should have a choices_universe class variable of the potential choices,\n# or None for no limitation and optionally a choices_extra class variable with an extra choice.\n# The choices_extra is so that there is no need to specially extend a large existing NamedInts.\n# ChoicesMapValidator validator is for map settings that map onto symbolic choices.   It takes\n#   choices_map is a map from keys to possible values\n#   byte_count is as for ChoicesValidator,\n#   read_skip_byte_count is as for ChoicesValidator,\n#   write_prefix_bytes is as for ChoicesValidator,\n#   key_byte_count is the number of bytes for the key integer (default size of largest key),\n#   extra_default is an extra raw value that is used as a default value (default None).\n# Settings that use ChoicesValidator should have keys_universe and choices_universe class variable of\n# the potential keys and potential choices or None for no limitation.\n\n# BitFieldValidator validator is for bit field settings.  It takes one positional and one keyword argument\n#   the positional argument is the number of bits in the bit field\n#   byte_count is the size of the bit field (default size of the bit field)\n#\n# A few settings work very differently.  They divert a key, which is then used to start and stop some special action.\n# These settings have reader/writer classes that perform special processing instead of sending commands to the device.\n\n\nclass FnSwapVirtual(settings.Setting):  # virtual setting to hold fn swap strings\n    name = \"fn-swap\"\n    label = _(\"Swap Fx function\")\n    description = (\n        _(\n            \"When set, the F1..F12 keys will activate their special function,\\n\"\n            \"and you must hold the FN key to activate their standard function.\"\n        )\n        + \"\\n\\n\"\n        + _(\n            \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n            \"and you must hold the FN key to activate their special function.\"\n        )\n    )\n\n\nclass RegisterHandDetection(settings.Setting):\n    name = \"hand-detection\"\n    label = _(\"Hand Detection\")\n    description = _(\"Turn on illumination when the hands hover over the keyboard.\")\n    register = Registers.KEYBOARD_HAND_DETECTION\n    validator_options = {\"true_value\": b\"\\x00\\x00\\x00\", \"false_value\": b\"\\x00\\x00\\x30\", \"mask\": b\"\\x00\\x00\\xff\"}\n\n\nclass RegisterSmoothScroll(settings.Setting):\n    name = \"smooth-scroll\"\n    label = _(\"Scroll Wheel Smooth Scrolling\")\n    description = _(\"High-sensitivity mode for vertical scroll with the wheel.\")\n    register = Registers.MOUSE_BUTTON_FLAGS\n    validator_options = {\"true_value\": 0x40, \"mask\": 0x40}\n\n\nclass RegisterSideScroll(settings.Setting):\n    name = \"side-scroll\"\n    label = _(\"Side Scrolling\")\n    description = _(\n        \"When disabled, pushing the wheel sideways sends custom button events\\n\"\n        \"instead of the standard side-scrolling events.\"\n    )\n    register = Registers.MOUSE_BUTTON_FLAGS\n    validator_options = {\"true_value\": 0x02, \"mask\": 0x02}\n\n\n# different devices have different sets of permissible dpis, so this should be subclassed\nclass RegisterDpi(settings.Setting):\n    name = \"dpi-old\"\n    label = _(\"Sensitivity (DPI - older mice)\")\n    description = _(\"Mouse movement sensitivity\")\n    register = Registers.MOUSE_DPI\n    choices_universe = common.NamedInts.range(0x81, 0x8F, lambda x: str((x - 0x80) * 100))\n    validator_class = settings_validator.ChoicesValidator\n    validator_options = {\"choices\": choices_universe}\n\n\nclass RegisterFnSwap(FnSwapVirtual):\n    register = Registers.KEYBOARD_FN_SWAP\n    validator_options = {\"true_value\": b\"\\x00\\x01\", \"mask\": b\"\\x00\\x01\"}\n\n\nclass _PerformanceMXDpi(RegisterDpi):\n    choices_universe = common.NamedInts.range(0x81, 0x8F, lambda x: str((x - 0x80) * 100))\n    validator_options = {\"choices\": choices_universe}\n\n\n# set up register settings for devices - this is done here to break up an import loop\ndescriptors.get_wpid(\"0060\").settings = [RegisterFnSwap]\ndescriptors.get_wpid(\"2008\").settings = [RegisterFnSwap]\ndescriptors.get_wpid(\"2010\").settings = [RegisterFnSwap, RegisterHandDetection]\ndescriptors.get_wpid(\"2011\").settings = [RegisterFnSwap]\ndescriptors.get_usbid(0xC318).settings = [RegisterFnSwap]\ndescriptors.get_wpid(\"C714\").settings = [RegisterFnSwap]\ndescriptors.get_wpid(\"100B\").settings = [RegisterSmoothScroll, RegisterSideScroll]\ndescriptors.get_wpid(\"100F\").settings = [RegisterSmoothScroll, RegisterSideScroll]\ndescriptors.get_wpid(\"1013\").settings = [RegisterSmoothScroll, RegisterSideScroll]\ndescriptors.get_wpid(\"1014\").settings = [RegisterSmoothScroll, RegisterSideScroll]\ndescriptors.get_wpid(\"1017\").settings = [RegisterSmoothScroll, RegisterSideScroll]\ndescriptors.get_wpid(\"1023\").settings = [RegisterSmoothScroll, RegisterSideScroll]\n# somehow messed up ? descriptors.get_wpid(\"4004\").settings = [_PerformanceMXDpi, RegisterSmoothScroll, RegisterSideScroll]\ndescriptors.get_wpid(\"101A\").settings = [_PerformanceMXDpi, RegisterSmoothScroll, RegisterSideScroll]\ndescriptors.get_wpid(\"101B\").settings = [RegisterSmoothScroll, RegisterSideScroll]\ndescriptors.get_wpid(\"101D\").settings = [RegisterSmoothScroll, RegisterSideScroll]\ndescriptors.get_wpid(\"101F\").settings = [RegisterSideScroll]\ndescriptors.get_usbid(0xC06B).settings = [RegisterSmoothScroll, RegisterSideScroll]\ndescriptors.get_wpid(\"1025\").settings = [RegisterSideScroll]\ndescriptors.get_wpid(\"102A\").settings = [RegisterSmoothScroll, RegisterSideScroll]\ndescriptors.get_usbid(0xC048).settings = [_PerformanceMXDpi, RegisterSmoothScroll, RegisterSideScroll]\ndescriptors.get_usbid(0xC066).settings = [_PerformanceMXDpi, RegisterSmoothScroll, RegisterSideScroll]\n\n\n# ignore the capabilities part of the feature - all devices should be able to swap Fn state\n# can't just use the first byte = 0xFF (for current host) because of a bug in the firmware of the MX Keys S\nclass K375sFnSwap(FnSwapVirtual):\n    feature = _F.K375S_FN_INVERSION\n    validator_options = {\"true_value\": b\"\\x01\", \"false_value\": b\"\\x00\", \"read_skip_byte_count\": 1}\n\n    class rw_class(settings.FeatureRW):\n        def find_current_host(self, device):\n            if not self.prefix:\n                response = device.feature_request(_F.HOSTS_INFO, 0x00)\n                self.prefix = response[3:4] if response else b\"\\xff\"\n\n        def read(self, device, data_bytes=b\"\"):\n            self.find_current_host(device)\n            return super().read(device, data_bytes)\n\n        def write(self, device, data_bytes):\n            self.find_current_host(device)\n            return super().write(device, data_bytes)\n\n\nclass FnSwap(FnSwapVirtual):\n    feature = _F.FN_INVERSION\n\n\nclass NewFnSwap(FnSwapVirtual):\n    feature = _F.NEW_FN_INVERSION\n\n\nclass Backlight(settings.Setting):\n    name = \"backlight-qualitative\"\n    label = _(\"Backlight Timed\")\n    description = _(\"Set illumination time for keyboard.\")\n    feature = _F.BACKLIGHT\n    choices_universe = common.NamedInts(Off=0, Varying=2, VeryShort=5, Short=10, Medium=20, Long=60, VeryLong=180)\n    validator_class = settings_validator.ChoicesValidator\n    validator_options = {\"choices\": choices_universe}\n\n\n# MX Keys S requires some extra values, as in 11 02 0c1a 000dff000b000b003c00000000000000\n# on/off options (from current) effect (FF-no change) level (from current) durations[6] (from current)\nclass Backlight2(settings.Setting):\n    name = \"backlight\"\n    label = _(\"Backlight\")\n    description = _(\"Illumination level on keyboard.  Changes made are only applied in Manual mode.\")\n    feature = _F.BACKLIGHT2\n    choices_universe = common.NamedInts(Disabled=0xFF, Enabled=0x00, Automatic=0x01, Manual=0x02)\n    min_version = 0\n\n    class rw_class:\n        def __init__(self, feature):\n            self.feature = feature\n            self.kind = settings.FeatureRW.kind\n\n        def read(self, device):\n            backlight = device.backlight\n            if not backlight.enabled:\n                return b\"\\xff\"\n            else:\n                return common.int2bytes(backlight.mode, 1)\n\n        def write(self, device, data_bytes):\n            backlight = device.backlight\n            backlight.enabled = data_bytes[0] != 0xFF\n            if data_bytes[0] != 0xFF:\n                backlight.mode = data_bytes[0]\n            backlight.write()\n            return True\n\n    class validator_class(settings_validator.ChoicesValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            backlight = device.backlight\n            choices = common.NamedInts()\n            choices[0xFF] = _(\"Disabled\")\n            if backlight.auto_supported:\n                choices[0x1] = _(\"Automatic\")\n            if backlight.perm_supported:\n                choices[0x3] = _(\"Manual\")\n            if not (backlight.auto_supported or backlight.temp_supported or backlight.perm_supported):\n                choices[0x0] = _(\"Enabled\")\n            return cls(choices=choices, byte_count=1)\n\n\nclass Backlight2Level(settings.Setting):\n    name = \"backlight_level\"\n    label = _(\"Backlight Level\")\n    description = _(\"Illumination level on keyboard when in Manual mode.\")\n    feature = _F.BACKLIGHT2\n    min_version = 3\n\n    class rw_class:\n        def __init__(self, feature):\n            self.feature = feature\n            self.kind = settings.FeatureRW.kind\n\n        def read(self, device):\n            backlight = device.backlight\n            return common.int2bytes(backlight.level, 1)\n\n        def write(self, device, data_bytes):\n            if device.backlight.level != common.bytes2int(data_bytes):\n                device.backlight.level = common.bytes2int(data_bytes)\n                device.backlight.write()\n            return True\n\n    class validator_class(settings_validator.RangeValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            reply = device.feature_request(_F.BACKLIGHT2, 0x20)\n            assert reply, \"Oops, backlight range cannot be retrieved!\"\n            if reply[0] > 1:\n                return cls(min_value=0, max_value=reply[0] - 1, byte_count=1)\n\n\nclass Backlight2Duration(settings.Setting):\n    feature = _F.BACKLIGHT2\n    min_version = 3\n    validator_class = settings_validator.RangeValidator\n    min_value = 1\n    max_value = 600  # 10 minutes - actual maximum is 2 hours\n    validator_options = {\"byte_count\": 2}\n\n    class rw_class:\n        def __init__(self, feature, field):\n            self.feature = feature\n            self.kind = settings.FeatureRW.kind\n            self.field = field\n\n        def read(self, device):\n            backlight = device.backlight\n            return common.int2bytes(getattr(backlight, self.field) * 5, 2)  # use seconds instead of 5-second units\n\n        def write(self, device, data_bytes):\n            backlight = device.backlight\n            new_duration = (int.from_bytes(data_bytes, byteorder=\"big\") + 4) // 5  # use ceiling in 5-second units\n            if new_duration != getattr(backlight, self.field):\n                setattr(backlight, self.field, new_duration)\n                backlight.write()\n            return True\n\n\nclass Backlight2DurationHandsOut(Backlight2Duration):\n    name = \"backlight_duration_hands_out\"\n    label = _(\"Backlight Delay Hands Out\")\n    description = _(\"Delay in seconds until backlight fades out with hands away from keyboard.\")\n    feature = _F.BACKLIGHT2\n    validator_class = settings_validator.RangeValidator\n    rw_options = {\"field\": \"dho\"}\n\n\nclass Backlight2DurationHandsIn(Backlight2Duration):\n    name = \"backlight_duration_hands_in\"\n    label = _(\"Backlight Delay Hands In\")\n    description = _(\"Delay in seconds until backlight fades out with hands near keyboard.\")\n    feature = _F.BACKLIGHT2\n    validator_class = settings_validator.RangeValidator\n    rw_options = {\"field\": \"dhi\"}\n\n\nclass Backlight2DurationPowered(Backlight2Duration):\n    name = \"backlight_duration_powered\"\n    label = _(\"Backlight Delay Powered\")\n    description = _(\"Delay in seconds until backlight fades out with external power.\")\n    feature = _F.BACKLIGHT2\n    validator_class = settings_validator.RangeValidator\n    rw_options = {\"field\": \"dpow\"}\n\n\nclass Backlight3(settings.Setting):\n    name = \"backlight-timed\"\n    label = _(\"Backlight (Seconds)\")\n    description = _(\"Set illumination time for keyboard.\")\n    feature = _F.BACKLIGHT3\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20, \"suffix\": b\"\\x09\"}\n    validator_class = settings_validator.RangeValidator\n    min_value = 0\n    max_value = 1000\n    validator_options = {\"byte_count\": 2}\n\n\nclass HiResScroll(settings.Setting):\n    name = \"hi-res-scroll\"\n    label = _(\"Scroll Wheel High Resolution\")\n    description = (\n        _(\"High-sensitivity mode for vertical scroll with the wheel.\")\n        + \"\\n\"\n        + _(\"Set to ignore if scrolling is abnormally fast or slow\")\n    )\n    feature = _F.HI_RES_SCROLLING\n\n\nclass LowresMode(settings.Setting):\n    name = \"lowres-scroll-mode\"\n    label = _(\"Scroll Wheel Diversion\")\n    description = _(\n        \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger Solaar rules but are otherwise ignored).\"\n    )\n    feature = _F.LOWRES_WHEEL\n\n\nclass HiresSmoothInvert(settings.Setting):\n    name = \"hires-smooth-invert\"\n    label = _(\"Scroll Wheel Direction\")\n    description = _(\"Invert direction for vertical scroll with wheel.\")\n    feature = _F.HIRES_WHEEL\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n    validator_options = {\"true_value\": 0x04, \"mask\": 0x04}\n\n\nclass HiresSmoothResolution(settings.Setting):\n    name = \"hires-smooth-resolution\"\n    label = _(\"Scroll Wheel Resolution\")\n    description = (\n        _(\"High-sensitivity mode for vertical scroll with the wheel.\")\n        + \"\\n\"\n        + _(\"Set to ignore if scrolling is abnormally fast or slow\")\n    )\n    feature = _F.HIRES_WHEEL\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n    validator_options = {\"true_value\": 0x02, \"mask\": 0x02}\n\n\nclass HiresMode(settings.Setting):\n    name = \"hires-scroll-mode\"\n    label = _(\"Scroll Wheel Diversion\")\n    description = _(\n        \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar rules but are otherwise ignored).\"\n    )\n    feature = _F.HIRES_WHEEL\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n    validator_options = {\"true_value\": 0x01, \"mask\": 0x01}\n\n\nclass PointerSpeed(settings.Setting):\n    name = \"pointer_speed\"\n    label = _(\"Sensitivity (Pointer Speed)\")\n    description = _(\"Speed multiplier for mouse (256 is normal multiplier).\")\n    feature = _F.POINTER_SPEED\n    validator_class = settings_validator.RangeValidator\n    min_value = 0x002E\n    max_value = 0x01FF\n    validator_options = {\"byte_count\": 2}\n\n\nclass ThumbMode(settings.Setting):\n    name = \"thumb-scroll-mode\"\n    label = _(\"Thumb Wheel Diversion\")\n    description = _(\n        \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar rules but are otherwise ignored).\"\n    )\n    feature = _F.THUMB_WHEEL\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n    validator_options = {\"true_value\": b\"\\x01\\x00\", \"false_value\": b\"\\x00\\x00\", \"mask\": b\"\\x01\\x00\"}\n\n\nclass ThumbInvert(settings.Setting):\n    name = \"thumb-scroll-invert\"\n    label = _(\"Thumb Wheel Direction\")\n    description = _(\"Invert thumb wheel scroll direction.\")\n    feature = _F.THUMB_WHEEL\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n    validator_options = {\"true_value\": b\"\\x00\\x01\", \"false_value\": b\"\\x00\\x00\", \"mask\": b\"\\x00\\x01\"}\n\n\n# change UI to show result of onboard profile change\ndef profile_change(device, profile_sector):\n    if device.setting_callback:\n        device.setting_callback(device, OnboardProfiles, [profile_sector])\n        for profile in device.profiles.profiles.values() if device.profiles else []:\n            if profile.sector == profile_sector:\n                resolution_index = profile.resolution_default_index\n                device.setting_callback(device, AdjustableDpi, [profile.resolutions[resolution_index]])\n                device.setting_callback(device, ReportRate, [profile.report_rate])\n                break\n\n\nclass OnboardProfiles(settings.Setting):\n    name = \"onboard_profiles\"\n    label = _(\"Onboard Profiles\")\n    description = _(\"Enable an onboard profile, which controls report rate, sensitivity, and button actions\")\n    feature = _F.ONBOARD_PROFILES\n    choices_universe = common.NamedInts(Disabled=0)\n    for i in range(1, 16):\n        choices_universe[i] = f\"Profile {i}\"\n        choices_universe[i + 0x100] = f\"Read-Only Profile {i}\"\n    validator_class = settings_validator.ChoicesValidator\n\n    class rw_class:\n        def __init__(self, feature):\n            self.feature = feature\n            self.kind = settings.FeatureRW.kind\n\n        def read(self, device):\n            enabled = device.feature_request(_F.ONBOARD_PROFILES, 0x20)[0]\n            if enabled == 0x01:\n                active = device.feature_request(_F.ONBOARD_PROFILES, 0x40)\n                return active[:2]\n            else:\n                return b\"\\x00\\x00\"\n\n        def write(self, device, data_bytes):\n            if data_bytes == b\"\\x00\\x00\":\n                result = device.feature_request(_F.ONBOARD_PROFILES, 0x10, b\"\\x02\")\n            else:\n                device.feature_request(_F.ONBOARD_PROFILES, 0x10, b\"\\x01\")\n                result = device.feature_request(_F.ONBOARD_PROFILES, 0x30, data_bytes)\n                profile_change(device, common.bytes2int(data_bytes))\n            return result\n\n    class validator_class(settings_validator.ChoicesValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            headers = hidpp20.OnboardProfiles.get_profile_headers(device)\n            profiles_list = [setting_class.choices_universe[0]]\n            if headers:\n                for sector, enabled in headers:\n                    if enabled and setting_class.choices_universe[sector]:\n                        profiles_list.append(setting_class.choices_universe[sector])\n            return cls(choices=common.NamedInts.list(profiles_list), byte_count=2) if len(profiles_list) > 1 else None\n\n\nclass ReportRate(settings.Setting):\n    name = \"report_rate\"\n    label = _(\"Report Rate\")\n    description = (\n        _(\"Frequency of device movement reports\") + \"\\n\" + _(\"May need Onboard Profiles set to Disable to be effective.\")\n    )\n    feature = _F.REPORT_RATE\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n    choices_universe = common.NamedInts()\n    choices_universe[1] = \"1ms\"\n    choices_universe[2] = \"2ms\"\n    choices_universe[3] = \"3ms\"\n    choices_universe[4] = \"4ms\"\n    choices_universe[5] = \"5ms\"\n    choices_universe[6] = \"6ms\"\n    choices_universe[7] = \"7ms\"\n    choices_universe[8] = \"8ms\"\n\n    class validator_class(settings_validator.ChoicesValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            # if device.wpid == '408E':\n            #    return None  # host mode borks the function keys on the G915 TKL keyboard\n            reply = device.feature_request(_F.REPORT_RATE, 0x00)\n            assert reply, \"Oops, report rate choices cannot be retrieved!\"\n            rate_list = []\n            rate_flags = common.bytes2int(reply[0:1])\n            for i in range(0, 8):\n                if (rate_flags >> i) & 0x01:\n                    rate_list.append(setting_class.choices_universe[i + 1])\n            return cls(choices=common.NamedInts.list(rate_list), byte_count=1) if rate_list else None\n\n\nclass ExtendedReportRate(settings.Setting):\n    name = \"report_rate_extended\"\n    label = _(\"Report Rate\")\n    description = (\n        _(\"Frequency of device movement reports\") + \"\\n\" + _(\"May need Onboard Profiles set to Disable to be effective.\")\n    )\n    feature = _F.EXTENDED_ADJUSTABLE_REPORT_RATE\n    rw_options = {\"read_fnid\": 0x20, \"write_fnid\": 0x30}\n    choices_universe = common.NamedInts()\n    choices_universe[0] = \"8ms\"\n    choices_universe[1] = \"4ms\"\n    choices_universe[2] = \"2ms\"\n    choices_universe[3] = \"1ms\"\n    choices_universe[4] = \"500us\"\n    choices_universe[5] = \"250us\"\n    choices_universe[6] = \"125us\"\n\n    class validator_class(settings_validator.ChoicesValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            reply = device.feature_request(_F.EXTENDED_ADJUSTABLE_REPORT_RATE, 0x10)\n            assert reply, \"Oops, report rate choices cannot be retrieved!\"\n            rate_list = []\n            rate_flags = common.bytes2int(reply[0:2])\n            for i in range(0, 7):\n                if rate_flags & (0x01 << i):\n                    rate_list.append(setting_class.choices_universe[i])\n            return cls(choices=common.NamedInts.list(rate_list), byte_count=1) if rate_list else None\n\n\nclass DivertCrown(settings.Setting):\n    name = \"divert-crown\"\n    label = _(\"Divert crown events\")\n    description = _(\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but are otherwise ignored).\")\n    feature = _F.CROWN\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n    validator_options = {\"true_value\": 0x02, \"false_value\": 0x01, \"mask\": 0xFF}\n\n\nclass CrownSmooth(settings.Setting):\n    name = \"crown-smooth\"\n    label = _(\"Crown smooth scroll\")\n    description = _(\"Set crown smooth scroll\")\n    feature = _F.CROWN\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n    validator_options = {\"true_value\": 0x01, \"false_value\": 0x02, \"read_skip_byte_count\": 1, \"write_prefix_bytes\": b\"\\x00\"}\n\n\nclass DivertGkeys(settings.Setting):\n    name = \"divert-gkeys\"\n    label = _(\"Divert G and M Keys\")\n    description = _(\"Make G and M keys send HID++ notifications (which trigger Solaar rules but are otherwise ignored).\")\n    feature = _F.GKEY\n    validator_options = {\"true_value\": 0x01, \"false_value\": 0x00, \"mask\": 0xFF}\n\n    class rw_class(settings.FeatureRW):\n        def __init__(self, feature):\n            super().__init__(feature, write_fnid=0x20)\n\n        def read(self, device):  # no way to read, so just assume not diverted\n            return b\"\\x00\"\n\n\nclass ScrollRatchet(settings.Setting):\n    name = \"scroll-ratchet\"\n    label = _(\"Scroll Wheel Ratcheted\")\n    description = _(\"Switch the mouse wheel between speed-controlled ratcheting and always freespin.\")\n    feature = _F.SMART_SHIFT\n    choices_universe = common.NamedInts(**{_(\"Freespinning\"): 1, _(\"Ratcheted\"): 2})\n    validator_class = settings_validator.ChoicesValidator\n    validator_options = {\"choices\": choices_universe}\n\n\nclass SmartShift(settings.Setting):\n    name = \"smart-shift\"\n    label = _(\"Scroll Wheel Ratchet Speed\")\n    description = _(\n        \"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\n    )\n    feature = _F.SMART_SHIFT\n    rw_options = {\"read_fnid\": 0x00, \"write_fnid\": 0x10}\n\n    class rw_class(settings.FeatureRW):\n        MIN_VALUE = 1\n        MAX_VALUE = 50\n\n        def __init__(self, feature, read_fnid, write_fnid):\n            super().__init__(feature, read_fnid, write_fnid)\n\n        def read(self, device):\n            value = super().read(device)\n            if common.bytes2int(value[0:1]) == 1:\n                # Mode = Freespin, map to minimum\n                return common.int2bytes(self.MIN_VALUE, count=1)\n            else:\n                # Mode = smart shift, map to the value, capped at maximum\n                threshold = min(common.bytes2int(value[1:2]), self.MAX_VALUE)\n                return common.int2bytes(threshold, count=1)\n\n        def write(self, device, data_bytes):\n            threshold = common.bytes2int(data_bytes)\n            # Freespin at minimum\n            mode = 0  # 1 if threshold <= self.MIN_VALUE else 2\n            # Ratchet at maximum\n            if threshold >= self.MAX_VALUE:\n                threshold = 255\n            data = common.int2bytes(mode, count=1) + common.int2bytes(max(0, threshold), count=1)\n            return super().write(device, data)\n\n    min_value = rw_class.MIN_VALUE\n    max_value = rw_class.MAX_VALUE\n    validator_class = settings_validator.RangeValidator\n\n\nclass SmartShiftEnhanced(SmartShift):\n    feature = _F.SMART_SHIFT_ENHANCED\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n\n\nclass ScrollRatchetEnhanced(ScrollRatchet):\n    feature = _F.SMART_SHIFT_ENHANCED\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n\n\nclass ScrollRatchetTorque(settings.Setting):\n    name = \"scroll-ratchet-torque\"\n    label = _(\"Scroll Wheel Ratchet Torque\")\n    description = _(\"Change the torque needed to overcome the ratchet.\")\n    feature = _F.SMART_SHIFT_ENHANCED\n    min_value = 1\n    max_value = 100\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n\n    class rw_class(settings.FeatureRW):\n        def write(self, device, data_bytes):\n            ratchetSetting = next(filter(lambda s: s.name == \"scroll-ratchet\", device.settings), None)\n            if ratchetSetting:  # for MX Master 4, the ratchet setting needs to be written for changes to take effect\n                ratchet_value = ratchetSetting.read(True)\n                data_bytes = ratchet_value.to_bytes(1, \"big\") + data_bytes[1:]\n            result = super().write(device, data_bytes)\n            return result\n\n    class validator_class(settings_validator.RangeValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            reply = device.feature_request(_F.SMART_SHIFT_ENHANCED, 0x00)\n            if reply[0] & 0x01:  # device supports tunable torque\n                return cls(\n                    min_value=setting_class.min_value,\n                    max_value=setting_class.max_value,\n                    byte_count=1,\n                    write_prefix_bytes=b\"\\x00\\x00\",  # don't change mode or disengage, but see above\n                    read_skip_byte_count=2,\n                )\n\n\n# the keys for the choice map are Logitech controls (from special_keys)\n# each choice value is a NamedInt with the string from a task (to be shown to the user)\n# and the integer being the control number for that task (to be written to the device)\n# Solaar only remaps keys (controlled by key gmask and group), not other key reprogramming\nclass ReprogrammableKeys(settings.Settings):\n    name = \"reprogrammable-keys\"\n    label = _(\"Key/Button Actions\")\n    description = (\n        _(\"Change the action for the key or button.\")\n        + \"  \"\n        + _(\"Overridden by diversion.\")\n        + \"\\n\"\n        + _(\"Changing important actions (such as for the left mouse button) can result in an unusable system.\")\n    )\n    feature = _F.REPROG_CONTROLS_V4\n    keys_universe = special_keys.CONTROL\n    choices_universe = special_keys.CONTROL\n\n    class rw_class:\n        def __init__(self, feature):\n            self.feature = feature\n            self.kind = settings.FeatureRW.kind\n\n        def read(self, device, key):\n            key_index = device.keys.index(key)\n            key_struct = device.keys[key_index]\n            return b\"\\x00\\x00\" + common.int2bytes(int(key_struct.mapped_to), 2)\n\n        def write(self, device, key, data_bytes):\n            key_index = device.keys.index(key)\n            key_struct = device.keys[key_index]\n            key_struct.remap(special_keys.CONTROL[common.bytes2int(data_bytes)])\n            return True\n\n    class validator_class(settings_validator.ChoicesMapValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            choices = {}\n            if device.keys:\n                for k in device.keys:\n                    tgts = k.remappable_to\n                    if len(tgts) > 1:\n                        choices[k.key] = tgts\n            return cls(choices, key_byte_count=2, byte_count=2, extra_default=0) if choices else None\n\n\nclass DpiSlidingXY(settings.RawXYProcessing):\n    def __init__(\n        self,\n        *args,\n        show_notification: Callable[[str, str], bool],\n        **kwargs,\n    ):\n        super().__init__(*args, **kwargs)\n        self.fsmState = None\n        self._show_notification = show_notification\n\n    def activate_action(self):\n        self.dpiSetting = next(filter(lambda s: s.name == \"dpi\" or s.name == \"dpi_extended\", self.device.settings), None)\n        self.dpiChoices = list(self.dpiSetting.choices)\n        self.otherDpiIdx = self.device.persister.get(\"_dpi-sliding\", -1) if self.device.persister else -1\n        if not isinstance(self.otherDpiIdx, int) or self.otherDpiIdx < 0 or self.otherDpiIdx >= len(self.dpiChoices):\n            self.otherDpiIdx = self.dpiChoices.index(self.dpiSetting.read())\n        self.fsmState = State.IDLE\n        self.dx = 0.0\n        self.movingDpiIdx = None\n\n    def setNewDpi(self, newDpiIdx):\n        newDpi = self.dpiChoices[newDpiIdx]\n        self.dpiSetting.write(newDpi)\n        if self.device.setting_callback:\n            self.device.setting_callback(self.device, type(self.dpiSetting), [newDpi])\n\n    def displayNewDpi(self, newDpiIdx):\n        selected_dpi = self.dpiChoices[newDpiIdx]\n        min_dpi = self.dpiChoices[0]\n        max_dpi = self.dpiChoices[-1]\n        reason = f\"DPI {selected_dpi} [min {min_dpi}, max {max_dpi}]\"\n        self._show_notification(self.device, reason)\n\n    def press_action(self, key):  # start tracking\n        self.starting = True\n        if self.fsmState == State.IDLE:\n            self.fsmState = State.PRESSED\n            self.dx = 0.0\n            # While in 'moved' state, the index into 'dpiChoices' of the currently selected DPI setting\n            self.movingDpiIdx = None\n\n    def release_action(self):  # adjust DPI and stop tracking\n        if self.fsmState == State.PRESSED:  # Swap with other DPI\n            thisIdx = self.dpiChoices.index(self.dpiSetting.read())\n            newDpiIdx, self.otherDpiIdx = self.otherDpiIdx, thisIdx\n            if self.device.persister:\n                self.device.persister[\"_dpi-sliding\"] = self.otherDpiIdx\n            self.setNewDpi(newDpiIdx)\n            self.displayNewDpi(newDpiIdx)\n        elif self.fsmState == State.MOVED:  # Set DPI according to displacement\n            self.setNewDpi(self.movingDpiIdx)\n        self.fsmState = State.IDLE\n\n    def move_action(self, dx, dy):\n        if self.device.features.get_feature_version(_F.REPROG_CONTROLS_V4) >= 5 and self.starting:\n            self.starting = False  # hack to ignore strange first movement report from MX Master 3S\n            return\n        currDpi = self.dpiSetting.read()\n        self.dx += float(dx) / float(currDpi) * 15.0  # yields a more-or-less DPI-independent dx of about 5/cm\n        if self.fsmState == State.PRESSED:\n            if abs(self.dx) >= 1.0:\n                self.fsmState = State.MOVED\n                self.movingDpiIdx = self.dpiChoices.index(currDpi)\n        elif self.fsmState == State.MOVED:\n            currIdx = self.dpiChoices.index(self.dpiSetting.read())\n            newMovingDpiIdx = min(max(currIdx + int(self.dx), 0), len(self.dpiChoices) - 1)\n            if newMovingDpiIdx != self.movingDpiIdx:\n                self.movingDpiIdx = newMovingDpiIdx\n                self.displayNewDpi(newMovingDpiIdx)\n\n\nclass MouseGesturesXY(settings.RawXYProcessing):\n    def activate_action(self):\n        self.dpiSetting = next(filter(lambda s: s.name == \"dpi\" or s.name == \"dpi_extended\", self.device.settings), None)\n        self.fsmState = State.IDLE\n        self.initialize_data()\n\n    def initialize_data(self):\n        self.dx = 0.0\n        self.dy = 0.0\n        self.lastEv = None\n        self.data = []\n\n    def press_action(self, key):\n        self.starting = True\n        if self.fsmState == State.IDLE:\n            self.fsmState = State.PRESSED\n            self.initialize_data()\n            self.data = [key.key]\n\n    def release_action(self):\n        if self.fsmState == State.PRESSED:\n            # emit mouse gesture notification\n            self.push_mouse_event()\n            if logger.isEnabledFor(logging.INFO):\n                logger.info(\"mouse gesture notification %s\", self.data)\n            payload = struct.pack(\"!\" + (len(self.data) * \"h\"), *self.data)\n            notification = base.HIDPPNotification(0, 0, 0, 0, payload)\n            diversion.process_notification(self.device, notification, _F.MOUSE_GESTURE)\n            self.fsmState = State.IDLE\n\n    def move_action(self, dx, dy):\n        if self.fsmState == State.PRESSED:\n            now = time() * 1000  # time_ns() / 1e6\n            if self.device.features.get_feature_version(_F.REPROG_CONTROLS_V4) >= 5 and self.starting:\n                self.starting = False  # hack to ignore strange first movement report from MX Master 3S\n                return\n            if self.lastEv is not None and now - self.lastEv > 200.0:\n                self.push_mouse_event()\n            dpi = self.dpiSetting.read() if self.dpiSetting else 1000\n            dx = float(dx) / float(dpi) * 15.0  # This multiplier yields a more-or-less DPI-independent dx of about 5/cm\n            self.dx += dx\n            dy = float(dy) / float(dpi) * 15.0  # This multiplier yields a more-or-less DPI-independent dx of about 5/cm\n            self.dy += dy\n            self.lastEv = now\n\n    def key_action(self, key):\n        self.push_mouse_event()\n        self.data.append(1)\n        self.data.append(key)\n        self.lastEv = time() * 1000  # time_ns() / 1e6\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"mouse gesture key event %d %s\", key, self.data)\n\n    def push_mouse_event(self):\n        x = int(self.dx)\n        y = int(self.dy)\n        if x == 0 and y == 0:\n            return\n        self.data.append(0)\n        self.data.append(x)\n        self.data.append(y)\n        self.dx = 0.0\n        self.dy = 0.0\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"mouse gesture move event %d %d %s\", x, y, self.data)\n\n\nclass DivertKeys(settings.Settings):\n    name = \"divert-keys\"\n    label = _(\"Key/Button Diversion\")\n    description = _(\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse Gestures or Sliding DPI\")\n    feature = _F.REPROG_CONTROLS_V4\n    keys_universe = special_keys.CONTROL\n    choices_universe = common.NamedInts(**{_(\"Regular\"): 0, _(\"Diverted\"): 1, _(\"Mouse Gestures\"): 2, _(\"Sliding DPI\"): 3})\n    choices_gesture = common.NamedInts(**{_(\"Regular\"): 0, _(\"Diverted\"): 1, _(\"Mouse Gestures\"): 2})\n    choices_divert = common.NamedInts(**{_(\"Regular\"): 0, _(\"Diverted\"): 1})\n\n    class rw_class:\n        def __init__(self, feature):\n            self.feature = feature\n            self.kind = settings.FeatureRW.kind\n\n        def read(self, device, key):\n            key_index = device.keys.index(key)\n            key_struct = device.keys[key_index]\n            return b\"\\x00\\x00\\x01\" if MappingFlag.DIVERTED in key_struct.mapping_flags else b\"\\x00\\x00\\x00\"\n\n        def write(self, device, key, data_bytes):\n            key_index = device.keys.index(key)\n            key_struct = device.keys[key_index]\n            key_struct.set_diverted(common.bytes2int(data_bytes) != 0)  # not regular\n            return True\n\n    class validator_class(settings_validator.ChoicesMapValidator):\n        def __init__(self, choices, key_byte_count=2, byte_count=1, mask=0x01):\n            super().__init__(choices, key_byte_count, byte_count, mask)\n\n        def prepare_write(self, key, new_value):\n            if self.gestures and new_value != 2:  # mouse gestures\n                self.gestures.stop(key)\n            if self.sliding and new_value != 3:  # sliding DPI\n                self.sliding.stop(key)\n            if self.gestures and new_value == 2:  # mouse gestures\n                self.gestures.start(key)\n            if self.sliding and new_value == 3:  # sliding DPI\n                self.sliding.start(key)\n            return super().prepare_write(key, new_value)\n\n        @classmethod\n        def build(cls, setting_class, device):\n            sliding = gestures = None\n            choices = {}\n            if device.keys:\n                for key in device.keys:\n                    if KeyFlag.DIVERTABLE in key.flags and KeyFlag.VIRTUAL not in key.flags:\n                        if KeyFlag.RAW_XY in key.flags:\n                            choices[key.key] = setting_class.choices_gesture\n                            if gestures is None:\n                                gestures = MouseGesturesXY(device, name=\"MouseGestures\")\n                            if _F.ADJUSTABLE_DPI in device.features:\n                                choices[key.key] = setting_class.choices_universe\n                                if sliding is None:\n                                    sliding = DpiSlidingXY(\n                                        device, name=\"DpiSliding\", show_notification=desktop_notifications.show\n                                    )\n                        else:\n                            choices[key.key] = setting_class.choices_divert\n            if not choices:\n                return None\n            validator = cls(choices, key_byte_count=2, byte_count=1, mask=0x01)\n            validator.sliding = sliding\n            validator.gestures = gestures\n            return validator\n\n\ndef produce_dpi_list(feature, function, ignore, device, direction):\n    dpi_bytes = b\"\"\n    for i in range(0, 0x100):  # there will be only a very few iterations performed\n        reply = device.feature_request(feature, function, 0x00, direction, i)\n        assert reply, \"Oops, DPI list cannot be retrieved!\"\n        dpi_bytes += reply[ignore:]\n        if dpi_bytes[-2:] == b\"\\x00\\x00\":\n            break\n    dpi_list = []\n    i = 0\n    while i < len(dpi_bytes):\n        val = common.bytes2int(dpi_bytes[i : i + 2])\n        if val == 0:\n            break\n        if val >> 13 == 0b111:\n            step = val & 0x1FFF\n            last = common.bytes2int(dpi_bytes[i + 2 : i + 4])\n            assert len(dpi_list) > 0 and last > dpi_list[-1], f\"Invalid DPI list item: {val!r}\"\n            dpi_list += range(dpi_list[-1] + step, last + 1, step)\n            i += 4\n        else:\n            dpi_list.append(val)\n            i += 2\n    return dpi_list\n\n\nclass AdjustableDpi(settings.Setting):\n    name = \"dpi\"\n    label = _(\"Sensitivity (DPI)\")\n    description = _(\"Mouse movement sensitivity\") + \"\\n\" + _(\"May need Onboard Profiles set to Disable to be effective.\")\n    feature = _F.ADJUSTABLE_DPI\n    rw_options = {\"read_fnid\": 0x20, \"write_fnid\": 0x30}\n    choices_universe = common.NamedInts.range(100, 4000, str, 50)\n\n    class validator_class(settings_validator.ChoicesValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            dpilist = produce_dpi_list(setting_class.feature, 0x10, 1, device, 0)\n            setting = (\n                cls(choices=common.NamedInts.list(dpilist), byte_count=2, write_prefix_bytes=b\"\\x00\") if dpilist else None\n            )\n            setting.dpilist = dpilist\n            return setting\n\n        def validate_read(self, reply_bytes):  # special validator to use default DPI if needed\n            reply_value = common.bytes2int(reply_bytes[1:3])\n            if reply_value == 0:  # use default value instead\n                reply_value = common.bytes2int(reply_bytes[3:5])\n            valid_value = self.choices[reply_value]\n            assert valid_value is not None, f\"{self.__class__.__name__}: failed to validate read value {reply_value:02X}\"\n            return valid_value\n\n\nclass ExtendedAdjustableDpi(settings.Setting):\n    # the extended version allows for two dimensions, longer dpi descriptions, but still assume only one sensor\n    name = \"dpi_extended\"\n    label = _(\"Sensitivity (DPI)\")\n    description = _(\"Mouse movement sensitivity\") + \"\\n\" + _(\"May need Onboard Profiles set to Disable to be effective.\")\n    feature = _F.EXTENDED_ADJUSTABLE_DPI\n    rw_options = {\"read_fnid\": 0x50, \"write_fnid\": 0x60}\n    keys_universe = common.NamedInts(X=0, Y=1, LOD=2)\n    choices_universe = common.NamedInts.range(100, 4000, str, 50)\n    choices_universe[1] = \"LOW\"\n    choices_universe[2] = \"MEDIUM\"\n    choices_universe[3] = \"HIGH\"\n    keys = common.NamedInts(X=0, Y=1, LOD=2)\n\n    def write_key_value(self, key, value, save=True):\n        if isinstance(self._value, dict):\n            self._value[key] = value\n        else:\n            self._value = {key: value}\n        result = self.write(self._value, save)\n        return result[key] if isinstance(result, dict) else result\n\n    class validator_class(settings_validator.ChoicesMapValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            reply = device.feature_request(setting_class.feature, 0x10, 0x00)\n            y = bool(reply[2] & 0x01)\n            lod = bool(reply[2] & 0x02)\n            choices_map = {}\n            dpilist_x = produce_dpi_list(setting_class.feature, 0x20, 3, device, 0)\n            choices_map[setting_class.keys[\"X\"]] = common.NamedInts.list(dpilist_x)\n            if y:\n                dpilist_y = produce_dpi_list(setting_class.feature, 0x20, 3, device, 1)\n                choices_map[setting_class.keys[\"Y\"]] = common.NamedInts.list(dpilist_y)\n            if lod:\n                choices_map[setting_class.keys[\"LOD\"]] = common.NamedInts(LOW=0, MEDIUM=1, HIGH=2)\n            validator = cls(choices_map=choices_map, byte_count=2, write_prefix_bytes=b\"\\x00\")\n            validator.y = y\n            validator.lod = lod\n            validator.keys = setting_class.keys\n            return validator\n\n        def validate_read(self, reply_bytes):  # special validator to read entire setting\n            dpi_x = common.bytes2int(reply_bytes[3:5]) if reply_bytes[1:3] == 0 else common.bytes2int(reply_bytes[1:3])\n            assert dpi_x in self.choices[0], f\"{self.__class__.__name__}: failed to validate dpi_x value {dpi_x:04X}\"\n            value = {self.keys[\"X\"]: dpi_x}\n            if self.y:\n                dpi_y = common.bytes2int(reply_bytes[7:9]) if reply_bytes[5:7] == 0 else common.bytes2int(reply_bytes[5:7])\n                assert dpi_y in self.choices[1], f\"{self.__class__.__name__}: failed to validate dpi_y value {dpi_y:04X}\"\n                value[self.keys[\"Y\"]] = dpi_y\n            if self.lod:\n                lod = reply_bytes[9]\n                assert lod in self.choices[2], f\"{self.__class__.__name__}: failed to validate lod value {lod:02X}\"\n                value[self.keys[\"LOD\"]] = lod\n            return value\n\n        def prepare_write(self, new_value, current_value=None):  # special preparer to write entire setting\n            data_bytes = self._write_prefix_bytes\n            if new_value[self.keys[\"X\"]] not in self.choices[self.keys[\"X\"]]:\n                raise ValueError(f\"invalid value {new_value!r}\")\n            data_bytes += common.int2bytes(new_value[0], 2)\n            if self.y:\n                if new_value[self.keys[\"Y\"]] not in self.choices[self.keys[\"Y\"]]:\n                    raise ValueError(f\"invalid value {new_value!r}\")\n                data_bytes += common.int2bytes(new_value[self.keys[\"Y\"]], 2)\n            else:\n                data_bytes += b\"\\x00\\x00\"\n            if self.lod:\n                if new_value[self.keys[\"LOD\"]] not in self.choices[self.keys[\"LOD\"]]:\n                    raise ValueError(f\"invalid value {new_value!r}\")\n                data_bytes += common.int2bytes(new_value[self.keys[\"LOD\"]], 1)\n            else:\n                data_bytes += b\"\\x00\"\n            return data_bytes\n\n\nclass SpeedChange(settings.Setting):\n    \"\"\"Implements the ability to switch Sensitivity by clicking on the DPI_Change button.\"\"\"\n\n    name = \"speed-change\"\n    label = _(\"Sensitivity Switching\")\n    description = _(\n        \"Switch the current sensitivity and the remembered sensitivity when the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current sensitivity\"\n    )\n    choices_universe = special_keys.CONTROL\n    choices_extra = common.NamedInt(0, _(\"Off\"))\n    feature = _F.POINTER_SPEED\n    rw_options = {\"name\": \"speed change\"}\n\n    class rw_class(settings.ActionSettingRW):\n        def press_action(self):  # switch sensitivity\n            currentSpeed = self.device.persister.get(\"pointer_speed\", None) if self.device.persister else None\n            newSpeed = self.device.persister.get(\"_speed-change\", None) if self.device.persister else None\n            speed_setting = next(filter(lambda s: s.name == \"pointer_speed\", self.device.settings), None)\n            if newSpeed is not None:\n                if speed_setting:\n                    speed_setting.write(newSpeed)\n                    if self.device.setting_callback:\n                        self.device.setting_callback(self.device, type(speed_setting), [newSpeed])\n                else:\n                    logger.error(\"cannot save sensitivity setting on %s\", self.device)\n            if self.device.persister:\n                self.device.persister[\"_speed-change\"] = currentSpeed\n\n    class validator_class(settings_validator.ChoicesValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            key_index = device.keys.index(special_keys.CONTROL.DPI_Change)\n            key = device.keys[key_index] if key_index is not None else None\n            if key is not None and KeyFlag.DIVERTABLE in key.flags:\n                keys = [setting_class.choices_extra, key.key]\n                return cls(choices=common.NamedInts.list(keys), byte_count=2)\n\n\nclass DisableKeyboardKeys(settings.BitFieldSetting):\n    name = \"disable-keyboard-keys\"\n    label = _(\"Disable keys\")\n    description = _(\"Disable specific keyboard keys.\")\n    feature = _F.KEYBOARD_DISABLE_KEYS\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n    _labels = {k: (None, _(\"Disables the %s key.\") % k) for k in special_keys.DISABLE}\n    choices_universe = special_keys.DISABLE\n\n    class validator_class(settings_validator.BitFieldValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            mask = device.feature_request(_F.KEYBOARD_DISABLE_KEYS, 0x00)[0]\n            options = [special_keys.DISABLE[1 << i] for i in range(8) if mask & (1 << i)]\n            return cls(options) if options else None\n\n\nclass Multiplatform(settings.Setting):\n    name = \"multiplatform\"\n    label = _(\"Set OS\")\n    description = _(\"Change keys to match OS.\")\n    feature = _F.MULTIPLATFORM\n    rw_options = {\"read_fnid\": 0x00, \"write_fnid\": 0x30}\n    choices_universe = common.NamedInts(**{\"OS \" + str(i + 1): i for i in range(8)})\n\n    # multiplatform OS bits\n    OSS = [\n        (\"Linux\", 0x0400),\n        (\"MacOS\", 0x2000),\n        (\"Windows\", 0x0100),\n        (\"iOS\", 0x4000),\n        (\"Android\", 0x1000),\n        (\"WebOS\", 0x8000),\n        (\"Chrome\", 0x0800),\n        (\"WinEmb\", 0x0200),\n        (\"Tizen\", 0x0001),\n    ]\n\n    # the problem here is how to construct the right values for the rules Set GUI,\n    # as, for example, the integer value for 'Windows' can be different on different devices\n\n    class validator_class(settings_validator.ChoicesValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            def _str_os_versions(low, high):\n                def _str_os_version(version):\n                    if version == 0:\n                        return \"\"\n                    elif version & 0xFF:\n                        return f\"{str(version >> 8)}.{str(version & 0xFF)}\"\n                    else:\n                        return str(version >> 8)\n\n                return \"\" if low == 0 and high == 0 else f\" {_str_os_version(low)}-{_str_os_version(high)}\"\n\n            infos = device.feature_request(_F.MULTIPLATFORM)\n            assert infos, \"Oops, multiplatform count cannot be retrieved!\"\n            flags, _ignore, num_descriptors = struct.unpack(\"!BBB\", infos[:3])\n            if not (flags & 0x02):  # can't set platform so don't create setting\n                return []\n            descriptors = []\n            for index in range(0, num_descriptors):\n                descriptor = device.feature_request(_F.MULTIPLATFORM, 0x10, index)\n                platform, _ignore, os_flags, low, high = struct.unpack(\"!BBHHH\", descriptor[:8])\n                descriptors.append((platform, os_flags, low, high))\n            choices = common.NamedInts()\n            for os_name, os_bit in setting_class.OSS:\n                for platform, os_flags, low, high in descriptors:\n                    os = os_name + _str_os_versions(low, high)\n                    if os_bit & os_flags and platform not in choices and os not in choices:\n                        choices[platform] = os\n            return cls(choices=choices, read_skip_byte_count=6, write_prefix_bytes=b\"\\xff\") if choices else None\n\n\nclass DualPlatform(settings.Setting):\n    name = \"multiplatform\"\n    label = _(\"Set OS\")\n    description = _(\"Change keys to match OS.\")\n    choices_universe = common.NamedInts()\n    choices_universe[0x00] = \"iOS, MacOS\"\n    choices_universe[0x01] = \"Android, Windows\"\n    feature = _F.DUALPLATFORM\n    rw_options = {\"read_fnid\": 0x00, \"write_fnid\": 0x20}\n    validator_class = settings_validator.ChoicesValidator\n    validator_options = {\"choices\": choices_universe}\n\n\nclass ChangeHost(settings.Setting):\n    name = \"change-host\"\n    label = _(\"Change Host\")\n    description = _(\"Switch connection to a different host\")\n    persist = False  # persisting this setting is harmful\n    feature = _F.CHANGE_HOST\n    rw_options = {\"read_fnid\": 0x00, \"write_fnid\": 0x10, \"no_reply\": True}\n    choices_universe = common.NamedInts(**{\"Host \" + str(i + 1): i for i in range(3)})\n\n    class validator_class(settings_validator.ChoicesValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            infos = device.feature_request(_F.CHANGE_HOST)\n            assert infos, \"Oops, host count cannot be retrieved!\"\n            numHosts, currentHost = struct.unpack(\"!BB\", infos[:2])\n            hostNames = _hidpp20.get_host_names(device)\n            hostNames = hostNames if hostNames is not None else {}\n            if currentHost not in hostNames or hostNames[currentHost][1] == \"\":\n                hostNames[currentHost] = (True, socket.gethostname().partition(\".\")[0])\n            choices = common.NamedInts()\n            for host in range(0, numHosts):\n                paired, hostName = hostNames.get(host, (True, \"\"))\n                choices[host] = f\"{str(host + 1)}:{hostName}\" if hostName else str(host + 1)\n            return cls(choices=choices, read_skip_byte_count=1) if choices and len(choices) > 1 else None\n\n\n_GESTURE2_GESTURES_LABELS = {\n    GestureId.TAP_1_FINGER: (_(\"Single tap\"), _(\"Performs a left click.\")),\n    GestureId.TAP_2_FINGER: (_(\"Single tap with two fingers\"), _(\"Performs a right click.\")),\n    GestureId.TAP_3_FINGER: (_(\"Single tap with three fingers\"), None),\n    GestureId.CLICK_1_FINGER: (None, None),\n    GestureId.CLICK_2_FINGER: (None, None),\n    GestureId.CLICK_3_FINGER: (None, None),\n    GestureId.DOUBLE_TAP_1_FINGER: (_(\"Double tap\"), _(\"Performs a double click.\")),\n    GestureId.DOUBLE_TAP_2_FINGER: (_(\"Double tap with two fingers\"), None),\n    GestureId.DOUBLE_TAP_3_FINGER: (_(\"Double tap with three fingers\"), None),\n    GestureId.TRACK_1_FINGER: (None, None),\n    GestureId.TRACKING_ACCELERATION: (None, None),\n    GestureId.TAP_DRAG_1_FINGER: (_(\"Tap and drag\"), _(\"Drags items by dragging the finger after double tapping.\")),\n    GestureId.TAP_DRAG_2_FINGER: (\n        _(\"Tap and drag with two fingers\"),\n        _(\"Drags items by dragging the fingers after double tapping.\"),\n    ),\n    GestureId.DRAG_3_FINGER: (_(\"Tap and drag with three fingers\"), None),\n    GestureId.TAP_GESTURES: (None, None),\n    GestureId.FN_CLICK_GESTURE_SUPPRESSION: (\n        _(\"Suppress tap and edge gestures\"),\n        _(\"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"),\n    ),\n    GestureId.SCROLL_1_FINGER: (_(\"Scroll with one finger\"), _(\"Scrolls.\")),\n    GestureId.SCROLL_2_FINGER: (_(\"Scroll with two fingers\"), _(\"Scrolls.\")),\n    GestureId.SCROLL_2_FINGER_HORIZONTAL: (_(\"Scroll horizontally with two fingers\"), _(\"Scrolls horizontally.\")),\n    GestureId.SCROLL_2_FINGER_VERTICAL: (_(\"Scroll vertically with two fingers\"), _(\"Scrolls vertically.\")),\n    GestureId.SCROLL_2_FINGER_STATELESS: (_(\"Scroll with two fingers\"), _(\"Scrolls.\")),\n    GestureId.NATURAL_SCROLLING: (_(\"Natural scrolling\"), _(\"Inverts the scrolling direction.\")),\n    GestureId.THUMBWHEEL: (_(\"Thumbwheel\"), _(\"Enables the thumbwheel.\")),\n    GestureId.V_SCROLL_INTERTIA: (None, None),\n    GestureId.V_SCROLL_BALLISTICS: (None, None),\n    GestureId.SWIPE_2_FINGER_HORIZONTAL: (None, None),\n    GestureId.SWIPE_3_FINGER_HORIZONTAL: (None, None),\n    GestureId.SWIPE_4_FINGER_HORIZONTAL: (None, None),\n    GestureId.SWIPE_3_FINGER_VERTICAL: (None, None),\n    GestureId.SWIPE_4_FINGER_VERTICAL: (None, None),\n    GestureId.LEFT_EDGE_SWIPE_1_FINGER: (None, None),\n    GestureId.RIGHT_EDGE_SWIPE_1_FINGER: (None, None),\n    GestureId.BOTTOM_EDGE_SWIPE_1_FINGER: (None, None),\n    GestureId.TOP_EDGE_SWIPE_1_FINGER: (_(\"Swipe from the top edge\"), None),\n    GestureId.LEFT_EDGE_SWIPE_1_FINGER_2: (_(\"Swipe from the left edge\"), None),\n    GestureId.RIGHT_EDGE_SWIPE_1_FINGER_2: (_(\"Swipe from the right edge\"), None),\n    GestureId.BOTTOM_EDGE_SWIPE_1_FINGER_2: (_(\"Swipe from the bottom edge\"), None),\n    GestureId.TOP_EDGE_SWIPE_1_FINGER_2: (_(\"Swipe from the top edge\"), None),\n    GestureId.LEFT_EDGE_SWIPE_2_FINGER: (_(\"Swipe two fingers from the left edge\"), None),\n    GestureId.RIGHT_EDGE_SWIPE_2_FINGER: (_(\"Swipe two fingers from the right edge\"), None),\n    GestureId.BOTTOM_EDGE_SWIPE_2_FINGER: (_(\"Swipe two fingers from the bottom edge\"), None),\n    GestureId.TOP_EDGE_SWIPE_2_FINGER: (_(\"Swipe two fingers from the top edge\"), None),\n    GestureId.ZOOM_2_FINGER: (_(\"Zoom with two fingers.\"), _(\"Pinch to zoom out; spread to zoom in.\")),\n    GestureId.ZOOM_2_FINGER_PINCH: (_(\"Pinch to zoom out.\"), _(\"Pinch to zoom out.\")),\n    GestureId.ZOOM_2_FINGER_SPREAD: (_(\"Spread to zoom in.\"), _(\"Spread to zoom in.\")),\n    GestureId.ZOOM_3_FINGER: (_(\"Zoom with three fingers.\"), None),\n    GestureId.ZOOM_2_FINGER_STATELESS: (_(\"Zoom with two fingers\"), _(\"Pinch to zoom out; spread to zoom in.\")),\n    GestureId.TWO_FINGERS_PRESENT: (None, None),\n    GestureId.ROTATE_2_FINGER: (None, None),\n    GestureId.FINGER_1: (None, None),\n    GestureId.FINGER_2: (None, None),\n    GestureId.FINGER_3: (None, None),\n    GestureId.FINGER_4: (None, None),\n    GestureId.FINGER_5: (None, None),\n    GestureId.FINGER_6: (None, None),\n    GestureId.FINGER_7: (None, None),\n    GestureId.FINGER_8: (None, None),\n    GestureId.FINGER_9: (None, None),\n    GestureId.FINGER_10: (None, None),\n    GestureId.DEVICE_SPECIFIC_RAW_DATA: (None, None),\n}\n\n_GESTURE2_PARAMS_LABELS = {\n    ParamId.EXTRA_CAPABILITIES: (None, None),  # not supported\n    ParamId.PIXEL_ZONE: (_(\"Pixel zone\"), None),  # TO DO: replace None with a short description\n    ParamId.RATIO_ZONE: (_(\"Ratio zone\"), None),  # TO DO: replace None with a short description\n    ParamId.SCALE_FACTOR: (_(\"Scale factor\"), _(\"Sets the cursor speed.\")),\n}\n\n_GESTURE2_PARAMS_LABELS_SUB = {\n    \"left\": (_(\"Left\"), _(\"Left-most coordinate.\")),\n    \"bottom\": (_(\"Bottom\"), _(\"Bottom coordinate.\")),\n    \"width\": (_(\"Width\"), _(\"Width.\")),\n    \"height\": (_(\"Height\"), _(\"Height.\")),\n    \"scale\": (_(\"Scale\"), _(\"Cursor speed.\")),\n}\n\n\nclass Gesture2Gestures(settings.BitFieldWithOffsetAndMaskSetting):\n    name = \"gesture2-gestures\"\n    label = _(\"Gestures\")\n    description = _(\"Tweak the mouse/touchpad behaviour.\")\n    feature = _F.GESTURE_2\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n    validator_options = {\"om_method\": hidpp20.Gesture.enable_offset_mask}\n    choices_universe = hidpp20_constants.GestureId\n    _labels = _GESTURE2_GESTURES_LABELS\n\n    class validator_class(settings_validator.BitFieldWithOffsetAndMaskValidator):\n        @classmethod\n        def build(cls, setting_class, device, om_method=None):\n            options = [g for g in device.gestures.gestures.values() if g.can_be_enabled or g.default_enabled]\n            return cls(options, om_method=om_method) if options else None\n\n\nclass Gesture2Divert(settings.BitFieldWithOffsetAndMaskSetting):\n    name = \"gesture2-divert\"\n    label = _(\"Gestures Diversion\")\n    description = _(\"Divert mouse/touchpad gestures.\")\n    feature = _F.GESTURE_2\n    rw_options = {\"read_fnid\": 0x30, \"write_fnid\": 0x40}\n    validator_options = {\"om_method\": hidpp20.Gesture.diversion_offset_mask}\n    choices_universe = hidpp20_constants.GestureId\n    _labels = _GESTURE2_GESTURES_LABELS\n\n    class validator_class(settings_validator.BitFieldWithOffsetAndMaskValidator):\n        @classmethod\n        def build(cls, setting_class, device, om_method=None):\n            options = [g for g in device.gestures.gestures.values() if g.can_be_diverted]\n            return cls(options, om_method=om_method) if options else None\n\n\nclass Gesture2Params(settings.LongSettings):\n    name = \"gesture2-params\"\n    label = _(\"Gesture params\")\n    description = _(\"Change numerical parameters of a mouse/touchpad.\")\n    feature = _F.GESTURE_2\n    rw_options = {\"read_fnid\": 0x70, \"write_fnid\": 0x80}\n    choices_universe = hidpp20_constants.ParamId\n    sub_items_universe = hidpp20.SUB_PARAM\n    # item (NamedInt) -> list/tuple of objects that have the following attributes\n    # .id (sub-item text), .length (in bytes), .minimum and .maximum\n\n    _labels = _GESTURE2_PARAMS_LABELS\n    _labels_sub = _GESTURE2_PARAMS_LABELS_SUB\n\n    class validator_class(settings_validator.MultipleRangeValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            params = _hidpp20.get_gestures(device).params.values()\n            items = [i for i in params if i.sub_params]\n            if not items:\n                return None\n            sub_items = {i: i.sub_params for i in items}\n            return cls(items, sub_items)\n\n\nclass MKeyLEDs(settings.BitFieldSetting):\n    name = \"m-key-leds\"\n    label = _(\"M-Key LEDs\")\n    description = (\n        _(\"Control the M-Key LEDs.\")\n        + \"\\n\"\n        + _(\"May need Onboard Profiles set to Disable to be effective.\")\n        + \"\\n\"\n        + _(\"May need G Keys diverted to be effective.\")\n    )\n    feature = _F.MKEYS\n    choices_universe = common.NamedInts()\n    for i in range(8):\n        choices_universe[1 << i] = \"M\" + str(i + 1)\n    _labels = {k: (None, _(\"Lights up the %s key.\") % k) for k in choices_universe}\n\n    class rw_class(settings.FeatureRW):\n        def __init__(self, feature):\n            super().__init__(feature, write_fnid=0x10)\n\n        def read(self, device):  # no way to read, so just assume off\n            return b\"\\x00\"\n\n    class validator_class(settings_validator.BitFieldValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            number = device.feature_request(setting_class.feature, 0x00)[0]\n            options = [setting_class.choices_universe[1 << i] for i in range(number)]\n            return cls(options) if options else None\n\n\nclass MRKeyLED(settings.Setting):\n    name = \"mr-key-led\"\n    label = _(\"MR-Key LED\")\n    description = (\n        _(\"Control the MR-Key LED.\")\n        + \"\\n\"\n        + _(\"May need Onboard Profiles set to Disable to be effective.\")\n        + \"\\n\"\n        + _(\"May need G Keys diverted to be effective.\")\n    )\n    feature = _F.MR\n\n    class rw_class(settings.FeatureRW):\n        def __init__(self, feature):\n            super().__init__(feature, write_fnid=0x00)\n\n        def read(self, device):  # no way to read, so just assume off\n            return b\"\\x00\"\n\n\n## Only implemented for devices that can produce Key and Consumer Codes (e.g., Craft)\n## and devices that can produce Key, Mouse, and Horizontal Scroll (e.g., M720)\n## Only interested in current host, so use 0xFF for it\nclass PersistentRemappableAction(settings.Settings):\n    name = \"persistent-remappable-keys\"\n    label = _(\"Persistent Key/Button Mapping\")\n    description = (\n        _(\"Permanently change the mapping for the key or button.\")\n        + \"\\n\"\n        + _(\"Changing important keys or buttons (such as for the left mouse button) can result in an unusable system.\")\n    )\n    persist = False  # This setting is persistent in the device so no need to persist it here\n    feature = _F.PERSISTENT_REMAPPABLE_ACTION\n    keys_universe = special_keys.CONTROL\n    choices_universe = special_keys.KEYS\n\n    class rw_class:\n        def __init__(self, feature):\n            self.feature = feature\n            self.kind = settings.FeatureRW.kind\n\n        def read(self, device, key):\n            ks = device.remap_keys[device.remap_keys.index(key)]\n            return b\"\\x00\\x00\" + ks.data_bytes\n\n        def write(self, device, key, data_bytes):\n            ks = device.remap_keys[device.remap_keys.index(key)]\n            v = ks.remap(data_bytes)\n            return v\n\n    class validator_class(settings_validator.ChoicesMapValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            remap_keys = device.remap_keys\n            if not remap_keys:\n                return None\n            capabilities = device.remap_keys.capabilities\n            if capabilities & 0x0041 == 0x0041:  # Key and Consumer Codes\n                keys = special_keys.KEYS_KEYS_CONSUMER\n            elif capabilities & 0x0023 == 0x0023:  # Key, Mouse, and HScroll Codes\n                keys = special_keys.KEYS_KEYS_MOUSE_HSCROLL\n            else:\n                if logger.isEnabledFor(logging.WARNING):\n                    logger.warning(\"%s: unimplemented Persistent Remappable capability %s\", device.name, hex(capabilities))\n                return None\n            choices = {}\n            for k in remap_keys:\n                if k is not None:\n                    key = special_keys.CONTROL[k.key]\n                    choices[key] = keys  # TO RECOVER FROM BAD VALUES use special_keys.KEYS\n            return cls(choices, key_byte_count=2, byte_count=4) if choices else None\n\n        def validate_read(self, reply_bytes, key):\n            start = self._key_byte_count + self._read_skip_byte_count\n            end = start + self._byte_count\n            reply_value = common.bytes2int(reply_bytes[start:end]) & self.mask\n            # Craft keyboard has a value that isn't valid so fudge these values\n            if reply_value not in self.choices[key]:\n                if logger.isEnabledFor(logging.WARNING):\n                    logger.warning(\"unusual persistent remappable action mapping %x: use Default\", reply_value)\n                reply_value = special_keys.KEYS_Default\n            return reply_value\n\n\nclass Sidetone(settings.Setting):\n    name = \"sidetone\"\n    label = _(\"Sidetone\")\n    description = _(\"Set sidetone level.\")\n    feature = _F.SIDETONE\n    validator_class = settings_validator.RangeValidator\n    min_value = 0\n    max_value = 100\n\n\nclass Equalizer(settings.RangeFieldSetting):\n    name = \"equalizer\"\n    label = _(\"Equalizer\")\n    description = _(\"Set equalizer levels.\")\n    feature = _F.EQUALIZER\n    rw_options = {\"read_fnid\": 0x20, \"write_fnid\": 0x30, \"read_prefix\": b\"\\x00\"}\n    keys_universe = []\n\n    class validator_class(settings_validator.PackedRangeValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            data = device.feature_request(_F.EQUALIZER, 0x00)\n            if not data:\n                return None\n            count, dbRange, _x, dbMin, dbMax = struct.unpack(\"!BBBBB\", data[:5])\n            if dbMin == 0:\n                dbMin = -dbRange\n            if dbMax == 0:\n                dbMax = dbRange\n            map = common.NamedInts()\n            for g in range((count + 6) // 7):\n                freqs = device.feature_request(_F.EQUALIZER, 0x10, g * 7)\n                for b in range(7):\n                    if g * 7 + b >= count:\n                        break\n                    map[g * 7 + b] = str(int.from_bytes(freqs[2 * b + 1 : 2 * b + 3], \"big\")) + _(\"Hz\")\n            return cls(map, min_value=dbMin, max_value=dbMax, count=count, write_prefix_bytes=b\"\\x02\")\n\n\nclass ADCPower(settings.Setting):\n    name = \"adc_power_management\"\n    label = _(\"Power Management\")\n    description = _(\"Power off in minutes (0 for never).\")\n    feature = _F.ADC_MEASUREMENT\n    min_version = 2  # documentation for version 1 does not mention this capability\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n    validator_class = settings_validator.RangeValidator\n    min_value = 0x00\n    max_value = 0xFF\n    validator_options = {\"byte_count\": 1}\n\n\nclass BrightnessControl(settings.Setting):\n    name = \"brightness_control\"\n    label = _(\"Brightness Control\")\n    description = _(\"Control overall brightness\")\n    feature = _F.BRIGHTNESS_CONTROL\n    rw_options = {\"read_fnid\": 0x10, \"write_fnid\": 0x20}\n    validator_class = settings_validator.RangeValidator\n\n    def __init__(self, device, rw, validator):\n        super().__init__(device, rw, validator)\n        rw.on_off = validator.on_off\n        rw.min_nonzero_value = validator.min_value\n        validator.min_value = 0 if validator.on_off else validator.min_value\n\n    class rw_class(settings.FeatureRW):\n        def read(self, device, data_bytes=b\"\"):\n            if self.on_off:\n                reply = device.feature_request(self.feature, 0x30)\n                if not reply[0] & 0x01:\n                    return b\"\\x00\\x00\"\n            return super().read(device, data_bytes)\n\n        def write(self, device, data_bytes):\n            if self.on_off:\n                off = int.from_bytes(data_bytes, byteorder=\"big\") < self.min_nonzero_value\n                reply = device.feature_request(self.feature, 0x40, b\"\\x00\" if off else b\"\\x01\", no_reply=False)\n                if off:\n                    return reply\n            return super().write(device, data_bytes)\n\n    class validator_class(settings_validator.RangeValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            reply = device.feature_request(_F.BRIGHTNESS_CONTROL)\n            assert reply, \"Oops, brightness range cannot be retrieved!\"\n            if reply:\n                max_value = int.from_bytes(reply[0:2], byteorder=\"big\")\n                min_value = int.from_bytes(reply[4:6], byteorder=\"big\")\n                on_off = bool(reply[3] & 0x04)  # separate on/off control\n                validator = cls(min_value=min_value, max_value=max_value, byte_count=2)\n                validator.on_off = on_off\n                return validator\n\n\nclass LEDControl(settings.Setting):\n    name = \"led_control\"\n    label = _(\"LED Control\")\n    description = _(\"Switch control of LED zones between device and Solaar\")\n    feature = _F.COLOR_LED_EFFECTS\n    rw_options = {\"read_fnid\": 0x70, \"write_fnid\": 0x80}\n    choices_universe = common.NamedInts(Device=0, Solaar=1)\n    validator_class = settings_validator.ChoicesValidator\n    validator_options = {\"choices\": choices_universe}\n\n\ncolors = special_keys.COLORS\n_LEDP = hidpp20.LEDParam\n\n\n# an LED Zone has an index, a set of possible LED effects, and an LED effect setting\nclass LEDZoneSetting(settings.Setting):\n    name = \"led_zone_\"  # the trailing underscore signals that this setting creates other settings\n    label = _(\"LED Zone Effects\")\n    description = _(\"Set effect for LED Zone\") + \"\\n\" + _(\"LED Control needs to be set to Solaar to be effective.\")\n    feature = _F.COLOR_LED_EFFECTS\n    color_field = {\"name\": _LEDP.color, \"kind\": settings.Kind.COLOR, \"label\": _(\"Color\")}\n    speed_field = {\"name\": _LEDP.speed, \"kind\": settings.Kind.RANGE, \"label\": _(\"Speed\"), \"min\": 0, \"max\": 255}\n    period_field = {\"name\": _LEDP.period, \"kind\": settings.Kind.RANGE, \"label\": _(\"Period\"), \"min\": 100, \"max\": 5000}\n    intensity_field = {\"name\": _LEDP.intensity, \"kind\": settings.Kind.RANGE, \"label\": _(\"Intensity\"), \"min\": 0, \"max\": 100}\n    ramp_field = {\"name\": _LEDP.ramp, \"kind\": settings.Kind.CHOICE, \"label\": _(\"Ramp\"), \"choices\": hidpp20.LedRampChoice}\n    possible_fields = [color_field, speed_field, period_field, intensity_field, ramp_field]\n\n    @classmethod\n    def setup(cls, device, read_fnid, write_fnid, suffix):\n        infos = device.led_effects\n        settings_ = []\n        for zone in infos.zones:\n            prefix = common.int2bytes(zone.index, 1)\n            rw = settings.FeatureRW(cls.feature, read_fnid, write_fnid, prefix=prefix, suffix=suffix)\n            validator = settings_validator.HeteroValidator(\n                data_class=hidpp20.LEDEffectSetting, options=zone.effects, readable=infos.readable and read_fnid is not None\n            )\n            setting = cls(device, rw, validator)\n            setting.name = cls.name + str(int(zone.location))\n            setting.label = _(\"LEDs\") + \" \" + str(hidpp20.LEDZoneLocations[zone.location])\n            choices = [hidpp20.LEDEffects[e.ID][0] for e in zone.effects if e.ID in hidpp20.LEDEffects]\n            ID_field = {\"name\": \"ID\", \"kind\": settings.Kind.CHOICE, \"label\": None, \"choices\": choices}\n            setting.possible_fields = [ID_field] + cls.possible_fields\n            setting.fields_map = hidpp20.LEDEffects\n            settings_.append(setting)\n        return settings_\n\n    @classmethod\n    def build(cls, device):\n        return cls.setup(device, 0xE0, 0x30, b\"\")\n\n\nclass RGBControl(settings.Setting):\n    name = \"rgb_control\"\n    label = _(\"LED Control\")\n    description = _(\"Switch control of LED zones between device and Solaar\")\n    feature = _F.RGB_EFFECTS\n    rw_options = {\"read_fnid\": 0x50, \"write_fnid\": 0x50}\n    choices_universe = common.NamedInts(Device=0, Solaar=1)\n    validator_class = settings_validator.ChoicesValidator\n    validator_options = {\"choices\": choices_universe, \"write_prefix_bytes\": b\"\\x01\", \"read_skip_byte_count\": 1}\n\n\nclass RGBEffectSetting(LEDZoneSetting):\n    name = \"rgb_zone_\"  # the trailing underscore signals that this setting creates other settings\n    label = _(\"LED Zone Effects\")\n    description = _(\"Set effect for LED Zone\") + \"\\n\" + _(\"LED Control needs to be set to Solaar to be effective.\")\n    feature = _F.RGB_EFFECTS\n\n    @classmethod\n    def build(cls, device):\n        return cls.setup(device, None, 0x10, b\"\\x01\")\n\n\nclass PerKeyLighting(settings.Settings):\n    name = \"per-key-lighting\"\n    label = _(\"Per-key Lighting\")\n    description = _(\"Control per-key lighting.\")\n    feature = _F.PER_KEY_LIGHTING_V2\n    keys_universe = special_keys.KEYCODES\n    choices_universe = special_keys.COLORSPLUS\n\n    def read(self, cached=True):\n        self._pre_read(cached)\n        if cached and self._value is not None:\n            return self._value\n        reply_map = {}\n        for key in self._validator.choices:\n            reply_map[int(key)] = special_keys.COLORSPLUS[\"No change\"]  # this signals no change\n        self._value = reply_map\n        return reply_map\n\n    def write(self, map, save=True):\n        if self._device.online:\n            self.update(map, save)\n            table = {}\n            for key, value in map.items():\n                if value in table:\n                    table[value].append(key)  # keys will be in order from small to large\n                else:\n                    table[value] = [key]\n            if len(table) == 1:  # use range update\n                for value, keys in table.items():  # only one, of course\n                    if value != special_keys.COLORSPLUS[\"No change\"]:  # this signals no change, so don't update at all\n                        data_bytes = keys[0].to_bytes(1, \"big\") + keys[-1].to_bytes(1, \"big\") + value.to_bytes(3, \"big\")\n                        self._device.feature_request(self.feature, 0x50, data_bytes)  # range update command to update all keys\n                        self._device.feature_request(self.feature, 0x70, 0x00)  # signal device to make the changes\n            else:\n                data_bytes = b\"\"\n                for value, keys in table.items():  # only one, of course\n                    if value != special_keys.COLORSPLUS[\"No change\"]:  # this signals no change, so ignore it\n                        while len(keys) > 3:  # use an optimized update command that can update up to 13 keys\n                            data = value.to_bytes(3, \"big\") + b\"\".join([key.to_bytes(1, \"big\") for key in keys[0:13]])\n                            self._device.feature_request(self.feature, 0x60, data)  # single-value multiple-keys update\n                            keys = keys[13:]\n                        for key in keys:\n                            data_bytes += key.to_bytes(1, \"big\") + value.to_bytes(3, \"big\")\n                            if len(data_bytes) >= 16:  # up to four values are packed into a regular update\n                                self._device.feature_request(self.feature, 0x10, data_bytes)\n                                data_bytes = b\"\"\n                if len(data_bytes) > 0:  # update any remaining keys\n                    self._device.feature_request(self.feature, 0x10, data_bytes)\n                self._device.feature_request(self.feature, 0x70, 0x00)  # signal device to make the changes\n        return map\n\n    def write_key_value(self, key, value, save=True):\n        if value != special_keys.COLORSPLUS[\"No change\"]:  # this signals no change\n            result = super().write_key_value(int(key), value, save)\n            if self._device.online:\n                self._device.feature_request(self.feature, 0x70, 0x00)  # signal device to make the change\n            return result\n        else:\n            return True\n\n    class rw_class(settings.FeatureRWMap):\n        pass\n\n    class validator_class(settings_validator.ChoicesMapValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            choices_map = {}\n            key_bitmap = device.feature_request(setting_class.feature, 0x00, 0x00, 0x00)[2:]\n            key_bitmap += device.feature_request(setting_class.feature, 0x00, 0x00, 0x01)[2:]\n            key_bitmap += device.feature_request(setting_class.feature, 0x00, 0x00, 0x02)[2:]\n            for i in range(1, 255):\n                if (key_bitmap[i // 8] >> i % 8) & 0x01:\n                    key = (\n                        setting_class.keys_universe[i]\n                        if i in setting_class.keys_universe\n                        else common.NamedInt(i, f\"KEY {str(i)}\")\n                    )\n                    choices_map[key] = setting_class.choices_universe\n            result = cls(choices_map) if choices_map else None\n            return result\n\n\n# Allow changes to force sensing buttons\nclass ForceSensing(settings_new.Settings):\n    name = \"force-sensing\"\n    label = _(\"Force Sensing Buttons\")\n    description = _(\"Change the force required to activate button.\")\n    feature = _F.FORCE_SENSING_BUTTON\n    setup = \"force_buttons\"\n    get = \"get_current\"\n    set = \"set_current\"\n    acceptable = \"acceptable_current_key\"\n    choices_universe = list(range(0, 256))\n    kind = settings.Kind.MAP_RANGE\n\n    @classmethod\n    def build(cls, device):\n        cls.check_properties(cls)\n        device_object = getattr(device, cls.setup)()\n        if device_object:\n            setting = cls(device, device_object)\n            if setting and len(device_object) == 1:\n                ## If there is only one force button a simpler interface can be used\n                setting.label = _(\"Force Sensing Button\")\n                setting.acceptable = \"acceptable_current\"\n                setting.min_value = device_object[0].min_value\n                setting.max_value = device_object[0].max_value\n                setting.kind = settings.Kind.RANGE\n            return setting\n\n\nclass HapticLevel(settings.Setting):\n    name = \"haptic-level\"\n    label = _(\"Haptic Feedback Level\")\n    description = _(\"Change power of haptic feedback.  (Zero to turn off.)\")\n    feature = _F.HAPTIC\n    choices_universe = common.NamedInts(Off=0, Low=25, Medium=50, High=75, Maximum=100)\n    min_value = 0\n    max_value = 100\n\n    class rw_class(settings.FeatureRW):\n        def __init__(self, feature):\n            super().__init__(feature, read_fnid=0x10, write_fnid=0x20)\n\n        def read(self, device, data_bytes=b\"\"):\n            result = device.feature_request(self.feature, 0x10)\n            if result[0] & 0x01 == 0:  # disabled, return 0\n                return b\"\\x00\"\n            else:  # enabled, return second byte\n                return result[1:2]\n\n        def write(self, device, data_bytes):\n            if data_bytes == b\"\\x00\":\n                write_bytes = b\"\\x00\\x32\"  # disable, at 50 percent\n            else:\n                write_bytes = b\"\\x01\" + data_bytes\n            reply = device.feature_request(self.feature, 0x20, write_bytes)\n            return reply\n\n    @classmethod\n    def build(cls, device):\n        response = device.feature_request(cls.feature, 0x10)\n        if response:\n            rw = cls.rw_class(cls.feature)\n            levels = response[2] & 0x01\n            if levels:  # device only has four levels\n                validator = settings_validator.ChoicesValidator(choices=cls.choices_universe)\n            else:  # device has all levels\n                validator = settings_validator.RangeValidator(min_value=cls.min_value, max_value=cls.max_value)\n            return cls(device, rw, validator)\n\n\n# This setting is not displayed in the UI\n# Use `solaar config <device> haptic-play <form>` to play a haptic form\nclass PlayHapticWaveForm(settings.Setting):\n    name = \"haptic-play\"\n    label = _(\"Play Haptic Waveform\")\n    description = _(\"Tell device to play a haptic waveform.\")\n    feature = _F.HAPTIC\n    choices_universe = hidpp20_constants.HapticWaveForms\n    rw_options = {\"read_fnid\": None, \"write_fnid\": 0x40}  # nothing to read\n    persist = False  # persisting this setting is useless\n    display = False  # don't display in UI, interact using `solaar config ...`\n\n    class validator_class(settings_validator.ChoicesValidator):\n        @classmethod\n        def build(cls, setting_class, device):\n            response = device.feature_request(_F.HAPTIC, 0x00)\n            if response:\n                waves = common.NamedInts()\n                waveforms = int.from_bytes(response[4:8])\n                for waveform in hidpp20_constants.HapticWaveForms:\n                    if (1 << int(waveform)) & waveforms:\n                        waves[int(waveform)] = str(waveform)\n            return cls(choices=waves, byte_count=1)\n\n\nSETTINGS: list[settings.Setting] = [\n    RegisterHandDetection,  # simple\n    RegisterSmoothScroll,  # simple\n    RegisterSideScroll,  # simple\n    RegisterDpi,\n    RegisterFnSwap,  # working\n    HiResScroll,  # simple\n    LowresMode,  # simple\n    HiresSmoothInvert,  # working\n    HiresSmoothResolution,  # working\n    HiresMode,  # simple\n    ScrollRatchet,  # simple\n    ScrollRatchetTorque,\n    SmartShift,  # working\n    ScrollRatchetEnhanced,\n    SmartShiftEnhanced,  # simple\n    ThumbInvert,  # working\n    ThumbMode,  # working\n    OnboardProfiles,\n    ReportRate,  # working\n    ExtendedReportRate,\n    PointerSpeed,  # simple\n    AdjustableDpi,  # working\n    ExtendedAdjustableDpi,\n    SpeedChange,\n    #    Backlight,  # not working - disabled temporarily\n    Backlight2,  # working\n    Backlight2Level,\n    Backlight2DurationHandsOut,\n    Backlight2DurationHandsIn,\n    Backlight2DurationPowered,\n    Backlight3,\n    LEDControl,\n    LEDZoneSetting,\n    RGBControl,\n    RGBEffectSetting,\n    BrightnessControl,\n    PerKeyLighting,\n    FnSwap,  # simple\n    NewFnSwap,  # simple\n    K375sFnSwap,  # working\n    ReprogrammableKeys,  # working\n    PersistentRemappableAction,\n    DivertKeys,  # working\n    DisableKeyboardKeys,  # working\n    ForceSensing,\n    CrownSmooth,  # working\n    DivertCrown,  # working\n    DivertGkeys,  # working\n    MKeyLEDs,  # working\n    MRKeyLED,  # working\n    Multiplatform,  # working\n    DualPlatform,  # simple\n    ChangeHost,  # working\n    Gesture2Gestures,  # working\n    Gesture2Divert,\n    Gesture2Params,  # working\n    HapticLevel,\n    PlayHapticWaveForm,\n    Sidetone,\n    Equalizer,\n    ADCPower,\n]\n\n\nclass SettingsProtocol(Protocol):\n    @property\n    def name(self):\n        ...\n\n    @property\n    def label(self):\n        ...\n\n    @property\n    def description(self):\n        ...\n\n    @property\n    def feature(self):\n        ...\n\n    @property\n    def register(self):\n        ...\n\n    @property\n    def kind(self):\n        ...\n\n    @property\n    def min_version(self):\n        ...\n\n    @property\n    def persist(self):\n        ...\n\n    @property\n    def rw_options(self):\n        ...\n\n    @property\n    def validator_class(self):\n        ...\n\n    @property\n    def validator_options(self):\n        ...\n\n    @classmethod\n    def build(cls, device):\n        ...\n\n    def val_to_string(self, value):\n        ...\n\n    @property\n    def choices(self):\n        ...\n\n    @property\n    def range(self):\n        ...\n\n    def _pre_read(self, cached, key=None):\n        ...\n\n    def read(self, cached=True):\n        ...\n\n    def _pre_write(self, save=True):\n        ...\n\n    def update(self, value, save=True):\n        ...\n\n    def write(self, value, save=True):\n        ...\n\n    def acceptable(self, args, current):\n        ...\n\n    def compare(self, args, current):\n        ...\n\n    def apply(self):\n        ...\n\n    def __str__(self):\n        ...\n\n\ndef check_feature(device, settings_class: SettingsProtocol) -> None | bool | SettingsProtocol:\n    if settings_class.feature not in device.features:\n        return\n    if settings_class.min_version > device.features.get_feature_version(settings_class.feature):\n        return\n    if device.features.get_hidden(settings_class.feature):\n        return\n    try:\n        detected = settings_class.build(device)\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"check_feature %s [%s] detected\", settings_class.name, settings_class.feature)\n        return detected\n    except Exception as e:\n        logger.error(\n            \"check_feature %s [%s] error %s\\n%s\", settings_class.name, settings_class.feature, e, traceback.format_exc()\n        )\n        raise e  # differentiate from an error-free determination that the setting is not supported\n\n\ndef check_feature_settings(device, already_known) -> bool:\n    \"\"\"Auto-detect device settings by the HID++ 2.0 features they have.\n\n    Returns\n    -------\n    bool\n        True, if device was fully queried to find features, False otherwise.\n    \"\"\"\n    if not device.features or not device.online:\n        return False\n    if device.protocol and device.protocol < 2.0:\n        return False\n    absent = device.persister.get(\"_absent\", []) if device.persister else []\n    new_absent = []\n    for sclass in SETTINGS:\n        if sclass.feature:\n            known_present = device.persister and sclass.name in device.persister\n            if not any(s.name == sclass.name for s in already_known) and (known_present or sclass.name not in absent):\n                try:\n                    setting = check_feature(device, sclass)\n                except Exception as err:\n                    # on an internal HID++ error, assume offline and stop further checking\n                    if (\n                        isinstance(err, exceptions.FeatureCallError)\n                        and err.error == hidpp20_constants.ErrorCode.LOGITECH_ERROR\n                    ):\n                        logger.warning(f\"HID++ internal error checking feature {sclass.name}: make device not present\")\n                        device.online = False\n                        device.present = False\n                        return False\n                    else:\n                        logger.warning(f\"ignore feature {sclass.name} because of error {err}\")\n\n                if isinstance(setting, list):\n                    for s in setting:\n                        already_known.append(s)\n                    if sclass.name in new_absent:\n                        new_absent.remove(sclass.name)\n                elif setting:\n                    already_known.append(setting)\n                    if sclass.name in new_absent:\n                        new_absent.remove(sclass.name)\n                elif setting is None:\n                    if sclass.name not in new_absent and sclass.name not in absent and sclass.name not in device.persister:\n                        new_absent.append(sclass.name)\n    if device.persister and new_absent:\n        absent.extend(new_absent)\n        device.persister[\"_absent\"] = absent\n    return True\n\n\ndef check_feature_setting(device, setting_name: str) -> settings.Setting | None:\n    for sclass in SETTINGS:\n        if (\n            sclass.feature\n            and device.features\n            and (sclass.name == setting_name or sclass.name.endswith(\"_\") and setting_name.startswith(sclass.name))\n        ):\n            try:\n                setting = check_feature(device, sclass)\n            except Exception:\n                return None\n            if isinstance(setting, list):\n                for s in setting:\n                    if s.name == setting_name:\n                        return s\n            elif setting:\n                return setting\n"
  },
  {
    "path": "lib/logitech_receiver/settings_validator.py",
    "content": "from __future__ import annotations\n\nimport logging\nimport math\n\nfrom enum import IntEnum\n\nfrom logitech_receiver import common\nfrom logitech_receiver.common import NamedInt\nfrom logitech_receiver.common import NamedInts\n\nlogger = logging.getLogger(__name__)\n\n\ndef bool_or_toggle(current: bool | str, new: bool | str) -> bool:\n    if isinstance(new, bool):\n        return new\n\n    try:\n        return bool(int(new))\n    except (TypeError, ValueError):\n        new = str(new).lower()\n\n    if new in (\"true\", \"yes\", \"on\", \"t\", \"y\"):\n        return True\n    if new in (\"false\", \"no\", \"off\", \"f\", \"n\"):\n        return False\n    if new in (\"~\", \"toggle\"):\n        return not current\n    return None\n\n\nclass Kind(IntEnum):\n    TOGGLE = 0x01\n    CHOICE = 0x02\n    RANGE = 0x04\n    MAP_CHOICE = 0x0A\n    MULTIPLE_TOGGLE = 0x10\n    PACKED_RANGE = 0x20\n    MULTIPLE_RANGE = 0x40\n    HETERO = 0x80\n\n\nclass Validator:\n    @classmethod\n    def build(cls, setting_class, device, **kwargs) -> Validator:\n        return cls(**kwargs)\n\n    @classmethod\n    def to_string(cls, value) -> str:\n        return str(value)\n\n    def compare(self, args, current):\n        if len(args) != 1:\n            return False\n        return args[0] == current\n\n\nclass BooleanValidator(Validator):\n    __slots__ = (\"true_value\", \"false_value\", \"read_skip_byte_count\", \"write_prefix_bytes\", \"mask\", \"needs_current_value\")\n\n    kind = Kind.TOGGLE\n    default_true = 0x01\n    default_false = 0x00\n    # mask specifies all the affected bits in the value\n    default_mask = 0xFF\n\n    def __init__(\n        self,\n        true_value=default_true,\n        false_value=default_false,\n        mask=default_mask,\n        read_skip_byte_count=0,\n        write_prefix_bytes=b\"\",\n    ):\n        if isinstance(true_value, int):\n            assert isinstance(false_value, int)\n            if mask is None:\n                mask = self.default_mask\n            else:\n                assert isinstance(mask, int)\n            assert true_value & false_value == 0\n            assert true_value & mask == true_value\n            assert false_value & mask == false_value\n            self.needs_current_value = mask != self.default_mask\n        elif isinstance(true_value, bytes):\n            if false_value is None or false_value == self.default_false:\n                false_value = b\"\\x00\" * len(true_value)\n            else:\n                assert isinstance(false_value, bytes)\n            if mask is None or mask == self.default_mask:\n                mask = b\"\\xff\" * len(true_value)\n            else:\n                assert isinstance(mask, bytes)\n            assert len(mask) == len(true_value) == len(false_value)\n            tv = common.bytes2int(true_value)\n            fv = common.bytes2int(false_value)\n            mv = common.bytes2int(mask)\n            assert tv != fv  # true and false might be something other than bit values\n            assert tv & mv == tv\n            assert fv & mv == fv\n            self.needs_current_value = any(m != 0xFF for m in mask)\n        else:\n            raise Exception(f\"invalid mask '{mask!r}', type {type(mask)}\")\n\n        self.true_value = true_value\n        self.false_value = false_value\n        self.mask = mask\n        self.read_skip_byte_count = read_skip_byte_count\n        self.write_prefix_bytes = write_prefix_bytes\n\n    def validate_read(self, reply_bytes):\n        reply_bytes = reply_bytes[self.read_skip_byte_count :]\n        if isinstance(self.mask, int):\n            reply_value = ord(reply_bytes[:1]) & self.mask\n            if logger.isEnabledFor(logging.DEBUG):\n                logger.debug(\"BooleanValidator: validate read %r => %02X\", reply_bytes, reply_value)\n            if reply_value == self.true_value:\n                return True\n            if reply_value == self.false_value:\n                return False\n            logger.warning(\n                \"BooleanValidator: reply %02X mismatched %02X/%02X/%02X\",\n                reply_value,\n                self.true_value,\n                self.false_value,\n                self.mask,\n            )\n            return False\n\n        count = len(self.mask)\n        mask = common.bytes2int(self.mask)\n        reply_value = common.bytes2int(reply_bytes[:count]) & mask\n\n        true_value = common.bytes2int(self.true_value)\n        if reply_value == true_value:\n            return True\n\n        false_value = common.bytes2int(self.false_value)\n        if reply_value == false_value:\n            return False\n\n        logger.warning(\n            \"BooleanValidator: reply %r mismatched %r/%r/%r\", reply_bytes, self.true_value, self.false_value, self.mask\n        )\n        return False\n\n    def prepare_write(self, new_value, current_value=None):\n        if new_value is None:\n            new_value = False\n        else:\n            assert isinstance(new_value, bool), f\"New value {new_value} for boolean setting is not a boolean\"\n\n        to_write = self.true_value if new_value else self.false_value\n\n        if isinstance(self.mask, int):\n            if current_value is not None and self.needs_current_value:\n                to_write |= ord(current_value[:1]) & (0xFF ^ self.mask)\n            if current_value is not None and to_write == ord(current_value[:1]):\n                return None\n            to_write = bytes([to_write])\n        else:\n            to_write = bytearray(to_write)\n            count = len(self.mask)\n            for i in range(0, count):\n                b = ord(to_write[i : i + 1])\n                m = ord(self.mask[i : i + 1])\n                assert b & m == b\n                # b &= m\n                if current_value is not None and self.needs_current_value:\n                    b |= ord(current_value[i : i + 1]) & (0xFF ^ m)\n                to_write[i] = b\n            to_write = bytes(to_write)\n\n            if current_value is not None and to_write == current_value[: len(to_write)]:\n                return None\n\n        if logger.isEnabledFor(logging.DEBUG):\n            logger.debug(\"BooleanValidator: prepare_write(%s, %s) => %r\", new_value, current_value, to_write)\n\n        return self.write_prefix_bytes + to_write\n\n    def acceptable(self, args, current):\n        if len(args) != 1:\n            return None\n        val = bool_or_toggle(current, args[0])\n        return [val] if val is not None else None\n\n\nclass BitFieldValidator(Validator):\n    __slots__ = (\"byte_count\", \"options\")\n\n    kind = Kind.MULTIPLE_TOGGLE\n\n    def __init__(self, options, byte_count=None):\n        assert isinstance(options, list)\n        self.options = options\n        self.byte_count = (max(x.bit_length() for x in options) + 7) // 8\n        if byte_count:\n            assert isinstance(byte_count, int) and byte_count >= self.byte_count\n            self.byte_count = byte_count\n\n    def to_string(self, value) -> str:\n        def element_to_string(key, val):\n            k = next((k for k in self.options if int(key) == k), None)\n            return str(k) + \":\" + str(val) if k is not None else \"?\"\n\n        return \"{\" + \", \".join([element_to_string(k, value[k]) for k in value]) + \"}\"\n\n    def validate_read(self, reply_bytes):\n        r = common.bytes2int(reply_bytes[: self.byte_count])\n        value = {int(k): False for k in self.options}\n        m = 1\n        for _ignore in range(8 * self.byte_count):\n            if m in self.options:\n                value[int(m)] = bool(r & m)\n            m <<= 1\n        return value\n\n    def prepare_write(self, new_value):\n        assert isinstance(new_value, dict)\n        w = 0\n        for k, v in new_value.items():\n            if v:\n                w |= int(k)\n        return common.int2bytes(w, self.byte_count)\n\n    def get_options(self):\n        return self.options\n\n    def acceptable(self, args, current):\n        if len(args) != 2:\n            return None\n        key = next((key for key in self.options if key == args[0]), None)\n        if key is None:\n            return None\n        val = bool_or_toggle(current[int(key)], args[1])\n        return None if val is None else [int(key), val]\n\n    def compare(self, args, current):\n        if len(args) != 2:\n            return False\n        key = next((key for key in self.options if key == args[0]), None)\n        if key is None:\n            return False\n        return args[1] == current[int(key)]\n\n\nclass BitFieldWithOffsetAndMaskValidator(Validator):\n    __slots__ = (\"byte_count\", \"options\", \"_option_from_key\", \"_mask_from_offset\", \"_option_from_offset_mask\")\n\n    kind = Kind.MULTIPLE_TOGGLE\n    sep = 0x01\n\n    def __init__(self, options, om_method=None, byte_count=None):\n        assert isinstance(options, list)\n        # each element of options is an instance of a class\n        # that has an id (which is used as an index in other dictionaries)\n        # and where om_method is a method that returns a byte offset and byte mask\n        # that says how to access and modify the bit toggle for the option\n        self.options = options\n        self.om_method = om_method\n        # to retrieve the options efficiently:\n        self._option_from_key = {}\n        self._mask_from_offset = {}\n        self._option_from_offset_mask = {}\n        for opt in options:\n            offset, mask = om_method(opt)\n            self._option_from_key[int(opt)] = opt\n            try:\n                self._mask_from_offset[offset] |= mask\n            except KeyError:\n                self._mask_from_offset[offset] = mask\n            try:\n                mask_to_opt = self._option_from_offset_mask[offset]\n            except KeyError:\n                mask_to_opt = {}\n                self._option_from_offset_mask[offset] = mask_to_opt\n            mask_to_opt[mask] = opt\n        self.byte_count = (max(om_method(x)[1].bit_length() for x in options) + 7) // 8  # is this correct??\n        if byte_count:\n            assert isinstance(byte_count, int) and byte_count >= self.byte_count\n            self.byte_count = byte_count\n\n    def prepare_read(self):\n        r = []\n        for offset, mask in self._mask_from_offset.items():\n            b = offset << (8 * (self.byte_count + 1))\n            b |= (self.sep << (8 * self.byte_count)) | mask\n            r.append(common.int2bytes(b, self.byte_count + 2))\n        return r\n\n    def prepare_read_key(self, key):\n        option = self._option_from_key.get(key, None)\n        if option is None:\n            return None\n        offset, mask = option.om_method(option)\n        b = offset << (8 * (self.byte_count + 1))\n        b |= (self.sep << (8 * self.byte_count)) | mask\n        return common.int2bytes(b, self.byte_count + 2)\n\n    def validate_read(self, reply_bytes_dict):\n        values = {int(k): False for k in self.options}\n        for query, b in reply_bytes_dict.items():\n            offset = common.bytes2int(query[0:1])\n            b += (self.byte_count - len(b)) * b\"\\x00\"\n            value = common.bytes2int(b[: self.byte_count])\n            mask_to_opt = self._option_from_offset_mask.get(offset, {})\n            m = 1\n            for _ignore in range(8 * self.byte_count):\n                if m in mask_to_opt:\n                    values[int(mask_to_opt[m])] = bool(value & m)\n                m <<= 1\n        return values\n\n    def prepare_write(self, new_value):\n        assert isinstance(new_value, dict)\n        w = {}\n        for k, v in new_value.items():\n            option = self._option_from_key[int(k)]\n            offset, mask = self.om_method(option)\n            if offset not in w:\n                w[offset] = 0\n            if v:\n                w[offset] |= mask\n        return [\n            common.int2bytes(\n                (offset << (8 * (2 * self.byte_count + 1)))\n                | (self.sep << (16 * self.byte_count))\n                | (self._mask_from_offset[offset] << (8 * self.byte_count))\n                | value,\n                2 * self.byte_count + 2,\n            )\n            for offset, value in w.items()\n        ]\n\n    def get_options(self):\n        return [int(opt) if isinstance(opt, int) else opt.as_int() for opt in self.options]\n\n    def acceptable(self, args, current):\n        if len(args) != 2:\n            return None\n        key = next((option.id for option in self.options if option.as_int() == args[0]), None)\n        if key is None:\n            return None\n        val = bool_or_toggle(current[int(key)], args[1])\n        return None if val is None else [int(key), val]\n\n    def compare(self, args, current):\n        if len(args) != 2:\n            return False\n        key = next((option.id for option in self.options if option.as_int() == args[0]), None)\n        if key is None:\n            return False\n        return args[1] == current[int(key)]\n\n\nclass ChoicesValidator(Validator):\n    \"\"\"Translates between NamedInts and a byte sequence.\n    :param choices: a list of NamedInts\n    :param byte_count: the size of the derived byte sequence. If None, it\n    will be calculated from the choices.\"\"\"\n\n    kind = Kind.CHOICE\n\n    def __init__(self, choices=None, byte_count=None, read_skip_byte_count=0, write_prefix_bytes=b\"\"):\n        assert choices is not None\n        assert isinstance(choices, NamedInts)\n        assert len(choices) > 1\n        self.choices = choices\n        self.needs_current_value = False\n\n        max_bits = max(x.bit_length() for x in choices)\n        self._byte_count = (max_bits // 8) + (1 if max_bits % 8 else 0)\n        if byte_count:\n            assert self._byte_count <= byte_count\n            self._byte_count = byte_count\n        assert self._byte_count < 8\n        self._read_skip_byte_count = read_skip_byte_count\n        self._write_prefix_bytes = write_prefix_bytes if write_prefix_bytes else b\"\"\n        assert self._byte_count + self._read_skip_byte_count <= 14\n        assert self._byte_count + len(self._write_prefix_bytes) <= 14\n\n    def to_string(self, value) -> str:\n        return str(self.choices[value]) if isinstance(value, int) else str(value)\n\n    def validate_read(self, reply_bytes):\n        reply_value = common.bytes2int(reply_bytes[self._read_skip_byte_count : self._read_skip_byte_count + self._byte_count])\n        valid_value = self.choices[reply_value]\n        assert valid_value is not None, f\"{self.__class__.__name__}: failed to validate read value {reply_value:02X}\"\n        return valid_value\n\n    def prepare_write(self, new_value, current_value=None):\n        if new_value is None:\n            value = self.choices[:][0]\n        else:\n            value = self.choice(new_value)\n        if value is None:\n            raise ValueError(f\"invalid choice {new_value!r}\")\n        assert isinstance(value, NamedInt)\n        return self._write_prefix_bytes + value.bytes(self._byte_count)\n\n    def choice(self, value):\n        if isinstance(value, int):\n            return self.choices[value]\n        try:\n            int(value)\n            if int(value) in self.choices:\n                return self.choices[int(value)]\n        except Exception:\n            pass\n        if value in self.choices:\n            return self.choices[value]\n        else:\n            return None\n\n    def acceptable(self, args, current):\n        choice = self.choice(args[0]) if len(args) == 1 else None\n        return None if choice is None else [choice]\n\n\nclass ChoicesMapValidator(ChoicesValidator):\n    kind = Kind.MAP_CHOICE\n\n    def __init__(\n        self,\n        choices_map,\n        key_byte_count=0,\n        key_postfix_bytes=b\"\",\n        byte_count=0,\n        read_skip_byte_count=0,\n        write_prefix_bytes=b\"\",\n        extra_default=None,\n        mask=-1,\n        activate=0,\n    ):\n        assert choices_map is not None\n        assert isinstance(choices_map, dict)\n        max_key_bits = 0\n        max_value_bits = 0\n        for key, choices in choices_map.items():\n            assert isinstance(key, NamedInt)\n            assert isinstance(choices, NamedInts)\n            max_key_bits = max(max_key_bits, key.bit_length())\n            for key_value in choices:\n                assert isinstance(key_value, NamedInt)\n                max_value_bits = max(max_value_bits, key_value.bit_length())\n        self._key_byte_count = (max_key_bits + 7) // 8\n        if key_byte_count:\n            assert self._key_byte_count <= key_byte_count\n            self._key_byte_count = key_byte_count\n        self._byte_count = (max_value_bits + 7) // 8\n        if byte_count:\n            assert self._byte_count <= byte_count\n            self._byte_count = byte_count\n\n        self.choices = choices_map\n        self.needs_current_value = False\n        self.extra_default = extra_default\n        self._key_postfix_bytes = key_postfix_bytes\n        self._read_skip_byte_count = read_skip_byte_count if read_skip_byte_count else 0\n        self._write_prefix_bytes = write_prefix_bytes if write_prefix_bytes else b\"\"\n        self.activate = activate\n        self.mask = mask\n        assert self._byte_count + self._read_skip_byte_count + self._key_byte_count <= 14\n        assert self._byte_count + len(self._write_prefix_bytes) + self._key_byte_count <= 14\n\n    def to_string(self, value) -> str:\n        def element_to_string(key, val):\n            k, c = next(((k, c) for k, c in self.choices.items() if int(key) == k), (None, None))\n            return str(k) + \":\" + str(c[val]) if k is not None else \"?\"\n\n        return \"{\" + \", \".join([element_to_string(k, value[k]) for k in sorted(value)]) + \"}\"\n\n    def validate_read(self, reply_bytes, key):\n        start = self._key_byte_count + self._read_skip_byte_count\n        end = start + self._byte_count\n        reply_value = common.bytes2int(reply_bytes[start:end]) & self.mask\n        # reprogrammable keys starts out as 0, which is not a choice, so don't use assert here\n        if self.extra_default is not None and self.extra_default == reply_value:\n            return int(self.choices[key][0])\n        if reply_value not in self.choices[key]:\n            assert reply_value in self.choices[key], \"%s: failed to validate read value %02X\" % (\n                self.__class__.__name__,\n                reply_value,\n            )\n        return reply_value\n\n    def prepare_key(self, key):\n        return key.to_bytes(self._key_byte_count, \"big\") + self._key_postfix_bytes\n\n    def prepare_write(self, key, new_value):\n        choices = self.choices.get(key)\n        if choices is None or (new_value not in choices and new_value != self.extra_default):\n            logger.error(\"invalid choice %r for %s\", new_value, key)\n            return None\n        new_value = new_value | self.activate\n        return self._write_prefix_bytes + new_value.to_bytes(self._byte_count, \"big\")\n\n    def acceptable(self, args, current):\n        if len(args) != 2:\n            return None\n        key, choices = next(((key, item) for key, item in self.choices.items() if key == args[0]), (None, None))\n        if choices is None or args[1] not in choices:\n            return None\n        choice = next((item for item in choices if item == args[1]), None)\n        return [int(key), int(choice)] if choice is not None else None\n\n    def compare(self, args, current):\n        if len(args) != 2:\n            return False\n        key = next((key for key in self.choices if key == int(args[0])), None)\n        if key is None:\n            return False\n        return args[1] == current[int(key)]\n\n\nclass RangeValidator(Validator):\n    kind = Kind.RANGE\n    \"\"\"Translates between integers and a byte sequence.\n    :param min_value: minimum accepted value (inclusive)\n    :param max_value: maximum accepted value (inclusive)\n    :param byte_count: the size of the derived byte sequence. If None, it\n    will be calculated from the range.\"\"\"\n    min_value = 0\n    max_value = 255\n\n    @classmethod\n    def build(cls, setting_class, device, **kwargs):\n        kwargs[\"min_value\"] = setting_class.min_value\n        kwargs[\"max_value\"] = setting_class.max_value\n        return cls(**kwargs)\n\n    def __init__(self, min_value=0, max_value=255, byte_count=1, read_skip_byte_count=0, write_prefix_bytes=b\"\"):\n        assert max_value > min_value\n        self.min_value = min_value\n        self.max_value = max_value\n        self.read_skip_byte_count = read_skip_byte_count\n        self.write_prefix_bytes = write_prefix_bytes\n        self.needs_current_value = True  # read and check before write (needed for ADC power and probably a good idea anyway)\n        self._byte_count = math.ceil(math.log(max_value + 1, 256))\n        if byte_count:\n            assert self._byte_count <= byte_count\n            self._byte_count = byte_count\n        assert self._byte_count < 8\n\n    def validate_read(self, reply_bytes):\n        reply_value = common.bytes2int(reply_bytes[self.read_skip_byte_count : self.read_skip_byte_count + self._byte_count])\n        assert reply_value >= self.min_value, f\"{self.__class__.__name__}: failed to validate read value {reply_value:02X}\"\n        assert reply_value <= self.max_value, f\"{self.__class__.__name__}: failed to validate read value {reply_value:02X}\"\n        return reply_value\n\n    def prepare_write(self, new_value, current_value=None):\n        if new_value < self.min_value or new_value > self.max_value:\n            raise ValueError(f\"invalid choice {new_value!r}\")\n        current_value = self.validate_read(current_value) if current_value is not None else None\n        to_write = self.write_prefix_bytes + common.int2bytes(new_value, self._byte_count)\n        # current value is known and same as value to be written return None to signal not to write it\n        return None if current_value is not None and current_value == new_value else to_write\n\n    def acceptable(self, args, current):\n        arg = args[0]\n        #  None if len(args) != 1 or type(arg) != int or arg < self.min_value or arg > self.max_value else args)\n        return None if len(args) != 1 or isinstance(arg, int) or arg < self.min_value or arg > self.max_value else args\n\n    def compare(self, args, current):\n        if len(args) == 1:\n            return args[0] == current\n        elif len(args) == 2:\n            return args[0] <= current <= args[1]\n        else:\n            return False\n\n\nclass HeteroValidator(Validator):\n    kind = Kind.HETERO\n\n    @classmethod\n    def build(cls, setting_class, device, **kwargs):\n        return cls(**kwargs)\n\n    def __init__(self, data_class=None, options=None, readable=True):\n        assert data_class is not None and options is not None\n        self.data_class = data_class\n        self.options = options\n        self.readable = readable\n        self.needs_current_value = False\n\n    def validate_read(self, reply_bytes):\n        if self.readable:\n            reply_value = self.data_class.from_bytes(reply_bytes, options=self.options)\n            return reply_value\n\n    def prepare_write(self, new_value, current_value=None):\n        to_write = new_value.to_bytes(options=self.options)\n        return to_write\n\n    def acceptable(self, args, current):  # should this actually do some checking?\n        return True\n\n\nclass PackedRangeValidator(Validator):\n    kind = Kind.PACKED_RANGE\n    \"\"\"Several range values, all the same size, all the same min and max\"\"\"\n    min_value = 0\n    max_value = 255\n    count = 1\n    rsbc = 0\n    write_prefix_bytes = b\"\"\n\n    def __init__(\n        self, keys, min_value=0, max_value=255, count=1, byte_count=1, read_skip_byte_count=0, write_prefix_bytes=b\"\"\n    ):\n        assert max_value > min_value\n        self.needs_current_value = True\n        self.keys = keys\n        self.min_value = min_value\n        self.max_value = max_value\n        self.count = count\n        self.bc = math.ceil(math.log(max_value + 1 - min(0, min_value), 256))\n        if byte_count:\n            assert self.bc <= byte_count\n            self.bc = byte_count\n        assert self.bc * self.count\n        self.rsbc = read_skip_byte_count\n        self.write_prefix_bytes = write_prefix_bytes\n\n    def validate_read(self, reply_bytes):\n        rvs = {\n            n: common.bytes2int(reply_bytes[self.rsbc + n * self.bc : self.rsbc + (n + 1) * self.bc], signed=True)\n            for n in range(self.count)\n        }\n        for n in range(self.count):\n            assert rvs[n] >= self.min_value, f\"{self.__class__.__name__}: failed to validate read value {rvs[n]:02X}\"\n            assert rvs[n] <= self.max_value, f\"{self.__class__.__name__}: failed to validate read value {rvs[n]:02X}\"\n        return rvs\n\n    def prepare_write(self, new_values):\n        if len(new_values) != self.count:\n            raise ValueError(f\"wrong number of values {new_values!r}\")\n        for new_value in new_values.values():\n            if new_value < self.min_value or new_value > self.max_value:\n                raise ValueError(f\"invalid value {new_value!r}\")\n        bytes = self.write_prefix_bytes + b\"\".join(\n            common.int2bytes(new_values[n], self.bc, signed=True) for n in range(self.count)\n        )\n        return bytes\n\n    def acceptable(self, args, current):\n        if len(args) != 2 or int(args[0]) < 0 or int(args[0]) >= self.count:\n            return None\n        return None if not isinstance(args[1], int) or args[1] < self.min_value or args[1] > self.max_value else args\n\n    def compare(self, args, current):\n        logger.warning(\"compare not implemented for packed range settings\")\n        return False\n\n\nclass MultipleRangeValidator(Validator):\n    kind = Kind.MULTIPLE_RANGE\n\n    def __init__(self, items, sub_items):\n        assert isinstance(items, list)  # each element must have .index and its __int__ must return its id (not its index)\n        assert isinstance(sub_items, dict)\n        # sub_items: items -> class with .minimum, .maximum, .length (in bytes), .id (a string) and .widget (e.g. 'Scale')\n        self.items = items\n        self.keys = NamedInts(**{str(item): int(item) for item in items})\n        self._item_from_id = {int(k): k for k in items}\n        self.sub_items = sub_items\n\n    def prepare_read_item(self, item):\n        return common.int2bytes((self._item_from_id[int(item)].index << 1) | 0xFF, 2)\n\n    def validate_read_item(self, reply_bytes, item):\n        item = self._item_from_id[int(item)]\n        start = 0\n        value = {}\n        for sub_item in self.sub_items[item]:\n            r = reply_bytes[start : start + sub_item.length]\n            if len(r) < sub_item.length:\n                r += b\"\\x00\" * (sub_item.length - len(value))\n            v = common.bytes2int(r)\n            if not (sub_item.minimum < v < sub_item.maximum):\n                logger.warning(\n                    f\"{self.__class__.__name__}: failed to validate read value for {item}.{sub_item}: \"\n                    + f\"{v} not in [{sub_item.minimum}..{sub_item.maximum}]\"\n                )\n            value[str(sub_item)] = v\n            start += sub_item.length\n        return value\n\n    def prepare_write(self, value):\n        seq = []\n        w = b\"\"\n        for item in value.keys():\n            _item = self._item_from_id[int(item)]\n            b = common.int2bytes(_item.index, 1)\n            for sub_item in self.sub_items[_item]:\n                try:\n                    v = value[int(item)][str(sub_item)]\n                except KeyError:\n                    return None\n                if not (sub_item.minimum <= v <= sub_item.maximum):\n                    raise ValueError(\n                        f\"invalid choice for {item}.{sub_item}: {v} not in [{sub_item.minimum}..{sub_item.maximum}]\"\n                    )\n                b += common.int2bytes(v, sub_item.length)\n            if len(w) + len(b) > 15:\n                seq.append(b + b\"\\xff\")\n                w = b\"\"\n            w += b\n        seq.append(w + b\"\\xff\")\n        return seq\n\n    def prepare_write_item(self, item, value):\n        _item = self._item_from_id[int(item)]\n        w = common.int2bytes(_item.index, 1)\n        for sub_item in self.sub_items[_item]:\n            try:\n                v = value[str(sub_item)]\n            except KeyError:\n                return None\n            if not (sub_item.minimum <= v <= sub_item.maximum):\n                raise ValueError(f\"invalid choice for {item}.{sub_item}: {v} not in [{sub_item.minimum}..{sub_item.maximum}]\")\n            w += common.int2bytes(v, sub_item.length)\n        return w + b\"\\xff\"\n\n    def acceptable(self, args, current):\n        # just one item, with at least one sub-item\n        if not isinstance(args, list) or len(args) != 2 or not isinstance(args[1], dict):\n            return None\n        item = next((p for p in self.items if p.id == args[0] or str(p) == args[0]), None)\n        if not item:\n            return None\n        for sub_key, value in args[1].items():\n            sub_item = next((it for it in self.sub_items[item] if it.id == sub_key), None)\n            if not sub_item:\n                return None\n            if not isinstance(value, int) or not (sub_item.minimum <= value <= sub_item.maximum):\n                return None\n        return [int(item), {**args[1]}]\n\n    def compare(self, args, current):\n        logger.warning(\"compare not implemented for multiple range settings\")\n        return False\n"
  },
  {
    "path": "lib/logitech_receiver/special_keys.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n# Reprogrammable keys information\n# Mostly from Logitech documentation, but with some edits for better Linux compatibility\n\nimport os\n\nfrom enum import IntEnum\n\nimport yaml\n\nfrom .common import NamedInts\nfrom .common import UnsortedNamedInts\n\n_XDG_CONFIG_HOME = os.environ.get(\"XDG_CONFIG_HOME\") or os.path.expanduser(os.path.join(\"~\", \".config\"))\n_keys_file_path = os.path.join(_XDG_CONFIG_HOME, \"solaar\", \"keys.yaml\")\n\n\n# Original set done as\n# <controls.xml awk -F\\\" '/<Control /{sub(/^LD_FINFO_(CTRLID_)?/, \"\", $2);printf(\"\\t%s=0x%04X,\\n\", $2, $4)}' | sort -t= -k2\n# Keys added afterwards based on information from Logitech and users\nCONTROL = NamedInts(\n    {\n        \"Volume_Up_old\": 0x0001,\n        \"Volume_Down_old\": 0x0002,\n        \"Mute\": 0x0003,\n        \"Play__Pause_old\": 0x0004,\n        \"Next\": 0x0005,\n        \"Previous\": 0x0006,\n        \"Stop\": 0x0007,\n        \"Application_Switcher\": 0x0008,\n        \"Burn\": 0x0009,\n        \"Calculator\": 0x000A,  # Craft Keyboard top 4th from right; Logitech\n        \"Calendar\": 0x000B,\n        \"Close\": 0x000C,\n        \"Eject\": 0x000D,\n        \"Mail\": 0x000E,\n        \"Help_As_HID\": 0x000F,\n        \"Help_As_F1\": 0x0010,\n        \"Launch_Word_Proc\": 0x0011,\n        \"Launch_Spreadsheet\": 0x0012,\n        \"Launch_Presentation\": 0x0013,\n        \"Undo_As_Ctrl_Z\": 0x0014,\n        \"Undo_As_HID\": 0x0015,\n        \"Redo_As_Ctrl_Y\": 0x0016,\n        \"Redo_As_HID\": 0x0017,\n        \"Print_As_Ctrl_P\": 0x0018,  # Logitech, modified\n        \"Print_As_HID\": 0x0019,\n        \"Save_As_Ctrl_S\": 0x001A,\n        \"Save_As_HID\": 0x001B,\n        \"Preset_A\": 0x001C,\n        \"Preset_B\": 0x001D,\n        \"Preset_C\": 0x001E,\n        \"Preset_D\": 0x001F,\n        \"Favorites\": 0x0020,\n        \"Gadgets\": 0x0021,\n        \"My_Home\": 0x0022,\n        \"Gadgets_As_Win_G\": 0x0023,\n        \"Maximize_As_HID\": 0x0024,\n        \"Maximize_As_Win_Shift_M\": 0x0025,\n        \"Minimize_As_HID\": 0x0026,\n        \"Minimize_As_Win_M\": 0x0027,\n        \"Media_Player\": 0x0028,\n        \"Media_Center_Logi\": 0x0029,\n        \"Media_Center_Msft\": 0x002A,  # Should not be used as it is not reprogrammable under Windows\n        \"Custom_Menu\": 0x002B,\n        \"Messenger\": 0x002C,\n        \"My_Documents\": 0x002D,\n        \"My_Music\": 0x002E,\n        \"Webcam\": 0x002F,\n        \"My_Pictures\": 0x0030,\n        \"My_Videos\": 0x0031,\n        \"My_Computer_As_HID\": 0x0032,\n        \"My_Computer_As_Win_E\": 0x0033,\n        \"FN_Key\": 0x0034,\n        \"Launch_Picture_Viewer\": 0x0035,\n        \"One_Touch_Search\": 0x0036,\n        \"Preset_1\": 0x0037,\n        \"Preset_2\": 0x0038,\n        \"Preset_3\": 0x0039,\n        \"Preset_4\": 0x003A,\n        \"Record\": 0x003B,\n        \"Internet_Refresh\": 0x003C,\n        \"Search\": 0x003E,  # SEARCH\n        \"Shuffle\": 0x003F,\n        \"Sleep\": 0x0040,\n        \"Internet_Stop\": 0x0041,\n        \"Synchronize\": 0x0042,\n        \"Zoom\": 0x0043,\n        \"Zoom_In_As_HID\": 0x0044,\n        \"Zoom_In_As_Ctrl_Wheel\": 0x0045,\n        \"Zoom_In_As_Cltr_Plus\": 0x0046,\n        \"Zoom_Out_As_HID\": 0x0047,\n        \"Zoom_Out_As_Ctrl_Wheel\": 0x0048,\n        \"Zoom_Out_As_Ctrl_Minus\": 0x0049,\n        \"Zoom_Reset\": 0x004A,\n        \"Zoom_Full_Screen\": 0x004B,\n        \"Print_Screen\": 0x004C,\n        \"Pause_Break\": 0x004D,\n        \"Scroll_Lock\": 0x004E,\n        \"Contextual_Menu\": 0x004F,\n        \"Left_Button\": 0x0050,  # LEFT_CLICK; Logitech\n        \"Right_Button\": 0x0051,  # RIGHT_CLICK; Logitech\n        \"Middle_Button\": 0x0052,  # MIDDLE_BUTTON; Logitech\n        \"Back_Button\": 0x0053,  # from M510v2 was BACK_AS_BUTTON_4; Logitech\n        \"Back\": 0x0054,  # BACK_AS_HID\n        \"Back_As_Alt_Win_Arrow\": 0x0055,\n        \"Forward_Button\": 0x0056,  # from M510v2 was FORWARD_AS_BUTTON_5; Logitech\n        \"Forward_As_HID\": 0x0057,\n        \"Forward_As_Alt_Win_Arrow\": 0x0058,\n        \"Button_6\": 0x0059,\n        \"Left_Scroll_As_Button_7\": 0x005A,\n        \"Left_Tilt\": 0x005B,  # from M510v2 was LEFT_SCROLL_AS_AC_PAN\n        \"Right_Scroll_As_Button_8\": 0x005C,\n        \"Right_Tilt\": 0x005D,  # from M510v2 was RIGHT_SCROLL_AS_AC_PAN\n        \"Button_9\": 0x005E,\n        \"Button_10\": 0x005F,\n        \"Button_11\": 0x0060,\n        \"Button_12\": 0x0061,\n        \"Button_13\": 0x0062,\n        \"Button_14\": 0x0063,\n        \"Button_15\": 0x0064,\n        \"Button_16\": 0x0065,\n        \"Button_17\": 0x0066,\n        \"Button_18\": 0x0067,\n        \"Button_19\": 0x0068,\n        \"Button_20\": 0x0069,\n        \"Button_21\": 0x006A,\n        \"Button_22\": 0x006B,\n        \"Button_23\": 0x006C,\n        \"Button_24\": 0x006D,\n        \"Show_Desktop\": 0x006E,  # Craft Keyboard Fn F5; Logitch\n        \"Screen_Lock\": 0x006F,  # Craft Keyboard top 1st from right; Logitech\n        \"Fn_F1\": 0x0070,\n        \"Fn_F2\": 0x0071,\n        \"Fn_F3\": 0x0072,\n        \"Fn_F4\": 0x0073,\n        \"Fn_F5\": 0x0074,\n        \"Fn_F6\": 0x0075,\n        \"Fn_F7\": 0x0076,\n        \"Fn_F8\": 0x0077,\n        \"Fn_F9\": 0x0078,\n        \"Fn_F10\": 0x0079,\n        \"Fn_F11\": 0x007A,\n        \"Fn_F12\": 0x007B,\n        \"Fn_F13\": 0x007C,\n        \"Fn_F14\": 0x007D,\n        \"Fn_F15\": 0x007E,\n        \"Fn_F16\": 0x007F,\n        \"Fn_F17\": 0x0080,\n        \"Fn_F18\": 0x0081,\n        \"Fn_F19\": 0x0082,\n        \"IOS_Home\": 0x0083,\n        \"Android_Home\": 0x0084,\n        \"Android_Menu\": 0x0085,\n        \"Android_Search\": 0x0086,\n        \"Android_Back\": 0x0087,\n        \"Home_Combo\": 0x0088,\n        \"Lock_Combo\": 0x0089,\n        \"IOS_Virtual_Keyboard\": 0x008A,\n        \"IOS_Language_Switch\": 0x008B,\n        \"Mac_Expose\": 0x008C,\n        \"Mac_Dashboard\": 0x008D,\n        \"Win7_Snap_Left\": 0x008E,\n        \"Win7_Snap_Right\": 0x008F,\n        \"Minimize_Window\": 0x0090,  # WIN7_MINIMIZE_AS_WIN_ARROW\n        \"Maximize_Window\": 0x0091,  # WIN7_MAXIMIZE_AS_WIN_ARROW\n        \"Win7_Stretch_Up\": 0x0092,\n        \"Win7_Monitor_Switch_As_Win_Shift_LeftArrow\": 0x0093,\n        \"Win7_Monitor_Switch_As_Win_Shift_RightArrow\": 0x0094,\n        \"Switch_Screen\": 0x0095,  # WIN7_SHOW_PRESENTATION_MODE\n        \"Win7_Show_Mobility_Center\": 0x0096,\n        \"Analog_HScroll\": 0x0097,\n        \"Metro_Appswitch\": 0x009F,\n        \"Metro_Appbar\": 0x00A0,\n        \"Metro_Charms\": 0x00A1,\n        \"Calc_Vkeyboard\": 0x00A2,\n        \"Metro_Search\": 0x00A3,\n        \"Combo_Sleep\": 0x00A4,\n        \"Metro_Share\": 0x00A5,\n        \"OS_Settings\": 0x00A6,  # Logitech\n        \"Metro_Devices\": 0x00A7,\n        \"Metro_Start_Screen\": 0x00A9,\n        \"Zoomin\": 0x00AA,\n        \"Zoomout\": 0x00AB,\n        \"Back_Hscroll\": 0x00AC,\n        \"Show_Desktop_HPP\": 0x00AE,\n        \"Fn_Left_Click\": 0x00B7,  # from K400 Plus\n        # https://docs.google.com/document/u/0/d/1YvXICgSe8BcBAuMr4Xu_TutvAxaa-RnGfyPFWBWzhkc/export?format=docx\n        # Extract to csv.  Eliminate extra linefeeds and spaces.\n        # awk -F, '/0x/{gsub(\" \\\\+ \",\"_\",$2); gsub(\"/\",\"__\",$2); gsub(\" -\",\"_Down\",$2);\n        # gsub(\" \\\\+\",\"_Up\",$2); gsub(\"[()\\\"-]\",\"\",$2); gsub(\" \",\"_\",$2); printf(\"\\t%s=0x%04X,\\n\", $2, $1)}' < controls.cvs\n        \"Second_Left_Click\": 0x00B8,  # Second_LClick / on K400 Plus\n        \"Fn_Second_Left_Click\": 0x00B9,  # Fn_Second_LClick\n        \"Multiplatform_App_Switch\": 0x00BA,\n        \"Multiplatform_Home\": 0x00BB,\n        \"Multiplatform_Menu\": 0x00BC,\n        \"Multiplatform_Back\": 0x00BD,\n        \"Multiplatform_Insert\": 0x00BE,\n        \"Screen_Capture__Print_Screen\": 0x00BF,  # Craft Keyboard top 3rd from right\n        \"Fn_Down\": 0x00C0,\n        \"Fn_Up\": 0x00C1,\n        \"Multiplatform_Lock\": 0x00C2,\n        \"Mouse_Gesture_Button\": 0x00C3,  # Thumb_Button on MX Master - Logitech name App_Switch_Gesture; Logitech\n        \"Smart_Shift\": 0x00C4,  # Top_Button on MX Master; Logitech\n        \"Microphone\": 0x00C5,\n        \"Wifi\": 0x00C6,\n        \"Brightness_Down\": 0x00C7,  # Craft Keyboard Fn F1, Logitech\n        \"Brightness_Up\": 0x00C8,  # Craft Keyboard Fn F2, Logitech\n        \"Display_Out__Project_Screen_\": 0x00C9,\n        \"View_Open_Apps\": 0x00CA,\n        \"View_All_Apps\": 0x00CB,\n        \"Switch_App\": 0x00CC,\n        \"Fn_Inversion_Change\": 0x00CD,\n        \"MultiPlatform_Back\": 0x00CE,  # Logitech\n        \"MultiPlatform_Forward\": 0x00CF,\n        \"MultiPlatform_Gesture_Button\": 0x00D0,\n        \"Host_Switch_Channel_1\": 0x00D1,  # Craft Keyboard; Logitech\n        \"Host_Switch_Channel_2\": 0x00D2,  # Craft Keyboard; Logitech\n        \"Host_Switch_Channel_3\": 0x00D3,  # Craft Keyboard; Logitech\n        \"MultiPlatform_Search\": 0x00D4,\n        \"MultiPlatform_Home__Mission_Control\": 0x00D5,\n        \"MultiPlatform_Menu__Show__Hide_Virtual_Keyboard__Launchpad\": 0x00D6,\n        \"Virtual_Gesture_Button\": 0x00D7,\n        \"Cursor_Button_Long_Press\": 0x00D8,\n        \"Next_Button_Shortpress\": 0x00D9,  # Next_Button\n        \"Next_Button_Long_Press\": 0x00DA,\n        \"Back_Button_Short_Press\": 0x00DB,  # Back\n        \"Back_Button_Long_Press\": 0x00DC,\n        \"Multi_Platform_Language_Switch\": 0x00DD,\n        \"F_Lock\": 0x00DE,\n        \"Switch_Highlight\": 0x00DF,\n        \"Mission_Control__Task_View\": 0x00E0,  # Craft Keyboard Fn F3 Switch_Workspace; Logitech\n        \"Dashboard_Launchpad__Action_Center\": 0x00E1,  # Craft Keyboard Fn F4 Application_Launcher\n        \"Backlight_Down\": 0x00E2,  # Craft Keyboard Fn F6, Logitech\n        \"Backlight_Up\": 0x00E3,  # Craft Keyboard Fn F7, Logitech\n        \"Previous_Track\": 0x00E4,  # Craft Keyboard Fn F8 Previous_Track; Logitech\n        \"Play__Pause\": 0x00E5,  # Craft Keyboard Fn F9 Play__Pause; Logitech\n        \"Next_Track\": 0x00E6,  # Craft Keyboard Fn F10 Next_Track; Logitech\n        \"Mute_Sound\": 0x00E7,  # Craft Keyboard Fn F11 Mute; Logitech\n        \"Volume_Down\": 0x00E8,  # Craft Keyboard Fn F12 Volume_Down; Logitech\n        \"Volume_Up\": 0x00E9,  # Craft Keyboard next to F12 Volume_Down; Logitech\n        \"App_Contextual_Menu__Right_Click\": 0x00EA,  # Craft Keyboard top 2nd from right\n        \"Right_Arrow\": 0x00EB,\n        \"Left_Arrow\": 0x00EC,\n        \"DPI_Change\": 0x00ED,\n        \"Open_New_Tab\": 0x00EE,  # Logitech\n        \"F2\": 0x00EF,\n        \"F3\": 0x00F0,\n        \"F4\": 0x00F1,\n        \"F5\": 0x00F2,\n        \"F6\": 0x00F3,\n        \"F7\": 0x00F4,\n        \"F8\": 0x00F5,\n        \"F1\": 0x00F6,\n        \"Next_Color_Effect\": 0x00F7,\n        \"Increase_Color_Effect_Speed\": 0x00F8,\n        \"Decrease_Color_Effect_Speed\": 0x00F9,\n        \"Load_Lighting_Custom_Profile\": 0x00FA,\n        \"Laser_Button_Short_Press\": 0x00FB,\n        \"Laser_Button_Long_Press\": 0x00FC,\n        \"DPI_Switch\": 0x00FD,\n        \"Multiplatform_Home__Show_Desktop\": 0x00FE,  # Logitech\n        \"Multiplatform_App_Switch__Show_Dashboard\": 0x00FF,\n        \"Multiplatform_App_Switch_2\": 0x0100,  # Multiplatform_App_Switch\n        \"Fn_Inversion__Hot_Key\": 0x0101,\n        \"LeftAndRightClick\": 0x0102,\n        \"Dictation\": 0x0103,  # MX Keys for Business Fn F5 ; MX Mini Fn F6 Dictation; Logitech\n        \"Emoji_Smiley_Heart_Eyes\": 0x0104,  # Logitech\n        \"Emoji_Crying_Face\": 0x0105,  # Logitech\n        \"Emoji_Smiley\": 0x0106,  # Logitech\n        \"Emoji_Smilie_With_Tears\": 0x0107,  # Logitech\n        \"Emoji\": 0x0108,  # MX Keys for Business Fn F6 ; MX Mini Fn F7 Emoji, Logitech\n        \"Multiplatform_App_Switch__Launchpad\": 0x0109,  # Logitech\n        \"Screen_Capture\": 0x010A,  # MX Keys for Business top 3rd from right; MX Mini Fn F8 Screenshot; Logitech\n        \"Grave_Accent\": 0x010B,  # Logitech\n        \"Tab_Key\": 0x010C,\n        \"Caps_Lock\": 0x010D,\n        \"Left_Shift\": 0x010E,\n        \"Left_Control\": 0x010F,\n        \"Left_Option__Start\": 0x0110,\n        \"Left_Command__Alt\": 0x0111,\n        \"Right_Command__Alt\": 0x0112,\n        \"Right_Option__Start\": 0x0113,\n        \"Right_Control\": 0x0114,\n        \"Right_Shift\": 0x0115,\n        \"Insert\": 0x0116,\n        \"Delete\": 0x0117,  # MX Mini Lock (on delete key in function row)\n        \"Home\": 0x118,  # Logitech\n        \"End\": 0x119,  # Logitech\n        \"Page_Up\": 0x11A,\n        \"Page_Down\": 0x11B,\n        \"Mute_Microphone\": 0x11C,  # MX Keys for Business Fn F7 ; MX Mini Fn F9 Microphone Mute; Logitech\n        \"Do_Not_Disturb\": 0x11D,  # Logitech\n        \"Backslash\": 0x11E,\n        \"Refresh\": 0x11F,  # Logitech\n        \"Close_Tab\": 0x120,\n        \"Lang_Switch\": 0x121,  # Logitech\n        \"Standard_Key_A\": 0x122,\n        \"Standard_Key_B\": 0x123,\n        \"Standard_Key_C\": 0x124,  # There are lots more of these\n        \"Right_Option__Start__2\": 0x013C,  # On MX Mechanical Mini\n        \"Play__Pause_mini\": 0x0141,  # On MX Mechanical Mini\n        \"Haptic\": 0x01A0,  # Logitech\n        \"Circle\": 0x01A3,\n        \"Triangle\": 0x01A4,\n        \"Diamond\": 0x01A5,\n        \"Star\": 0x01A6,\n        \"Cut\": 0x1A9,  # Logitech\n        \"Copy\": 0x1AA,  # Logitech\n        \"Paste\": 0x1AB,  # Logitech\n        \"Video_On_Off\": 0x01AC,  # Logitech\n        \"AI\": 0x1B4,  # Logitech\n    }\n)\n\nfor i in range(1, 33):  # add in G keys - these are not really Logitech Controls\n    CONTROL[0x1000 + i] = f\"G{str(i)}\"\nfor i in range(1, 9):  # add in M keys - these are not really Logitech Controls\n    CONTROL[0x1100 + i] = f\"M{str(i)}\"\nCONTROL[0x1200] = \"MR\"  # add in MR key - this is not really a Logitech Control\n\nCONTROL._fallback = lambda x: f\"unknown:{x:04X}\"\n\n\nclass Task(IntEnum):\n    \"\"\"\n    <tasks.xml awk -F\\\" '/<Task /{gsub(/ /, \"_\", $6); printf(\"\\t%s=0x%04X,\\n\", $6, $4)}'\n    \"\"\"\n\n    VOLUME_UP = 0x0001\n    VOLUME_DOWN = 0x0002\n    MUTE = 0x0003\n    # Multimedia tasks:\n    PLAY_PAUSE = 0x0004\n    NEXT = 0x0005\n    PREVIOUS = 0x0006\n    STOP = 0x0007\n    APPLICATION_SWITCHER = 0x0008\n    BURN_MEDIA_PLAYER = 0x0009\n    CALCULATOR = 0x000A\n    CALENDAR = 0x000B\n    CLOSE_APPLICATION = 0x000C\n    EJECT = 0x000D\n    EMAIL = 0x000E\n    HELP = 0x000F\n    OFF_DOCUMENT = 0x0010\n    OFF_SPREADSHEET = 0x0011\n    OFF_POWERPNT = 0x0012\n    UNDO = 0x0013\n    REDO = 0x0014\n    PRINT = 0x0015\n    SAVE = 0x0016\n    SMART_KEY_SET = 0x0017\n    FAVORITES = 0x0018\n    GADGETS_SET = 0x0019\n    HOME_PAGE = 0x001A\n    WINDOWS_RESTORE = 0x001B\n    WINDOWS_MINIMIZE = 0x001C\n    MUSIC = 0x001D  # also known as MediaPlayer\n    # Both 0x001E and 0x001F are known as MediaCenterSet\n    MEDIA_CENTER_LOGITECH = 0x001E\n    MEDIA_CENTER_MICROSOFT = 0x001F\n    USER_MENU = 0x0020\n    MESSENGER = 0x0021\n    PERSONAL_FOLDERS = 0x0022\n    MY_MUSIC = 0x0023\n    WEBCAM = 0x0024\n    PICTURES_FOLDER = 0x0025\n    MY_VIDEOS = 0x0026\n    MY_COMPUTER = 0x0027\n    PICTURE_APP_SET = 0x0028\n    SEARCH = 0x0029  # also known as AdvSmartSearch\n    RECORD_MEDIA_PLAYER = 0x002A\n    BROWSER_REFRESH = 0x002B\n    ROTATE_RIGHT = 0x002C\n    SEARCH_FILES = 0x002D  # SearchForFiles\n    MM_SHUFFLE = 0x002E\n    SLEEP = 0x002F  # also known as StandBySet\n    BROWSER_STOP = 0x0030\n    ONE_TOUCH_SYNC = 0x0031\n    ZOOM_SET = 0x0032\n    ZOOM_BTN_IN_SET_2 = 0x0033\n    ZOOM_BTN_IN_SET = 0x0034\n    ZOOM_BTN_OUT_SET_2 = 0x0035\n    ZOOM_BTN_OUT_SET = 0x0036\n    ZOOM_BTN_RESET_SET = 0x0037\n    LEFT_CLICK = 0x0038  # LeftClick\n    RIGHT_CLICK = 0x0039  # RightClick\n    MOUSE_MIDDLE_BUTTON = 0x003A  # from M510v2 was MiddleMouseButton\n    BACK = 0x003B\n    MOUSE_BACK_BUTTON = 0x003C  # from M510v2 was BackEx\n    BROWSER_FORWARD = 0x003D\n    MOUSE_FORWARD_BUTTON = 0x003E  # from M510v2 was BrowserForwardEx\n    MOUSE_SCROLL_LEFT_BUTTON = 0x003F  # from M510v2 was HorzScrollLeftSet\n    MOUSE_SCROLL_RIGHT_BUTTON = 0x0040  # from M510v2 was HorzScrollRightSet\n    QUICK_SWITCH = 0x0041\n    BATTERY_STATUS = 0x0042\n    SHOW_DESKTOP = 0x0043  # ShowDesktop\n    WINDOWS_LOCK = 0x0044\n    FILE_LAUNCHER = 0x0045\n    FOLDER_LAUNCHER = 0x0046\n    GOTO_WEB_ADDRESS = 0x0047\n    GENERIC_MOUSE_BUTTON = 0x0048\n    KEYSTROKE_ASSIGNMENT = 0x0049\n    LAUNCH_PROGRAM = 0x004A\n    MIN_MAX_WINDOW = 0x004B\n    VOLUME_MUTE_NO_OSD = 0x004C\n    NEW = 0x004D\n    COPY = 0x004E\n    CRUISE_DOWN = 0x004F\n    CRUISE_UP = 0x0050\n    CUT = 0x0051\n    DO_NOTHING = 0x0052\n    PAGE_DOWN = 0x0053\n    PAGE_UP = 0x0054\n    PASTE = 0x0055\n    SEARCH_PICTURE = 0x0056\n    REPLY = 0x0057\n    PHOTO_GALLERY_SET = 0x0058\n    MM_REWIND = 0x0059\n    MM_FASTFORWARD = 0x005A\n    SEND = 0x005B\n    CONTROL_PANEL = 0x005C\n    UNIVERSAL_SCROLL = 0x005D\n    AUTO_SCROLL = 0x005E\n    GENERIC_BUTTON = 0x005F\n    MM_NEXT = 0x0060\n    MM_PREVIOUS = 0x0061\n    DO_NOTHING_ONE = 0x0062  # also known as Do_Nothing\n    SNAP_LEFT = 0x0063\n    SNAP_RIGHT = 0x0064\n    WIN_MIN_RESTORE = 0x0065\n    WIN_MAX_RESTORE = 0x0066\n    WIN_STRETCH = 0x0067\n    SWITCH_MONITOR_LEFT = 0x0068\n    SWITCH_MONITOR_RIGHT = 0x0069\n    SHOW_PRESENTATION = 0x006A\n    SHOW_MOBILITY_CENTER = 0x006B\n    HORZ_SCROLL_NO_REPEAT_SET = 0x006C\n    TOUCH_BACK_FORWARD_HORZ_SCROLL = 0x0077\n    METRO_APP_SWITCH = 0x0078\n    METRO_APP_BAR = 0x0079\n    METRO_CHARMS = 0x007A\n    CALCULATOR_VKEY = 0x007B  # also known as Calculator\n    METRO_SEARCH = 0x007C\n    METRO_START_SCREEN = 0x0080\n    METRO_SHARE = 0x007D\n    METRO_SETTINGS = 0x007E\n    METRO_DEVICES = 0x007F\n    METRO_BACK_LEFT_HORZ = 0x0082\n    METRO_FORW_RIGHT_HORZ = 0x0083\n    WIN8_BACK = 0x0084  # also known as MetroCharms\n    WIN8_FORWARD = 0x0085  # also known as AppSwitchBar\n    WIN8_CHARM_APPSWITCH_GIF_ANIMATION = 0x0086\n    WIN8_BACK_HORZ_LEFT = 0x008B  # also known as Back\n    WIN8_FORWARD_HORZ_RIGHT = 0x008C  # also known as BrowserForward\n    METRO_SEARCH_2 = 0x0087\n    METROA_SHARE_2 = 0x0088\n    METRO_SETTINGS_2 = 0x008A\n    METRO_DEVICES_2 = 0x0089\n    WIN8_METRO_WIN7_FORWARD = 0x008D  # also known as MetroStartScreen\n    WIN8_SHOW_DESKTOP_WIN7_BACK = 0x008E  # also known as ShowDesktop\n    METRO_APPLICATION_SWITCH = 0x0090  # also known as MetroStartScreen\n    SHOW_UI = 0x0092\n    # https://docs.google.com/document/d/1Dpx_nWRQAZox_zpZ8SNc9nOkSDE9svjkghOCbzopabc/edit\n    # Extract to csv.  Eliminate extra linefeeds and spaces. Turn / into __ and space into _\n    # awk -F, '/0x/{gsub(\" \\\\+ \",\"_\",$2);  gsub(\"_-\",\"_Down\",$2); gsub(\"_\\\\+\",\"_Up\",$2);\n    # gsub(\"[()\\\"-]\",\"\",$2); gsub(\" \",\"_\",$2); printf(\"\\t%s=0x%04X,\\n\", $2, $1)}' < tasks.csv > tasks.py\n    SWITCH_PRESENTATION_SWITCH_SCREEN = 0x0093  # on K400 Plus\n    MINIMIZE_WINDOW = 0x0094\n    MAXIMIZE_WINDOW = 0x0095  # on K400 Plus\n    MULTI_PLATFORM_APP_SWITCH = 0x0096\n    MULTI_PLATFORM_HOME = 0x0097\n    MULTI_PLATFORM_MENU = 0x0098\n    MULTI_PLATFORM_BACK = 0x0099\n    SWITCH_LANGUAGE = 0x009A  # Mac_switch_language\n    SCREEN_CAPTURE = 0x009B  # Mac_screen_Capture, on Craft Keyboard\n    GESTURE_BUTTON = 0x009C\n    SMART_SHIFT = 0x009D\n    APP_EXPOSE = 0x009E\n    SMART_ZOOM = 0x009F\n    LOOKUP = 0x00A0\n    MICROPHEON_ON_OFF = 0x00A1\n    WIFI_ON_OFF = 0x00A2\n    BRIGHTNESS_DOWN = 0x00A3\n    BRIGHTNESS_UP = 0x00A4\n    DISPLAY_OUT = 0x00A5\n    VIEW_OPEN_APPS = 0x00A6\n    VIEW_ALL_OPEN_APPS = 0x00A7\n    APP_SWITCH = 0x00A8\n    GESTURE_BUTTON_NAVIGATION = 0x00A9  # Mouse_Thumb_Button on MX Master\n    FN_INVERSION = 0x00AA\n    MULTI_PLATFORM_BACK_2 = 0x00AB  # Alternative\n    MULTI_PLATFORM_FORWARD = 0x00AC\n    MULTI_PLATFORM_Gesture_Button = 0x00AD\n    HostSwitch_Channel_1 = 0x00AE\n    HostSwitch_Channel_2 = 0x00AF\n    HostSwitch_Channel_3 = 0x00B0\n    MULTI_PLATFORM_SEARCH = 0x00B1\n    MULTI_PLATFORM_HOME_MISSION_CONTROL = 0x00B2\n    MULTI_PLATFORM_MENU_LAUNCHPAD = 0x00B3\n    VIRTUAL_GESTURE_BUTTON = 0x00B4\n    CURSOR = 0x00B5\n    KEYBOARD_RIGHT_ARROW = 0x00B6\n    SW_CUSTOM_HIGHLIGHT = 0x00B7\n    KEYBOARD_LEFT_ARROW = 0x00B8\n    TBD = 0x00B9\n    MULTI_PLATFORM_Language_Switch = 0x00BA\n    SW_CUSTOM_HIGHLIGHT_2 = 0x00BB\n    FAST_FORWARD = 0x00BC\n    FAST_BACKWARD = 0x00BD\n    SWITCH_HIGHLIGHTING = 0x00BE\n    MISSION_CONTROL_TASK_VIEW = 0x00BF  # Switch_Workspace on Craft Keyboard\n    DASHBOARD_LAUNCHPAD_ACTION_CENTER = 0x00C0  # Application_Launcher on Craft\n    # Keyboard\n    BACKLIGHT_DOWN = 0x00C1  # Backlight_Down_FW_internal_function\n    BACKLIGHT_UP = 0x00C2  # Backlight_Up_FW_internal_function\n    RIGHT_CLICK_APP_CONTEXT_MENU = 0x00C3  # Context_Menu on Craft Keyboard\n    DPI_Change = 0x00C4\n    NEW_TAB = 0x00C5\n    F2 = 0x00C6\n    F3 = 0x00C7\n    F4 = 0x00C8\n    F5 = 0x00C9\n    F6 = 0x00CA\n    F7 = 0x00CB\n    F8 = 0x00CC\n    F1 = 0x00CD\n    LASER_BUTTON = 0x00CE\n    LASER_BUTTON_LONG_PRESS = 0x00CF\n    START_PRESENTATION = 0x00D0\n    BLANK_SCREEN = 0x00D1\n    DPI_Switch = 0x00D2  # AdjustDPI on MX Vertical\n    HOME_SHOW_DESKTOP = 0x00D3\n    APP_SWITCH_DASHBOARD = 0x00D4\n    APP_SWITCH_2 = 0x00D5  # Alternative\n    FN_INVERSION_2 = 0x00D6  # Alternative\n    LEFT_AND_RIGHT_CLICK = 0x00D7\n    VOICE_DICTATION = 0x00D8\n    EMOJI_SMILING_FACE_WITH_HEART_SHAPED_EYES = 0x00D9\n    EMOJI_LOUDLY_CRYING_FACE = 0x00DA\n    EMOJI_SMILEY = 0x00DB\n    EMOJI_SMILE_WITH_TEARS = 0x00DC\n    OPEN_EMOJI_PANEL = 0x00DD\n    MULTI_PLATFORM_APP_SWITCH_LAUNCHPAD = 0x00DE\n    SNIPPING_TOOL = 0x00DF\n    GRAVE_ACCENT = 0x00E0\n    STANDARD_TAB_KEY = 0x00E1\n    CAPS_LOCK = 0x00E2\n    LEFT_SHIFT = 0x00E3\n    LEFT_CONTROL = 0x00E4\n    LEFT_OPTION_START = 0x00E5\n    LEFT_COMMAND_ALT = 0x00E6\n    RIGHT_COMMAND_ALT = 0x00E7\n    RIGHT_OPTION_START = 0x00E8\n    RIGHT_CONTROL = 0x00E9\n    RIGHT_SHIFT = 0x0EA\n    INSERT = 0x00EB\n    DELETE = 0x00EC\n    HOME = 0x00ED\n    END = 0x00EE\n    PAGE_UP_2 = 0x00EF  # Alternative\n    PAGE_DOWN_2 = 0x00F0  # Alternative\n    MUTE_MICROPHONE = 0x00F1\n    DO_NOT_DISTURB = 0x00F2\n    BACKSLASH = 0x00F3\n    REFRESH = 0x00F4\n    CLOSE_TAB = 0x00F5\n    LANG_SWITCH = 0x00F6\n    STANDARD_ALPHABETICAL_KEY = 0x00F7\n    RRIGH_OPTION_START_2 = 0x00F8\n    LEFT_OPTION = 0x00F9\n    RIGHT_OPTION = 0x00FA\n    LEFT_CMD = 0x00FB\n    RIGHT_CMD = 0x00FC\n\n    def __str__(self):\n        return self.name.replace(\"_\", \" \").title()\n\n\nclass CIDGroupBit(IntEnum):\n    g1 = 0x01\n    g2 = 0x02\n    g3 = 0x04\n    g4 = 0x08\n    g5 = 0x10\n    g6 = 0x20\n    g7 = 0x40\n    g8 = 0x80\n\n\nclass CidGroup(IntEnum):\n    g1 = 1\n    g2 = 2\n    g3 = 3\n    g4 = 4\n    g5 = 5\n    g6 = 6\n    g7 = 7\n    g8 = 8\n\n\nDISABLE = NamedInts(\n    Caps_Lock=0x01,\n    Num_Lock=0x02,\n    Scroll_Lock=0x04,\n    Insert=0x08,\n    Win=0x10,  # aka Super\n)\nDISABLE._fallback = lambda x: f\"unknown:{x:02X}\"\n\n# HID USB Keycodes from https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf\n# Modified by information from Linux HID driver linux/drivers/hid/hid-input.c\nUSB_HID_KEYCODES = NamedInts(\n    A=0x04,\n    B=0x05,\n    C=0x06,\n    D=0x07,\n    E=0x08,\n    F=0x09,\n    G=0x0A,\n    H=0x0B,\n    I=0x0C,\n    J=0x0D,\n    K=0x0E,\n    L=0x0F,\n    M=0x10,\n    N=0x11,\n    O=0x12,\n    P=0x13,\n    Q=0x14,\n    R=0x15,\n    S=0x16,\n    T=0x17,\n    U=0x18,\n    V=0x19,\n    W=0x1A,\n    X=0x1B,\n    Y=0x1C,\n    Z=0x1D,\n    ENTER=0x28,\n    ESC=0x29,\n    BACKSPACE=0x2A,\n    TAB=0x2B,\n    SPACE=0x2C,\n    MINUS=0x2D,\n    EQUAL=0x2E,\n    LEFTBRACE=0x2F,\n    RIGHTBRACE=0x30,\n    BACKSLASH=0x31,\n    HASHTILDE=0x32,\n    SEMICOLON=0x33,\n    APOSTROPHE=0x34,\n    GRAVE=0x35,\n    COMMA=0x36,\n    DOT=0x37,\n    SLASH=0x38,\n    CAPSLOCK=0x39,\n    F1=0x3A,\n    F2=0x3B,\n    F3=0x3C,\n    F4=0x3D,\n    F5=0x3E,\n    F6=0x3F,\n    F7=0x40,\n    F8=0x41,\n    F9=0x42,\n    F10=0x43,\n    F11=0x44,\n    F12=0x45,\n    SYSRQ=0x46,\n    SCROLLLOCK=0x47,\n    PAUSE=0x48,\n    INSERT=0x49,\n    HOME=0x4A,\n    PAGEUP=0x4B,\n    DELETE=0x4C,\n    END=0x4D,\n    PAGEDOWN=0x4E,\n    RIGHT=0x4F,\n    LEFT=0x50,\n    DOWN=0x51,\n    UP=0x52,\n    NUMLOCK=0x53,\n    KPSLASH=0x54,\n    KPASTERISK=0x55,\n    KPMINUS=0x56,\n    KPPLUS=0x57,\n    KPENTER=0x58,\n    KP1=0x59,\n    KP2=0x5A,\n    KP3=0x5B,\n    KP4=0x5C,\n    KP5=0x5D,\n    KP6=0x5E,\n    KP7=0x5F,\n    KP8=0x60,\n    KP9=0x61,\n    KP0=0x62,\n    KPDOT=0x63,\n    COMPOSE=0x65,\n    POWER=0x66,\n    KPEQUAL=0x67,\n    F13=0x68,\n    F14=0x69,\n    F15=0x6A,\n    F16=0x6B,\n    F17=0x6C,\n    F18=0x6D,\n    F19=0x6E,\n    F20=0x6F,\n    F21=0x70,\n    F22=0x71,\n    F23=0x72,\n    F24=0x73,\n    OPEN=0x74,\n    HELP=0x75,\n    PROPS=0x76,\n    FRONT=0x77,\n    STOP=0x78,\n    AGAIN=0x79,\n    UNDO=0x7A,\n    CUT=0x7B,\n    COPY=0x7C,\n    PASTE=0x7D,\n    FIND=0x7E,\n    MUTE=0x7F,\n    VOLUMEUP=0x80,\n    VOLUMEDOWN=0x81,\n    KPCOMMA=0x85,\n    RO=0x87,\n    KATAKANAHIRAGANA=0x88,\n    YEN=0x89,\n    HENKAN=0x8A,\n    MUHENKAN=0x8B,\n    KPJPCOMMA=0x8C,\n    HANGEUL=0x90,\n    HANJA=0x91,\n    KATAKANA=0x92,\n    HIRAGANA=0x93,\n    ZENKAKUHANKAKU=0x94,\n    KPLEFTPAREN=0xB6,\n    KPRIGHTPAREN=0xB7,\n    LEFTCTRL=0xE0,\n    LEFTSHIFT=0xE1,\n    LEFTALT=0xE2,\n    LEFTWINDOWS=0xE3,\n    RIGHTCTRL=0xE4,\n    RIGHTSHIFT=0xE5,\n    RIGHTALT=0xE6,\n    RIGHTMETA=0xE7,\n    MEDIA_PLAYPAUSE=0xE8,\n    MEDIA_STOPCD=0xE9,\n    MEDIA_PREVIOUSSONG=0xEA,\n    MEDIA_NEXTSONG=0xEB,\n    MEDIA_EJECTCD=0xEC,\n    MEDIA_VOLUMEUP=0xED,\n    MEDIA_VOLUMEDOWN=0xEE,\n    MEDIA_MUTE=0xEF,\n    MEDIA_WWW=0xF0,\n    MEDIA_BACK=0xF1,\n    MEDIA_FORWARD=0xF2,\n    MEDIA_STOP=0xF3,\n    MEDIA_FIND=0xF4,\n    MEDIA_SCROLLUP=0xF5,\n    MEDIA_SCROLLDOWN=0xF6,\n    MEDIA_EDIT=0xF7,\n    MEDIA_SLEEP=0xF8,\n    MEDIA_COFFEE=0xF9,\n    MEDIA_REFRESH=0xFA,\n    MEDIA_CALC=0xFB,\n)\nUSB_HID_KEYCODES[0] = \"No Output\"\nUSB_HID_KEYCODES[0x1E] = \"1\"\nUSB_HID_KEYCODES[0x1F] = \"2\"\nUSB_HID_KEYCODES[0x20] = \"3\"\nUSB_HID_KEYCODES[0x21] = \"4\"\nUSB_HID_KEYCODES[0x22] = \"5\"\nUSB_HID_KEYCODES[0x23] = \"6\"\nUSB_HID_KEYCODES[0x24] = \"7\"\nUSB_HID_KEYCODES[0x25] = \"8\"\nUSB_HID_KEYCODES[0x26] = \"9\"\nUSB_HID_KEYCODES[0x27] = \"0\"\nUSB_HID_KEYCODES[0x64] = \"102ND\"\n\nHID_CONSUMERCODES = NamedInts(\n    {\n        #    Unassigned=0x00,\n        #    Consumer_Control=0x01,\n        #    Numeric_Key_Pad=0x02,\n        #    Programmable_Buttons=0x03,\n        #    Microphone=0x04,\n        #    Headphone=0x05,\n        #    Graphic_Equalizer=0x06,\n        #    AM__PM=0x22,\n        \"Power\": 0x30,\n        \"Reset\": 0x31,\n        \"Sleep\": 0x32,\n        \"Sleep_After\": 0x33,\n        \"Sleep_Mode\": 0x34,\n        \"Illumination\": 0x35,\n        \"Function_Buttons\": 0x36,\n        \"Menu\": 0x40,\n        \"Menu__Pick\": 0x41,\n        \"Menu_Up\": 0x42,\n        \"Menu_Down\": 0x43,\n        \"Menu_Left\": 0x44,\n        \"Menu_Right\": 0x45,\n        \"Menu_Escape\": 0x46,\n        \"Menu_Value_Increase\": 0x47,\n        \"Menu_Value_Decrease\": 0x48,\n        \"Data_On_Screen\": 0x60,\n        \"Closed_Caption\": 0x61,\n        #    Closed_Caption_Select=0x62,\n        \"VCR__TV\": 0x63,\n        #    Broadcast_Mode=0x64,\n        \"Snapshot\": 0x65,\n        #    Still=0x66,\n        \"Red\": 0x69,\n        \"Green\": 0x6A,\n        \"Blue\": 0x6B,\n        \"Yellow\": 0x6C,\n        \"Aspect_Ratio\": 0x6D,\n        \"Brightness_Up\": 0x6F,\n        \"Brightness_Down\": 0x70,\n        \"Brightness_Toggle\": 0x72,\n        \"Brightness_Min\": 0x73,\n        \"Brightness_Max\": 0x74,\n        \"Brightness_Auto\": 0x75,\n        \"Keyboard_Illumination_Up\": 0x79,\n        \"Keyboard_Illumination_Down\": 0x7A,\n        \"Keyboard_Illumination_Toggle\": 0x7C,\n        #    Selection=0x80,\n        #    Assign_Selection=0x81,\n        \"Mode_Step\": 0x82,\n        \"Recall_Last\": 0x83,\n        \"Enter_Channel\": 0x84,\n        #    Order_Movie=0x85,\n        #    Channel=0x86,\n        #    Media_Selection=0x87,\n        \"Media_Select_Computer\": 0x88,\n        \"Media_Select_TV\": 0x89,\n        \"Media_Select_WWW\": 0x8A,\n        \"Media_Select_DVD\": 0x8B,\n        \"Media_Select_Telephone\": 0x8C,\n        \"Media_Select_Program_Guide\": 0x8D,\n        \"Media_Select_Video_Phone\": 0x8E,\n        \"Media_Select_Games\": 0x8F,\n        \"Media_Select_Messages\": 0x90,\n        \"Media_Select_CD\": 0x91,\n        \"Media_Select_VCR\": 0x92,\n        \"Media_Select_Tuner\": 0x93,\n        \"Quit\": 0x94,\n        \"Help\": 0x95,\n        \"Media_Select_Tape\": 0x96,\n        \"Media_Select_Cable\": 0x97,\n        \"Media_Select_Satellite\": 0x98,\n        \"Media_Select_Security\": 0x99,\n        \"Media_Select_Home\": 0x9A,\n        #    Media_Select_Call=0x9B,\n        \"Channel_Increment\": 0x9C,\n        \"Channel_Decrement\": 0x9D,\n        #    Media_Select_SAP=0x9E,\n        \"VCR_Plus\": 0xA0,\n        #    Once=0xA1,\n        #    Daily=0xA2,\n        #    Weekly=0xA3,\n        #    Monthly=0xA4,\n        \"Play\": 0xB0,\n        \"Pause\": 0xB1,\n        \"Record\": 0xB2,\n        \"Fast_Forward\": 0xB3,\n        \"Rewind\": 0xB4,\n        \"Scan_Next_Track\": 0xB5,\n        \"Scan_Previous_Track\": 0xB6,\n        \"Stop\": 0xB7,\n        \"Eject\": 0xB8,\n        \"Random_Play\": 0xB9,\n        \"Select_DisC\": 0xBA,\n        \"Enter_Disc\": 0xBB,\n        \"Repeat\": 0xBC,\n        \"Tracking\": 0xBD,\n        \"Track_Normal\": 0xBE,\n        \"Slow_Tracking\": 0xBF,\n        #    Frame_Forward=0xC0,\n        #    Frame_Back=0xC1,\n        #    Mark=0xC2,\n        #    Clear_Mark=0xC3,\n        #    Repeat_From_Mark=0xC4,\n        #    Return_To_Mark=0xC5,\n        #    Search_Mark_Forward=0xC6,\n        #    Search_Mark_Backwards=0xC7,\n        #    Counter_Reset=0xC8,\n        #    Show_Counter=0xC9,\n        #    Tracking_Increment=0xCA,\n        #    Tracking_Decrement=0xCB,\n        #    Stop__Eject=0xCC,\n        \"Play__Pause\": 0xCD,\n        #    Play__Skip=0xCE,\n        \"Volume\": 0xE0,\n        #    Balance=0xE1,\n        \"Mute\": 0xE2,\n        #    Bass=0xE3,\n        #    Treble=0xE4,\n        \"Bass_Boost\": 0xE5,\n        #    Surround_Mode=0xE6,\n        #    Loudness=0xE7,\n        #    MPX=0xE8,\n        \"Volume_Up\": 0xE9,\n        \"Volume_Down\": 0xEA,\n        #    Speed_Select=0xF0,\n        #    Playback_Speed=0xF1,\n        #    Standard_Play=0xF2,\n        #    Long_Play=0xF3,\n        #    Extended_Play=0xF4,\n        \"Slow\": 0xF5,\n        \"Fan_Enable\": 0x100,\n        \"Fan_Speed\": 0x101,\n        \"Light\": 0x102,\n        \"Light_Illumination_Level\": 0x103,\n        \"Climate_Control_Enable\": 0x104,\n        \"Room_Temperature\": 0x105,\n        \"Security_Enable\": 0x106,\n        \"Fire_Alarm\": 0x107,\n        \"Police_Alarm\": 0x108,\n        \"Proximity\": 0x109,\n        \"Motion\": 0x10A,\n        \"Duress_Alarm\": 0x10B,\n        \"Holdup_Alarm\": 0x10C,\n        \"Medical_Alarm\": 0x10D,\n        \"Balance_Right\": 0x150,\n        \"Balance_Left\": 0x151,\n        \"Bass_Increment\": 0x152,\n        \"Bass_Decrement\": 0x153,\n        \"Treble_Increment\": 0x154,\n        \"Treble_Decrement\": 0x155,\n        \"Speaker_System\": 0x160,\n        \"Channel_Left\": 0x161,\n        \"Channel_Right\": 0x162,\n        \"Channel_Center\": 0x163,\n        \"Channel_Front\": 0x164,\n        \"Channel_Center_Front\": 0x165,\n        \"Channel_Side\": 0x166,\n        \"Channel_Surround\": 0x167,\n        \"Channel_Low_Frequency_Enhancement\": 0x168,\n        \"Channel_Top\": 0x169,\n        \"Channel_Unknown\": 0x16A,\n        \"Subchannel\": 0x170,\n        \"Subchannel_Increment\": 0x171,\n        \"Subchannel_Decrement\": 0x172,\n        \"Alternate_Audio_Increment\": 0x173,\n        \"Alternate_Audio_Decrement\": 0x174,\n        \"Application_Launch_Buttons\": 0x180,\n        \"AL_Launch_Button_Configuration_Tool\": 0x181,\n        \"AL_Programmable_Button_Configuration\": 0x182,\n        \"AL_Consumer_Control_Configuration\": 0x183,\n        \"AL_Word_Processor\": 0x184,\n        \"AL_Text_Editor\": 0x185,\n        \"AL_Spreadsheet\": 0x186,\n        \"AL_Graphics_Editor\": 0x187,\n        \"AL_Presentation_App\": 0x188,\n        \"AL_Database_App\": 0x189,\n        \"AL_Email_Reader\": 0x18A,\n        \"AL_Newsreader\": 0x18B,\n        \"AL_Voicemail\": 0x18C,\n        \"AL_Contacts__Address_Book\": 0x18D,\n        \"AL_Calendar__Schedule\": 0x18E,\n        \"AL_Task__Project_Manager\": 0x18F,\n        \"AL_Log__Journal__Timecard\": 0x190,\n        \"AL_Checkbook__Finance\": 0x191,\n        \"AL_Calculator\": 0x192,\n        \"AL_A__V_Capture__Playback\": 0x193,\n        \"AL_Local_Machine_Browser\": 0x194,\n        \"AL_LAN__WAN_Browser\": 0x195,\n        \"AL_Internet_Browser\": 0x196,\n        \"AL_Remote_Networking__ISP_Connect\": 0x197,\n        \"AL_Network_Conference\": 0x198,\n        \"AL_Network_Chat\": 0x199,\n        \"AL_Telephony__Dialer\": 0x19A,\n        \"AL_Logon\": 0x19B,\n        \"AL_Logoff\": 0x19C,\n        \"AL_Logon__Logoff\": 0x19D,\n        \"AL_Terminal_Lock__Screensaver\": 0x19E,\n        \"AL_Control_Panel\": 0x19F,\n        \"AL_Command_Line_Processor__Run\": 0x1A0,\n        \"AL_Process__Task_Manager\": 0x1A1,\n        \"AL_Select_Tast__Application\": 0x1A2,\n        \"AL_Next_Task__Application\": 0x1A3,\n        \"AL_Previous_Task__Application\": 0x1A4,\n        \"AL_Preemptive_Halt_Task__Application\": 0x1A5,\n        \"AL_Integrated_Help_Center\": 0x1A6,\n        \"AL_Documents\": 0x1A7,\n        \"AL_Thesaurus\": 0x1A8,\n        \"AL_Dictionary\": 0x1A9,\n        \"AL_Desktop\": 0x1AA,\n        \"AL_Spell_Check\": 0x1AB,\n        \"AL_Grammar_Check\": 0x1AC,\n        \"AL_Wireless_Status\": 0x1AD,\n        \"AL_Keyboard_Layout\": 0x1AE,\n        \"AL_Virus_Protection\": 0x1AF,\n        \"AL_Encryption\": 0x1B0,\n        \"AL_Screen_Saver\": 0x1B1,\n        \"AL_Alarms\": 0x1B2,\n        \"AL_Clock\": 0x1B3,\n        \"AL_File_Browser\": 0x1B4,\n        \"AL_Power_Status\": 0x1B5,\n        \"AL_Image_Browser\": 0x1B6,\n        \"AL_Audio_Browser\": 0x1B7,\n        \"AL_Movie_Browser\": 0x1B8,\n        \"AL_Digital_Rights_Manager\": 0x1B9,\n        \"AL_Digital_Wallet\": 0x1BA,\n        \"AL_Instant_Messaging\": 0x1BC,\n        \"AL_OEM_Features___Tips__Tutorial_Browser\": 0x1BD,\n        \"AL_OEM_Help\": 0x1BE,\n        \"AL_Online_Community\": 0x1BF,\n        \"AL_Entertainment_Content_Browser\": 0x1C0,\n        \"AL_Online_Shopping_Browser\": 0x1C1,\n        \"AL_SmartCard_Information__Help\": 0x1C2,\n        \"AL_Market_Monitor__Finance_Browser\": 0x1C3,\n        \"AL_Customized_Corporate_News_Browser\": 0x1C4,\n        \"AL_Online_Activity_Browser\": 0x1C5,\n        \"AL_Research__Search_Browser\": 0x1C6,\n        \"AL_Audio_Player\": 0x1C7,\n        \"Generic_GUI_Application_Controls\": 0x200,\n        \"AC_New\": 0x201,\n        \"AC_Open\": 0x202,\n        \"AC_Close\": 0x203,\n        \"AC_Exit\": 0x204,\n        \"AC_Maximize\": 0x205,\n        \"AC_Minimize\": 0x206,\n        \"AC_Save\": 0x207,\n        \"AC_Print\": 0x208,\n        \"AC_Properties\": 0x209,\n        \"AC_Undo\": 0x21A,\n        \"AC_Copy\": 0x21B,\n        \"AC_Cut\": 0x21C,\n        \"AC_Paste\": 0x21D,\n        \"AC_Select_All\": 0x21E,\n        \"AC_Find\": 0x21F,\n        \"AC_Find_and_Replace\": 0x220,\n        \"AC_Search\": 0x221,\n        \"AC_Go_To\": 0x222,\n        \"AC_Home\": 0x223,\n        \"AC_Back\": 0x224,\n        \"AC_Forward\": 0x225,\n        \"AC_Stop\": 0x226,\n        \"AC_Refresh\": 0x227,\n        \"AC_Previous_Link\": 0x228,\n        \"AC_Next_Link\": 0x229,\n        \"AC_Bookmarks\": 0x22A,\n        \"AC_History\": 0x22B,\n        \"AC_Subscriptions\": 0x22C,\n        \"AC_Zoom_In\": 0x22D,\n        \"AC_Zoom_Out\": 0x22E,\n        \"AC_Zoom\": 0x22F,\n        \"AC_Full_Screen_View\": 0x230,\n        \"AC_Normal_View\": 0x231,\n        \"AC_View_Toggle\": 0x232,\n        \"AC_Scroll_Up\": 0x233,\n        \"AC_Scroll_Down\": 0x234,\n        \"AC_Scroll\": 0x235,\n        \"AC_Pan_Left\": 0x236,\n        \"AC_Pan_Right\": 0x237,\n        \"AC_Pan\": 0x238,\n        \"AC_New_Window\": 0x239,\n        \"AC_Tile_Horizontally\": 0x23A,\n        \"AC_Tile_Vertically\": 0x23B,\n        \"AC_Format\": 0x23C,\n        \"AC_Edit\": 0x23D,\n        \"AC_Bold\": 0x23E,\n        \"AC_Italics\": 0x23F,\n        \"AC_Underline\": 0x240,\n        \"AC_Strikethrough\": 0x241,\n        \"AC_Subscript\": 0x242,\n        \"AC_Superscript\": 0x243,\n        \"AC_All_Caps\": 0x244,\n        \"AC_Rotate\": 0x245,\n        \"AC_Resize\": 0x246,\n        \"AC_Flip_horizontal\": 0x247,\n        \"AC_Flip_Vertical\": 0x248,\n        \"AC_Mirror_Horizontal\": 0x249,\n        \"AC_Mirror_Vertical\": 0x24A,\n        \"AC_Font_Select\": 0x24B,\n        \"AC_Font_Color\": 0x24C,\n        \"AC_Font_Size\": 0x24D,\n        \"AC_Justify_Left\": 0x24E,\n        \"AC_Justify_Center_H\": 0x24F,\n        \"AC_Justify_Right\": 0x250,\n        \"AC_Justify_Block_H\": 0x251,\n        \"AC_Justify_Top\": 0x252,\n        \"AC_Justify_Center_V\": 0x253,\n        \"AC_Justify_Bottom\": 0x254,\n        \"AC_Justify_Block_V\": 0x255,\n        \"AC_Indent_Decrease\": 0x256,\n        \"AC_Indent_Increase\": 0x257,\n        \"AC_Numbered_List\": 0x258,\n        \"AC_Restart_Numbering\": 0x259,\n        \"AC_Bulleted_List\": 0x25A,\n        \"AC_Promote\": 0x25B,\n        \"AC_Demote\": 0x25C,\n        \"AC_Yes\": 0x25D,\n        \"AC_No\": 0x25E,\n        \"AC_Cancel\": 0x25F,\n        \"AC_Catalog\": 0x260,\n        \"AC_Buy__Checkout\": 0x261,\n        \"AC_Add_to_Cart\": 0x262,\n        \"AC_Expand\": 0x263,\n        \"AC_Expand_All\": 0x264,\n        \"AC_Collapse\": 0x265,\n        \"AC_Collapse_All\": 0x266,\n        \"AC_Print_Preview\": 0x267,\n        \"AC_Paste_Special\": 0x268,\n        \"AC_Insert_Mode\": 0x269,\n        \"AC_Delete\": 0x26A,\n        \"AC_Lock\": 0x26B,\n        \"AC_Unlock\": 0x26C,\n        \"AC_Protect\": 0x26D,\n        \"AC_Unprotect\": 0x26E,\n        \"AC_Attach_Comment\": 0x26F,\n        \"AC_Delete_Comment\": 0x270,\n        \"AC_View_Comment\": 0x271,\n        \"AC_Select_Word\": 0x272,\n        \"AC_Select_Sentence\": 0x273,\n        \"AC_Select_Paragraph\": 0x274,\n        \"AC_Select_Column\": 0x275,\n        \"AC_Select_Row\": 0x276,\n        \"AC_Select_Table\": 0x277,\n        \"AC_Select_Object\": 0x278,\n        \"AC_Redo__Repeat\": 0x279,\n        \"AC_Sort\": 0x27A,\n        \"AC_Sort_Ascending\": 0x27B,\n        \"AC_Sort_Descending\": 0x27C,\n        \"AC_Filter\": 0x27D,\n        \"AC_Set_Clock\": 0x27E,\n        \"AC_View_Clock\": 0x27F,\n        \"AC_Select_Time_Zone\": 0x280,\n        \"AC_Edit_Time_Zones\": 0x281,\n        \"AC_Set_Alarm\": 0x282,\n        \"AC_Clear_Alarm\": 0x283,\n        \"AC_Snooze_Alarm\": 0x284,\n        \"AC_Reset_Alarm\": 0x285,\n        \"AC_Synchronize\": 0x286,\n        \"AC_Send__Receive\": 0x287,\n        \"AC_Send_To\": 0x288,\n        \"AC_Reply\": 0x289,\n        \"AC_Reply_All\": 0x28A,\n        \"AC_Forward_Msg\": 0x28B,\n        \"AC_Send\": 0x28C,\n        \"AC_Attach_File\": 0x28D,\n        \"AC_Upload\": 0x28E,\n        \"AC_Download_Save_Target_As\": 0x28F,\n        \"AC_Set_Borders\": 0x290,\n        \"AC_Insert_Row\": 0x291,\n        \"AC_Insert_Column\": 0x292,\n        \"AC_Insert_File\": 0x293,\n        \"AC_Insert_Picture\": 0x294,\n        \"AC_Insert_Object\": 0x295,\n        \"AC_Insert_Symbol\": 0x296,\n        \"AC_Save_and_Close\": 0x297,\n        \"AC_Rename\": 0x298,\n        \"AC_Merge\": 0x299,\n        \"AC_Split\": 0x29A,\n        \"AC_Distribute_Horizontally\": 0x29B,\n        \"AC_Distribute_Vertically\": 0x29C,\n    }\n)\nHID_CONSUMERCODES[0x20] = \"+10\"\nHID_CONSUMERCODES[0x21] = \"+100\"\nHID_CONSUMERCODES._fallback = lambda x: f\"unknown:{x:04X}\"\n\n## Information for x1c00 Persistent from https://drive.google.com/drive/folders/0BxbRzx7vEV7eWmgwazJ3NUFfQ28\n\nKEYMOD = NamedInts(CTRL=0x01, SHIFT=0x02, ALT=0x04, META=0x08, RCTRL=0x10, RSHIFT=0x20, RALT=0x40, RMETA=0x80)\n\nACTIONID = NamedInts(\n    Empty=0x00,\n    Key=0x01,\n    Mouse=0x02,\n    Xdisp=0x03,\n    Ydisp=0x04,\n    Vscroll=0x05,\n    Hscroll=0x06,\n    Consumer=0x07,\n    Internal=0x08,\n    Power=0x09,\n)\n\nMOUSE_BUTTONS = NamedInts(\n    Mouse_Button_Left=0x0001,\n    Mouse_Button_Right=0x0002,\n    Mouse_Button_Middle=0x0004,\n    Mouse_Button_Back=0x0008,\n    Mouse_Button_Forward=0x0010,\n    Mouse_Button_6=0x0020,\n    Mouse_Button_Scroll_Left=0x0040,\n    Mouse_Button_Scroll_Right=0x0080,\n    Mouse_Button_9=0x0100,\n    Mouse_Button_10=0x0200,\n    Mouse_Button_11=0x0400,\n    Mouse_Button_12=0x0800,\n    Mouse_Button_13=0x1000,\n    Mouse_Button_DPI=0x2000,\n    Mouse_Button_15=0x4000,\n    Mouse_Button_16=0x8000,\n)\nMOUSE_BUTTONS._fallback = lambda x: f\"unknown mouse button:{x:04X}\"\n\n\nclass HorizontalScroll(IntEnum):\n    Left = 0x4000\n    Right = 0x8000\n\n\n# Construct universe for Persistent Remappable Keys setting (only for supported values)\nKEYS = UnsortedNamedInts()\nKEYS_Default = 0x7FFFFFFF  # Special value to reset key to default - has to be different from all others\nKEYS[KEYS_Default] = \"Default\"  # Value to reset to default\nKEYS[0] = \"None\"  # Value for no output\n\n# Add HID keys plus modifiers\nmodifiers = {\n    0x00: \"\",\n    0x01: \"Cntrl+\",\n    0x02: \"Shift+\",\n    0x04: \"Alt+\",\n    0x08: \"Meta+\",\n    0x03: \"Cntrl+Shift+\",\n    0x05: \"Alt+Cntrl+\",\n    0x09: \"Meta+Cntrl+\",\n    0x06: \"Alt+Shift+\",\n    0x0A: \"Meta+Shift+\",\n    0x0C: \"Meta+Alt+\",\n}\nfor val, name in modifiers.items():\n    for key in USB_HID_KEYCODES:\n        KEYS[(ACTIONID.Key << 24) + (int(key) << 8) + val] = name + str(key)\n\n# Add HID Consumer Codes\nfor code in HID_CONSUMERCODES:\n    KEYS[(ACTIONID.Consumer << 24) + (int(code) << 8)] = str(code)\n\n# Add Mouse Buttons\nfor code in MOUSE_BUTTONS:\n    KEYS[(ACTIONID.Mouse << 24) + (int(code) << 8)] = str(code)\n\n# Add Horizontal Scroll\nfor code in HorizontalScroll:\n    KEYS[(ACTIONID.Hscroll << 24) + (int(code) << 8)] = str(code)\n\n\n# Construct subsets for known devices\ndef persistent_keys(action_ids):\n    keys = UnsortedNamedInts()\n    keys[KEYS_Default] = \"Default\"  # Value to reset to default\n    keys[0] = \"No Output (only as default)\"\n    for key in KEYS:\n        if (int(key) >> 24) in action_ids:\n            keys[int(key)] = str(key)\n    return keys\n\n\nKEYS_KEYS_CONSUMER = persistent_keys([ACTIONID.Key, ACTIONID.Consumer])\nKEYS_KEYS_MOUSE_HSCROLL = persistent_keys([ACTIONID.Key, ACTIONID.Mouse, ACTIONID.Hscroll])\n\nCOLORS = UnsortedNamedInts(\n    {\n        # from Xorg rgb.txt,v 1.3 2000/08/17\n        \"red\": 0xFF0000,\n        \"orange\": 0xFFA500,\n        \"yellow\": 0xFFFF00,\n        \"green\": 0x00FF00,\n        \"blue\": 0x0000FF,\n        \"purple\": 0xA020F0,\n        \"violet\": 0xEE82EE,\n        \"black\": 0x000000,\n        \"white\": 0xFFFFFF,\n        \"gray\": 0xBEBEBE,\n        \"brown\": 0xA52A2A,\n        \"cyan\": 0x00FFFF,\n        \"magenta\": 0xFF00FF,\n        \"pink\": 0xFFC0CB,\n        \"maroon\": 0xB03060,\n        \"turquoise\": 0x40E0D0,\n        \"gold\": 0xFFD700,\n        \"tan\": 0xD2B48C,\n        \"snow\": 0xFFFAFA,\n        \"ghost white\": 0xF8F8FF,\n        \"white smoke\": 0xF5F5F5,\n        \"gainsboro\": 0xDCDCDC,\n        \"floral white\": 0xFFFAF0,\n        \"old lace\": 0xFDF5E6,\n        \"linen\": 0xFAF0E6,\n        \"antique white\": 0xFAEBD7,\n        \"papaya whip\": 0xFFEFD5,\n        \"blanched almond\": 0xFFEBCD,\n        \"bisque\": 0xFFE4C4,\n        \"peach puff\": 0xFFDAB9,\n        \"navajo white\": 0xFFDEAD,\n        \"moccasin\": 0xFFE4B5,\n        \"cornsilk\": 0xFFF8DC,\n        \"ivory\": 0xFFFFF0,\n        \"lemon chiffon\": 0xFFFACD,\n        \"seashell\": 0xFFF5EE,\n        \"honeydew\": 0xF0FFF0,\n        \"mint cream\": 0xF5FFFA,\n        \"azure\": 0xF0FFFF,\n        \"alice blue\": 0xF0F8FF,\n        \"lavender\": 0xE6E6FA,\n        \"lavender blush\": 0xFFF0F5,\n        \"misty rose\": 0xFFE4E1,\n        \"dark slate gray\": 0x2F4F4F,\n        \"dim gray\": 0x696969,\n        \"slate gray\": 0x708090,\n        \"light slate gray\": 0x778899,\n        \"light gray\": 0xD3D3D3,\n        \"midnight blue\": 0x191970,\n        \"navy blue\": 0x000080,\n        \"cornflower blue\": 0x6495ED,\n        \"dark slate blue\": 0x483D8B,\n        \"slate blue\": 0x6A5ACD,\n        \"medium slate blue\": 0x7B68EE,\n        \"light slate blue\": 0x8470FF,\n        \"medium blue\": 0x0000CD,\n        \"royal blue\": 0x4169E1,\n        \"dodger blue\": 0x1E90FF,\n        \"deep sky blue\": 0x00BFFF,\n        \"sky blue\": 0x87CEEB,\n        \"light sky blue\": 0x87CEFA,\n        \"steel blue\": 0x4682B4,\n        \"light steel blue\": 0xB0C4DE,\n        \"light blue\": 0xADD8E6,\n        \"powder blue\": 0xB0E0E6,\n        \"pale turquoise\": 0xAFEEEE,\n        \"dark turquoise\": 0x00CED1,\n        \"medium turquoise\": 0x48D1CC,\n        \"light cyan\": 0xE0FFFF,\n        \"cadet blue\": 0x5F9EA0,\n        \"medium aquamarine\": 0x66CDAA,\n        \"aquamarine\": 0x7FFFD4,\n        \"dark green\": 0x006400,\n        \"dark olive green\": 0x556B2F,\n        \"dark sea green\": 0x8FBC8F,\n        \"sea green\": 0x2E8B57,\n        \"medium sea green\": 0x3CB371,\n        \"light sea green\": 0x20B2AA,\n        \"pale green\": 0x98FB98,\n        \"spring green\": 0x00FF7F,\n        \"lawn green\": 0x7CFC00,\n        \"chartreuse\": 0x7FFF00,\n        \"medium spring green\": 0x00FA9A,\n        \"green yellow\": 0xADFF2F,\n        \"lime green\": 0x32CD32,\n        \"yellow green\": 0x9ACD32,\n        \"forest green\": 0x228B22,\n        \"olive drab\": 0x6B8E23,\n        \"dark khaki\": 0xBDB76B,\n        \"khaki\": 0xF0E68C,\n        \"pale goldenrod\": 0xEEE8AA,\n        \"light goldenrod yellow\": 0xFAFAD2,\n        \"light yellow\": 0xFFFFE0,\n        \"light goldenrod\": 0xEEDD82,\n        \"goldenrod\": 0xDAA520,\n        \"dark goldenrod\": 0xB8860B,\n        \"rosy brown\": 0xBC8F8F,\n        \"indian red\": 0xCD5C5C,\n        \"saddle brown\": 0x8B4513,\n        \"sienna\": 0xA0522D,\n        \"peru\": 0xCD853F,\n        \"burlywood\": 0xDEB887,\n        \"beige\": 0xF5F5DC,\n        \"wheat\": 0xF5DEB3,\n        \"sandy brown\": 0xF4A460,\n        \"chocolate\": 0xD2691E,\n        \"firebrick\": 0xB22222,\n        \"dark salmon\": 0xE9967A,\n        \"salmon\": 0xFA8072,\n        \"light salmon\": 0xFFA07A,\n        \"dark orange\": 0xFF8C00,\n        \"coral\": 0xFF7F50,\n        \"light coral\": 0xF08080,\n        \"tomato\": 0xFF6347,\n        \"orange red\": 0xFF4500,\n        \"hot pink\": 0xFF69B4,\n        \"deep pink\": 0xFF1493,\n        \"light pink\": 0xFFB6C1,\n        \"pale violet red\": 0xDB7093,\n        \"medium violet red\": 0xC71585,\n        \"violet red\": 0xD02090,\n        \"plum\": 0xDDA0DD,\n        \"orchid\": 0xDA70D6,\n        \"medium orchid\": 0xBA55D3,\n        \"dark orchid\": 0x9932CC,\n        \"dark violet\": 0x9400D3,\n        \"blue violet\": 0x8A2BE2,\n        \"medium purple\": 0x9370DB,\n        \"thistle\": 0xD8BFD8,\n        \"dark gray\": 0xA9A9A9,\n        \"dark blue\": 0x00008B,\n        \"dark cyan\": 0x008B8B,\n        \"dark magenta\": 0x8B008B,\n        \"dark red\": 0x8B0000,\n        \"light green\": 0x90EE90,\n    }\n)\n\nCOLORSPLUS = UnsortedNamedInts({\"No change\": -1})\nfor i in COLORS:\n    COLORSPLUS[int(i)] = str(i)\n\nKEYCODES = NamedInts(\n    {\n        \"A\": 1,\n        \"B\": 2,\n        \"C\": 3,\n        \"D\": 4,\n        \"E\": 5,\n        \"F\": 6,\n        \"G\": 7,\n        \"H\": 8,\n        \"I\": 9,\n        \"J\": 10,\n        \"K\": 11,\n        \"L\": 12,\n        \"M\": 13,\n        \"N\": 14,\n        \"O\": 15,\n        \"P\": 16,\n        \"Q\": 17,\n        \"R\": 18,\n        \"S\": 19,\n        \"T\": 20,\n        \"U\": 21,\n        \"V\": 22,\n        \"W\": 23,\n        \"X\": 24,\n        \"Y\": 25,\n        \"Z\": 26,\n        \"1\": 27,\n        \"2\": 28,\n        \"3\": 29,\n        \"4\": 30,\n        \"5\": 31,\n        \"6\": 32,\n        \"7\": 33,\n        \"8\": 34,\n        \"9\": 35,\n        \"0\": 36,\n        \"ENTER\": 37,\n        \"ESC\": 38,\n        \"BACKSPACE\": 39,\n        \"TAB\": 40,\n        \"SPACE\": 41,\n        \"-\": 42,\n        \"=\": 43,\n        \"[\": 44,\n        \"]\": 45,\n        \"\\\\\": 45,\n        \"~\": 47,\n        \";\": 48,\n        \"'\": 49,\n        \"`\": 50,\n        \",\": 51,\n        \".\": 52,\n        \"/\": 53,\n        \"CAPS LOCK\": 54,\n        \"F1\": 55,\n        \"F2\": 56,\n        \"F3\": 57,\n        \"F4\": 58,\n        \"F5\": 59,\n        \"F6\": 60,\n        \"F7\": 61,\n        \"F8\": 62,\n        \"F9\": 63,\n        \"F10\": 64,\n        \"F11\": 65,\n        \"F12\": 66,\n        \"PRINT\": 67,\n        \"SCROLL LOCK\": 68,\n        \"PASTE\": 69,\n        \"INSERT\": 70,\n        \"HOME\": 71,\n        \"PAGE UP\": 72,\n        \"DELETE\": 73,\n        \"END\": 74,\n        \"PAGE DOWN\": 75,\n        \"RIGHT\": 76,\n        \"LEFT\": 77,\n        \"DOWN\": 78,\n        \"UP\": 79,\n        \"NUMLOCK\": 80,\n        \"KEYPAD /\": 81,\n        \"KEYPAD *\": 82,\n        \"KEYPAD -\": 83,\n        \"KEYPAD +\": 84,\n        \"KEYPAD ENTER\": 85,\n        \"KEYPAD 1\": 86,\n        \"KEYPAD 2\": 87,\n        \"KEYPAD 3\": 88,\n        \"KEYPAD 4\": 89,\n        \"KEYPAD 5\": 90,\n        \"KEYPAD 6\": 91,\n        \"KEYPAD 7\": 92,\n        \"KEYPAD 8\": 93,\n        \"KEYPAD 9\": 94,\n        \"KEYPAD 0\": 95,\n        \"KEYPAD .\": 96,\n        \"COMPOSE\": 98,\n        \"POWER\": 99,\n        \"LEFT CTRL\": 104,\n        \"LEFT SHIFT\": 105,\n        \"LEFT ALT\": 106,\n        \"LEFT WINDOWS\": 107,\n        \"RIGHT CTRL\": 108,\n        \"RIGHT SHIFT\": 109,\n        \"RIGHT ALTGR\": 110,\n        \"RIGHT WINDOWS\": 111,\n        \"BRIGHTNESS\": 153,\n        \"PAUSE\": 155,\n        \"MUTE\": 156,\n        \"NEXT\": 157,\n        \"PREVIOUS\": 158,\n        \"G1\": 180,\n        \"G2\": 181,\n        \"G3\": 182,\n        \"G4\": 183,\n        \"G5\": 184,\n        \"LOGO\": 210,\n    }\n)\n\n\n# load in override dictionary for KEYCODES\ntry:\n    if os.path.isfile(_keys_file_path):\n        with open(_keys_file_path) as keys_file:\n            keys = yaml.safe_load(keys_file)\n            if isinstance(keys, dict):\n                keys = NamedInts(**keys)\n                for k in KEYCODES:\n                    if int(k) not in keys and str(k) not in keys:\n                        keys[int(k)] = str(k)\n                KEYCODES = keys\nexcept Exception as e:\n    print(e)\n"
  },
  {
    "path": "lib/solaar/__init__.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport pkgutil\nimport subprocess\nimport sys\n\nNAME = \"Solaar\"\n\ntry:\n    __version__ = (\n        subprocess.check_output(\n            [\n                \"git\",\n                \"describe\",\n                \"--always\",\n            ],\n            cwd=sys.path[0],\n            stderr=subprocess.DEVNULL,\n        )\n        .strip()\n        .decode()\n    )\nexcept Exception:\n    try:\n        __version__ = pkgutil.get_data(\"solaar\", \"commit\").strip().decode()\n    except Exception:\n        __version__ = pkgutil.get_data(\"solaar\", \"version\").strip().decode()\n"
  },
  {
    "path": "lib/solaar/cli/__init__.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport argparse\nimport logging\nimport sys\n\nfrom importlib import import_module\nfrom traceback import extract_tb\nfrom traceback import format_exc\n\nfrom logitech_receiver import base\nfrom logitech_receiver import device\nfrom logitech_receiver import receiver\n\nfrom solaar import NAME\n\nlogger = logging.getLogger(__name__)\n\n\ndef _create_parser():\n    parser = argparse.ArgumentParser(\n        prog=NAME.lower(),\n        add_help=False,\n        epilog=f\"For details on individual actions, run `{NAME.lower()} <action> --help`.\",\n    )\n    subparsers = parser.add_subparsers(title=\"actions\", help=\"command-line action to perform\")\n\n    sp = subparsers.add_parser(\"show\", description=\"Show information about device or all devices.\")\n    sp.add_argument(\n        \"device\",\n        nargs=\"?\",\n        default=\"all\",\n        help=\"device to show information about; may be a device number (1..6), a serial number, \"\n        'a substring of a device\\'s name, or \"all\" (the default)',\n    )\n    sp.set_defaults(action=\"show\")\n\n    sp = subparsers.add_parser(\"probe\", description=\"Probe a receiver (debugging use only).\")\n    sp.add_argument(\n        \"receiver\", nargs=\"?\", help=\"select receiver by name substring or serial number when more than one is present\"\n    )\n    sp.set_defaults(action=\"probe\")\n\n    sp = subparsers.add_parser(\n        \"profiles\",\n        description=\"Print or load YAML dump of profiles.\",\n        epilog=\"Only works on active devices.\",\n    )\n    sp.add_argument(\n        \"device\",\n        help=\"device to read or load profiles; may be a device number (1..6), a serial number, \"\n        \"or a substring of a device's name\",\n    )\n    sp.add_argument(\"profiles\", nargs=\"?\", help=\"file containing YAML dump of profiles to load\")\n    sp.set_defaults(action=\"profiles\")\n\n    sp = subparsers.add_parser(\n        \"config\",\n        description=\"Print or load device-specific settings.  Only some settings can be loaded.  \"\n        \"Loading complex settings uses the same syntax as in ~/.config/solaar/config.yaml\",\n        epilog=\"Please note that configuration only works on active devices.\",\n    )\n    sp.add_argument(\n        \"device\",\n        help=\"device to configure; may be a device number (1..6), a serial number, or a substring of a device's name\",\n    )\n    sp.add_argument(\"setting\", nargs=\"?\", help=\"device-specific setting; leave empty to list available settings\")\n    sp.add_argument(\"value_key\", nargs=\"?\", help=\"new value for the setting or key for keyed settings\")\n    sp.add_argument(\"extra_subkey\", nargs=\"?\", help=\"value for keyed or subkey for subkeyed settings\")\n    sp.add_argument(\"extra2\", nargs=\"?\", help=\"value for subkeyed settings\")\n    sp.set_defaults(action=\"config\")\n\n    sp = subparsers.add_parser(\n        \"pair\",\n        description=\"Pair a new device with a receiver.  The device has to be compatible with the receiver.\",\n        epilog=\"The Logitech Unifying Receiver supports up to 6 paired devices at the same time.\",\n    )\n    sp.add_argument(\n        \"receiver\", nargs=\"?\", help=\"select receiver by name substring or serial number when more than one is present\"\n    )\n    sp.set_defaults(action=\"pair\")\n\n    sp = subparsers.add_parser(\"unpair\", description=\"Unpair a device from its receiver.  Not all receivers allow unpairing.\")\n    sp.add_argument(\n        \"device\",\n        help=\"device to unpair; may be a device number (1..6), a serial number, \" \"or a substring of a device's name.\",\n    )\n    sp.set_defaults(action=\"unpair\")\n\n    return parser, subparsers.choices\n\n\n_cli_parser, actions = _create_parser()\nprint_help = _cli_parser.print_help\n\n\ndef _receivers(dev_path=None):\n    for dev_info in base.receivers():\n        if dev_path is not None and dev_path != dev_info.path:\n            continue\n        try:\n            r = receiver.create_receiver(base, dev_info)\n            logger.debug(\"[%s] => %s\", dev_info.path, r)\n            if r:\n                yield r\n        except Exception as e:\n            logger.exception(\"opening \" + str(dev_info))\n            sys.exit(f\"{NAME.lower()}: error: {str(e)}\")\n\n\ndef _receivers_and_devices(dev_path=None):\n    for dev_info in base.receivers_and_devices():\n        if dev_path is not None and dev_path != dev_info.path:\n            continue\n        try:\n            if dev_info.isDevice:\n                d = device.create_device(base, dev_info)\n            else:\n                d = receiver.create_receiver(base, dev_info)\n\n            logger.debug(\"[%s] => %s\", dev_info.path, d)\n            if d is not None:\n                yield d\n        except Exception as e:\n            logger.exception(\"opening \" + str(dev_info))\n            sys.exit(f\"{NAME.lower()}: error: {str(e)}\")\n\n\ndef _find_receiver(receivers, name):\n    assert receivers\n    assert name\n\n    for r in receivers:\n        if name in r.name.lower() or (r.serial is not None and name == r.serial.lower()):\n            return r\n\n\ndef _find_device(receivers, name):\n    assert receivers\n    assert name\n\n    number = None\n    if len(name) == 1:\n        try:\n            number = int(name)\n        except Exception:\n            pass\n        else:\n            assert not (number < 0)\n            if number > 6:\n                number = None\n\n    for r in receivers:\n        if not r.isDevice:  # look for nth device of receiver\n            if number:\n                dev = r[number]\n                if dev:\n                    yield dev\n            count = r.count()\n        else:  # wired device, make a device list from it\n            r.ping()\n            r = [r]\n            count = 1\n\n        for dev in r:\n            if (\n                name == dev.serial.lower()\n                or name == dev.codename.lower()\n                or name == str(dev.kind).lower()\n                or name in dev.name.lower()\n            ):\n                yield dev\n            count -= 1\n            if not count:\n                break\n\n\ndef run(cli_args=None, hidraw_path=None):\n    if cli_args:\n        action = cli_args[0]\n        args = _cli_parser.parse_args(cli_args)\n    else:\n        args = _cli_parser.parse_args()\n        # Python 3 has an undocumented 'feature' that breaks parsing empty args\n        # http://bugs.python.org/issue16308\n        if \"cmd\" not in args:\n            _cli_parser.print_usage(sys.stderr)\n            sys.stderr.write(f\"{NAME.lower()}: error: too few arguments\\n\")\n            sys.exit(2)\n        action = args.action\n    assert action in actions\n\n    try:\n        if action == \"show\" or action == \"probe\" or action == \"config\" or action == \"profiles\":\n            c = list(_receivers_and_devices(hidraw_path))\n        else:\n            c = list(_receivers(hidraw_path))\n        if not c:\n            raise Exception(\n                'No supported device found. Use \"lsusb\" and \"bluetoothctl devices Connected\" to list connected devices.'\n            )\n        m = import_module(\".\" + action, package=__name__)\n        m.run(c, args, _find_receiver, _find_device)\n    except AssertionError:\n        tb_last = extract_tb(sys.exc_info()[2])[-1]\n        sys.exit(f\"{NAME.lower()}: assertion failed: {tb_last[0]} line {int(tb_last[1])}\")\n    except Exception:\n        sys.exit(f\"{NAME.lower()}: error: {format_exc()}\")\n"
  },
  {
    "path": "lib/solaar/cli/config.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport yaml\n\nfrom logitech_receiver import settings\nfrom logitech_receiver import settings_templates\nfrom logitech_receiver.common import NamedInts\nfrom logitech_receiver.settings_templates import SettingsProtocol\n\nfrom solaar import configuration\n\nAPP_ID = \"io.github.pwr_solaar.solaar\"\n\n\ndef _print_setting(s, verbose=True):\n    print(\"#\", s.label)\n    if verbose:\n        if s.description:\n            print(\"#\", s.description.replace(\"\\n\", \" \"))\n        if s.kind == settings.Kind.TOGGLE:\n            print(\"#   possible values: on/true/t/yes/y/1 or off/false/f/no/n/0 or Toggle/~\")\n        elif s.kind == settings.Kind.CHOICE:\n            print(\n                \"#   possible values: one of [\",\n                \", \".join(str(v) for v in s.choices),\n                \"], or higher/lower/highest/max/lowest/min\",\n            )\n        else:\n            # wtf?\n            pass\n    value = s.read(cached=False)\n    if value is None:\n        print(s.name, \"= ? (failed to read from device)\")\n    else:\n        print(s.name, \"=\", s.val_to_string(value))\n\n\ndef _print_setting_keyed(s, key, verbose=True):\n    print(\"#\", s.label)\n    if verbose:\n        if s.description:\n            print(\"#\", s.description.replace(\"\\n\", \" \"))\n        if s.kind == settings.Kind.MULTIPLE_TOGGLE:\n            k = next((k for k in s._labels if key == k), None)\n            if k is None:\n                print(s.name, \"=? (key not found)\")\n            else:\n                print(\"#   possible values: on/true/t/yes/y/1 or off/false/f/no/n/0 or Toggle/~\")\n                value = s.read(cached=False)\n                if value is None:\n                    print(s.name, \"= ? (failed to read from device)\")\n                else:\n                    print(s.name, s.val_to_string({k: value[str(int(k))]}))\n        elif s.kind == settings.Kind.MAP_CHOICE:\n            k = next((k for k in s.choices.keys() if key == k), None)\n            if k is None:\n                print(s.name, \"=? (key not found)\")\n            else:\n                print(\"#   possible values: one of [\", \", \".join(str(v) for v in s.choices[k]), \"]\")\n                value = s.read(cached=False)\n                if value is None:\n                    print(s.name, \"= ? (failed to read from device)\")\n                else:\n                    print(s.name, s.val_to_string({k: value[int(k)]}))\n\n\ndef to_int(s):\n    try:\n        return int(s)\n    except ValueError:\n        return None\n\n\ndef select_choice(value, choices, setting, key):\n    lvalue = value.lower()\n    ivalue = to_int(value)\n    val = None\n    for choice in choices:\n        if value == str(choice):\n            val = choice\n            break\n    if val is not None:\n        value = val\n    elif ivalue is not None and 1 <= ivalue <= len(choices):\n        value = choices[ivalue - 1]\n    elif lvalue in (\"higher\", \"lower\"):\n        old_value = setting.read() if key is None else setting.read_key(key)\n        if old_value is None:\n            raise Exception(f\"{setting.name}: could not read current value\")\n        if lvalue == \"lower\":\n            lower_values = choices[:old_value]\n            value = lower_values[-1] if lower_values else choices[:][0]\n        elif lvalue == \"higher\":\n            higher_values = choices[old_value + 1 :]\n            value = higher_values[0] if higher_values else choices[:][-1]\n    elif lvalue in (\"highest\", \"max\", \"first\"):\n        value = choices[:][-1]\n    elif lvalue in (\"lowest\", \"min\", \"last\"):\n        value = choices[:][0]\n    else:\n        raise Exception(f\"{setting.name}: possible values are [{', '.join(str(v) for v in choices)}]\")\n    return value\n\n\ndef select_toggle(value, setting, key=None):\n    if value.lower() in (\"toggle\", \"~\"):\n        value = not (setting.read() if key is None else setting.read()[str(int(key))])\n    else:\n        try:\n            value = bool(int(value))\n        except Exception as exc:\n            if value.lower() in (\"true\", \"yes\", \"on\", \"t\", \"y\"):\n                value = True\n            elif value.lower() in (\"false\", \"no\", \"off\", \"f\", \"n\"):\n                value = False\n            else:\n                raise Exception(f\"{setting.name}: don't know how to interpret '{value}' as boolean\") from exc\n    return value\n\n\ndef select_range(value, setting):\n    try:\n        value = int(value)\n    except ValueError as exc:\n        raise Exception(f\"{setting.name}: can't interpret '{value}' as integer\") from exc\n    minimum, maximum = setting.range\n    if value < minimum or value > maximum:\n        raise Exception(f\"{setting.name}: value '{value}' out of bounds\")\n    return value\n\n\ndef run(receivers, args, _find_receiver, find_device):\n    assert receivers\n    assert args.device\n\n    device_name = args.device.lower()\n\n    dev = None\n    for dev in find_device(receivers, device_name):\n        if dev.ping():\n            break\n        dev = None\n\n    if not dev:\n        raise Exception(f\"no online device found matching '{device_name}'\")\n\n    if not args.setting:  # print all settings, so first set them all up\n        if not dev.settings:\n            raise Exception(f\"no settings for {dev.name}\")\n        configuration.attach_to(dev)\n        print(dev.name, f\"({dev.codename}) [{dev.wpid}:{dev.serial}]\")\n        for s in dev.settings:\n            print(\"\")\n            _print_setting(s)\n        return\n\n    setting_name = args.setting.lower()\n    setting = settings_templates.check_feature_setting(dev, setting_name)\n    if not setting and dev.descriptor and dev.descriptor.settings:\n        for sclass in dev.descriptor.settings:\n            if sclass.register and sclass.name == setting_name:\n                try:\n                    setting = sclass.build(dev)\n                except Exception:\n                    setting = None\n    if setting is None:\n        raise Exception(f\"no setting '{args.setting}' for {dev.name}\")\n\n    if args.value_key is None:\n        _print_setting(setting)\n        return\n\n    remote = False\n    try:\n        import gi\n\n        gi.require_version(\"Gtk\", \"3.0\")\n        from gi.repository import Gio\n        from gi.repository import Gtk\n\n        if Gtk.init_check()[0]:  # can Gtk be initialized?\n            application = Gtk.Application.new(APP_ID, Gio.ApplicationFlags.HANDLES_COMMAND_LINE)\n            application.register()\n            remote = application.get_is_remote()\n    except Exception:\n        pass\n\n    # don't save configuration here because we might want the Solaar GUI to make the change\n    result, message, value = set(dev, setting, args, False)\n    if message is not None:\n        print(message)\n        if result is None:\n            raise Exception(f\"{setting.name}: failed to set value '{str(value)}' [{value!r}]\")\n\n    # if the Solaar UI is running tell it to also perform the set, otherwise save the change in the configuration file\n    if remote:\n        argl = [\"config\", dev.serial or dev.unitId, setting.name]\n        argl.extend([a for a in [args.value_key, args.extra_subkey, args.extra2] if a is not None])\n        args = yaml.dump(argl)\n        application.run(args)\n    else:\n        if dev.persister and setting.persist:\n            dev.persister[setting.name] = setting._value\n\n\ndef set(dev, setting: SettingsProtocol, args, save):\n    if setting.kind == settings.Kind.TOGGLE:\n        value = select_toggle(args.value_key, setting)\n        args.value_key = value\n        message = f\"Setting {setting.name} of {dev.name} to {value}\"\n        result = setting.write(value, save=save)\n\n    elif setting.kind == settings.Kind.RANGE:\n        value = select_range(args.value_key, setting)\n        args.value_key = value\n        message = f\"Setting {setting.name} of {dev.name} to {value}\"\n        result = setting.write(value, save=save)\n\n    elif setting.kind == settings.Kind.CHOICE:\n        value = select_choice(args.value_key, setting.choices, setting, None)\n        args.value_key = int(value)\n        message = f\"Setting {setting.name} of {dev.name} to {value}\"\n        result = setting.write(value, save=save)\n\n    elif setting.kind == settings.Kind.MAP_CHOICE:\n        if args.extra_subkey is None:\n            _print_setting_keyed(setting, args.value_key)\n            return None, None, None\n        key = args.value_key\n        ikey = to_int(key)\n        k = next((k for k in setting.choices.keys() if key == k), None)\n        if k is None and ikey is not None:\n            k = next((k for k in setting.choices.keys() if ikey == k), None)\n        if k is not None:\n            value = select_choice(args.extra_subkey, setting.choices[k], setting, key)\n            args.extra_subkey = int(value)\n            args.value_key = str(int(k))\n        else:\n            raise Exception(f\"{setting.name}: key '{key}' not in setting\")\n        message = f\"Setting {setting.name} of {dev.name} key {k!r} to {value!r}\"\n        result = setting.write_key_value(int(k), value, save=save)\n\n    elif setting.kind == settings.Kind.MULTIPLE_TOGGLE:\n        if args.extra_subkey is None:\n            _print_setting_keyed(setting, args.value_key)\n            return None, None, None\n        key = args.value_key\n        all_keys = getattr(setting, \"choices_universe\", None)\n        ikey = all_keys[int(key) if key.isdigit() else key] if isinstance(all_keys, NamedInts) else to_int(key)\n        k = next((k for k in setting._labels if key == k), None)\n        if k is None and ikey is not None:\n            k = next((k for k in setting._labels if ikey == k), None)\n        if k is not None:\n            value = select_toggle(args.extra_subkey, setting, key=k)\n            args.extra_subkey = value\n            args.value_key = str(int(k))\n        else:\n            raise Exception(f\"{setting.name}: key '{key}' not in setting\")\n        message = f\"Setting {setting.name} key {k!r} to {value!r}\"\n        result = setting.write_key_value(str(int(k)), value, save=save)\n\n    elif setting.kind == settings.Kind.MULTIPLE_RANGE:\n        if args.extra_subkey is None:\n            raise Exception(f\"{setting.name}: setting needs both key and value to set\")\n        key = args.value_key\n        all_keys = getattr(setting, \"choices_universe\", None)\n        ikey = all_keys[int(key) if key.isdigit() else key] if isinstance(all_keys, NamedInts) else to_int(key)\n        if args.extra2 is None or to_int(args.extra2) is None:\n            raise Exception(f\"{setting.name}: setting needs an integer value, not {args.extra2}\")\n        if not setting._value:  # ensure that there are values to look through\n            setting.read()\n        k = next((k for k in setting._value if key == ikey or key.isdigit() and ikey == int(key)), None)\n        if k is None and ikey is not None:\n            k = next((k for k in setting._value if ikey == k), None)\n        item = setting._value[k]\n        if args.extra_subkey in item.keys():\n            item[args.extra_subkey] = to_int(args.extra2)\n            args.value_key = str(int(k))\n        else:\n            raise Exception(f\"{setting.name}: key '{key}' not in setting\")\n        message = f\"Setting {setting.name} key {k} parameter {args.extra_subkey} to {item[args.extra_subkey]!r}\"\n        result = setting.write_key_value(int(k), item, save=save)\n        value = item\n\n    elif setting.kind == settings.Kind.MAP_RANGE:\n        if args.extra_subkey is None:\n            _print_setting_keyed(setting, args.value_key)\n            return None, None, None\n        key = int(args.value_key)\n        value = int(args.extra_subkey)\n        if key not in setting._device_object:\n            raise Exception(f\"{setting.name}: key '{key}' not in setting\")\n        message = f\"Setting {setting.name} of {dev.name} key {key} to {value}\"\n        result = setting.write_key_value(key, value, save=save)\n\n    elif setting.kind == settings.Kind.HETERO:\n        value = yaml.safe_load(args.value_key)\n        args.value_key = value\n        message = f\"Setting {setting.name} of {dev.name} to {value}\"\n        result = setting.write(value, save=save)\n\n    else:\n        print(f\"Setting {setting.name}, with kind {setting.kind.name}, not implemented\")\n        raise Exception(\"NotImplemented\")\n\n    return result, message, value\n"
  },
  {
    "path": "lib/solaar/cli/pair.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom time import time\n\nfrom logitech_receiver import base\nfrom logitech_receiver import hidpp10\nfrom logitech_receiver import hidpp10_constants\nfrom logitech_receiver import notifications\n\n_hidpp10 = hidpp10.Hidpp10()\n\n\ndef run(receivers, args, find_receiver, _ignore):\n    assert receivers\n\n    if args.receiver:\n        receiver_name = args.receiver.lower()\n        receiver = find_receiver(receivers, receiver_name)\n        if not receiver:\n            raise Exception(f\"no receiver found matching '{receiver_name}'\")\n    else:\n        receiver = receivers[0]\n\n    assert receiver\n\n    # check if it's necessary to set the notification flags\n    old_notification_flags = _hidpp10.get_notification_flags(receiver)\n    if not (old_notification_flags & hidpp10_constants.NotificationFlag.WIRELESS):\n        _hidpp10.set_notification_flags(receiver, old_notification_flags | hidpp10_constants.NotificationFlag.WIRELESS)\n\n    # get all current devices\n    known_devices = [dev.number for dev in receiver]\n\n    class _HandleWithNotificationHook(int):\n        def notifications_hook(self, n):\n            nonlocal known_devices\n            assert n\n            if n.devnumber == 0xFF:\n                notifications.process(receiver, n)\n            elif n.sub_id == 0x41 and len(n.data) == base.SHORT_MESSAGE_SIZE - 4:\n                kd, known_devices = known_devices, None  # only process one connection notification\n                if kd is not None:\n                    if n.devnumber not in kd:\n                        receiver.pairing.new_device = receiver.register_new_device(n.devnumber, n)\n                    elif receiver.re_pairs:\n                        del receiver[n.devnumber]  # get rid of information on device re-paired away\n                        receiver.pairing.new_device = receiver.register_new_device(n.devnumber, n)\n\n    timeout = 30  # seconds\n    receiver.handle = _HandleWithNotificationHook(receiver.handle)\n\n    if receiver.receiver_kind == \"bolt\":  # Bolt receivers require authentication to pair a device\n        receiver.discover(timeout=timeout)\n        print(\"Bolt Pairing: long-press the pairing key or button on your device (timing out in\", timeout, \"seconds).\")\n        pairing_start = time()\n        patience = 5  # the discovering notification may come slightly later, so be patient\n        while receiver.pairing.discovering or time() - pairing_start < patience:\n            if receiver.pairing.device_address and receiver.pairing.device_authentication and receiver.pairing.device_name:\n                break\n            n = base.read(receiver.handle)\n            n = base.make_notification(*n) if n else None\n            if n:\n                receiver.handle.notifications_hook(n)\n        address = receiver.pairing.device_address\n        name = receiver.pairing.device_name\n        authentication = receiver.pairing.device_authentication\n        kind = receiver.pairing.device_kind\n        if authentication is None:  # no compatible device stepped forward\n            print(\"No Bolt-compatible device requested pairing.\")\n        else:\n            print(f\"Bolt Pairing: discovered {name}\")\n            receiver.pair_device(\n                address=address,\n                authentication=authentication,\n                entropy=20 if kind == hidpp10_constants.DEVICE_KIND.keyboard else 10,\n            )\n            pairing_start = time()\n            patience = 5  # the discovering notification may come slightly later, so be patient\n            while receiver.pairing.lock_open or time() - pairing_start < patience:\n                if receiver.pairing.device_passkey:\n                    break\n                n = base.read(receiver.handle)\n                n = base.make_notification(*n) if n else None\n                if n:\n                    receiver.handle.notifications_hook(n)\n            if authentication & 0x01:\n                print(f\"Bolt Pairing: type passkey {receiver.pairing.device_passkey} and then press the enter key\")\n            else:\n                passkey = f\"{int(receiver.pairing.device_passkey):010b}\"\n                passkey = \", \".join([\"right\" if bit == \"1\" else \"left\" for bit in passkey])\n                print(f\"Bolt Pairing: press {passkey}\")\n                print(\"and then press left and right buttons simultaneously\")\n            while receiver.pairing.lock_open:\n                n = base.read(receiver.handle)\n                n = base.make_notification(*n) if n else None\n                if n:\n                    receiver.handle.notifications_hook(n)\n\n    else:\n        receiver.set_lock(False, timeout=timeout)\n        print(\"Pairing: Turn your device on or press, hold, and release\")\n        print(\"a channel button or the channel switch button.\")\n        print(\"Timing out in\", timeout, \"seconds.\")\n        pairing_start = time()\n        patience = 5  # the lock-open notification may come slightly later, wait for it a bit\n        while receiver.pairing.lock_open or time() - pairing_start < patience:\n            n = base.read(receiver.handle)\n            if n:\n                n = base.make_notification(*n)\n                if n:\n                    receiver.handle.notifications_hook(n)\n\n    if not (old_notification_flags & hidpp10_constants.NotificationFlag.WIRELESS):\n        # only clear the flags if they weren't set before, otherwise a\n        # concurrently running Solaar app might stop working properly\n        _hidpp10.set_notification_flags(receiver, old_notification_flags)\n\n    if receiver.pairing.new_device:\n        dev = receiver.pairing.new_device\n        print(f\"Paired device {int(dev.number)}: {dev.name} ({dev.codename}) [{dev.wpid}:{dev.serial}]\")\n    else:\n        error = receiver.pairing.error\n        if error:\n            raise Exception(f\"pairing failed: {error}\")\n        else:\n            print(\"Paired device\")  # this is better than an error\n"
  },
  {
    "path": "lib/solaar/cli/probe.py",
    "content": "## Copyright (C) 2020\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom logitech_receiver import base\nfrom logitech_receiver.common import strhex\nfrom logitech_receiver.hidpp10_constants import ErrorCode\nfrom logitech_receiver.hidpp10_constants import Registers\n\nfrom solaar.cli.show import _print_device\nfrom solaar.cli.show import _print_receiver\n\n\ndef run(receivers, args, find_receiver, _ignore):\n    assert receivers\n\n    if args.receiver:\n        receiver_name = args.receiver.lower()\n        receiver = find_receiver(receivers, receiver_name)\n        if not receiver:\n            raise Exception(f\"no receiver found matching '{receiver_name}'\")\n    else:\n        receiver = receivers[0]\n\n    assert receiver is not None\n\n    if receiver.isDevice:\n        _print_device(receiver, 1)\n        return\n\n    _print_receiver(receiver)\n\n    print(\"\")\n    print(\"  Register Dump\")\n    rgst = receiver.read_register(Registers.NOTIFICATIONS)\n    print(\"    Notifications         %#04x: %s\" % (Registers.NOTIFICATIONS % 0x100, f\"0x{strhex(rgst)}\" if rgst else \"None\"))\n    rgst = receiver.read_register(Registers.RECEIVER_CONNECTION)\n    print(\n        \"    Connection State      %#04x: %s\"\n        % (Registers.RECEIVER_CONNECTION % 0x100, f\"0x{strhex(rgst)}\" if rgst else \"None\")\n    )\n    rgst = receiver.read_register(Registers.DEVICES_ACTIVITY)\n    print(\n        \"    Device Activity       %#04x: %s\" % (Registers.DEVICES_ACTIVITY % 0x100, f\"0x{strhex(rgst)}\" if rgst else \"None\")\n    )\n\n    for sub_reg in range(0, 16):\n        rgst = receiver.read_register(Registers.RECEIVER_INFO, sub_reg)\n        print(\n            \"    Pairing Register %#04x %#04x: %s\"\n            % (Registers.RECEIVER_INFO % 0x100, sub_reg, f\"0x{strhex(rgst)}\" if rgst else \"None\")\n        )\n    for device in range(0, 7):\n        for sub_reg in [0x10, 0x20, 0x30, 0x50]:\n            rgst = receiver.read_register(Registers.RECEIVER_INFO, sub_reg + device)\n            print(\n                \"    Pairing Register %#04x %#04x: %s\"\n                % (Registers.RECEIVER_INFO % 0x100, sub_reg + device, f\"0x{strhex(rgst)}\" if rgst else \"None\")\n            )\n        rgst = receiver.read_register(Registers.RECEIVER_INFO, 0x40 + device)\n        print(\n            \"    Pairing Name     %#04x %#02x: %s\"\n            % (Registers.RECEIVER_INFO % 0x100, 0x40 + device, rgst[2 : 2 + ord(rgst[1:2])] if rgst else \"None\")\n        )\n        for part in range(1, 4):\n            rgst = receiver.read_register(Registers.RECEIVER_INFO, 0x60 + device, part)\n            print(\n                \"    Pairing Name     %#04x %#02x %#02x: %2d %s\"\n                % (\n                    Registers.RECEIVER_INFO % 0x100,\n                    0x60 + device,\n                    part,\n                    ord(rgst[2:3]) if rgst else 0,\n                    rgst[3 : 3 + ord(rgst[2:3])] if rgst else \"None\",\n                )\n            )\n    for sub_reg in range(0, 5):\n        rgst = receiver.read_register(Registers.FIRMWARE, sub_reg)\n        print(\n            \"    Firmware         %#04x %#04x: %s\"\n            % (Registers.FIRMWARE % 0x100, sub_reg, f\"0x{strhex(rgst)}\" if rgst is not None else \"None\")\n        )\n\n    print(\"\")\n    for reg in range(0, 0xFF):\n        for offset, reg_type in [(0x00, \"Short\"), (0x200, \"Long\")]:\n            last = None\n            for sub in range(0, 0xFF):\n                rgst = base.request(receiver.handle, 0xFF, 0x8100 | (offset + reg), sub, return_error=True)\n                if isinstance(rgst, int) and rgst == ErrorCode.INVALID_ADDRESS:\n                    break\n                elif isinstance(rgst, int) and rgst == ErrorCode.INVALID_VALUE:\n                    continue\n                else:\n                    if not isinstance(last, bytes) or not isinstance(rgst, bytes) or last != rgst:\n                        print(\n                            \"    Register %s   %#04x %#04x: %s\"\n                            % (reg_type, reg, sub, \"0x\" + strhex(rgst) if isinstance(rgst, bytes) else str(rgst))\n                        )\n                last = rgst\n"
  },
  {
    "path": "lib/solaar/cli/profiles.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport traceback\n\nimport yaml\n\nfrom logitech_receiver.hidpp20 import OnboardProfiles\nfrom logitech_receiver.hidpp20 import OnboardProfilesVersion\n\n\ndef run(receivers, args, find_receiver, find_device):\n    assert receivers\n    assert args.device\n\n    device_name = args.device.lower()\n    profiles_file = args.profiles\n\n    dev = None\n    for dev in find_device(receivers, device_name):\n        if dev.ping():\n            break\n        dev = None\n\n    if not dev:\n        raise Exception(f\"no online device found matching '{device_name}'\")\n\n    if not dev.online:\n        print(f\"Device {dev.name} is offline.\")\n    elif not dev.profiles:\n        print(f\"Device {dev.name} has no onboard profiles that Solaar supports.\")\n    elif not profiles_file:\n        print(f\"#Dumping profiles from {dev.name}\")\n        print(yaml.dump(dev.profiles))\n    else:\n        try:\n            with open(profiles_file, \"r\") as f:\n                print(f\"Reading profiles from {profiles_file}\")\n                profiles = yaml.safe_load(f)\n                if not isinstance(profiles, OnboardProfiles):\n                    print(\"Profiles file does not contain current onboard profiles\")\n                elif getattr(profiles, \"version\", None) != OnboardProfilesVersion:\n                    version = getattr(profiles, \"version\", None)\n                    print(f\"Missing or incorrect profile version {version} in loaded profile\")\n                elif getattr(profiles, \"name\", None) != dev.name:\n                    name = getattr(profiles, \"name\", None)\n                    print(f\"Different device name {name} in loaded profile\")\n                else:\n                    print(f\"Loading profiles into {dev.name}\")\n                    written = profiles.write(dev)\n                    print(f\"Wrote {written} sectors to {dev.name}\")\n        except Exception as exc:\n            print(\"Profiles not written:\", exc)\n            print(traceback.format_exc())\n"
  },
  {
    "path": "lib/solaar/cli/show.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom logitech_receiver import common\nfrom logitech_receiver import exceptions\nfrom logitech_receiver import hidpp10\nfrom logitech_receiver import hidpp10_constants\nfrom logitech_receiver import hidpp20\nfrom logitech_receiver import hidpp20_constants\nfrom logitech_receiver import receiver\nfrom logitech_receiver import settings_templates\nfrom logitech_receiver.common import LOGITECH_VENDOR_ID\nfrom logitech_receiver.common import NamedInt\nfrom logitech_receiver.common import strhex\nfrom logitech_receiver.hidpp20_constants import SupportedFeature\n\nfrom solaar import NAME\nfrom solaar import __version__\n\n_hidpp10 = hidpp10.Hidpp10()\n_hidpp20 = hidpp20.Hidpp20()\n\n\ndef _print_receiver(receiver):\n    paired_count = receiver.count()\n\n    print(receiver.name)\n    print(\"  Device path  :\", receiver.path)\n    print(f\"  USB id       : {LOGITECH_VENDOR_ID:04x}:{receiver.product_id}\")\n    print(\"  Serial       :\", receiver.serial)\n    pending = hidpp10.get_configuration_pending_flags(receiver)\n    if pending:\n        print(f\"  C Pending    : {pending:02x}\")\n    if receiver.firmware:\n        for f in receiver.firmware:\n            print(\"    %-11s: %s\" % (f.kind, f.version))\n\n    print(\"  Has\", paired_count, f\"paired device(s) out of a maximum of {int(receiver.max_devices)}.\")\n    if receiver.remaining_pairings() and receiver.remaining_pairings() >= 0:\n        print(f\"  Has {int(receiver.remaining_pairings())} successful pairing(s) remaining.\")\n\n    notification_flags = _hidpp10.get_notification_flags(receiver)\n    if notification_flags is not None:\n        if notification_flags:\n            notification_names = hidpp10_constants.NotificationFlag.flag_names(notification_flags)\n            print(f\"  Notifications: {', '.join(notification_names)} (0x{notification_flags.value:06X})\")\n        else:\n            print(\"  Notifications: (none)\")\n\n    activity = receiver.read_register(hidpp10_constants.Registers.DEVICES_ACTIVITY)\n    if activity:\n        activity = [(d, ord(activity[d - 1 : d])) for d in range(1, receiver.max_devices)]\n        activity_text = \", \".join(f\"{int(d)}={int(a)}\" for d, a in activity if a > 0)\n        print(\"  Device activity counters:\", activity_text or \"(empty)\")\n\n\ndef _battery_text(level) -> str:\n    if level is None:\n        return \"N/A\"\n    elif isinstance(level, NamedInt):\n        return str(level)\n    else:\n        return f\"{int(level)}%\"\n\n\ndef _battery_line(dev):\n    battery = dev.battery()\n    if battery is not None:\n        level, nextLevel, status, voltage = battery.level, battery.next_level, battery.status, battery.voltage\n        text = _battery_text(level)\n        if voltage is not None:\n            text = f\"{text} {voltage}mV \"\n        nextText = \"\" if nextLevel is None else f\", next level {_battery_text(nextLevel)}\"\n        print(f\"     Battery: {text}, {status}{nextText}.\")\n    else:\n        print(\"     Battery status unavailable.\")\n\n\ndef _print_device(dev, num=None):\n    assert dev is not None\n    # try to ping the device to see if it actually exists and to wake it up\n    try:\n        dev.ping()\n    except exceptions.NoSuchDevice:\n        print(f\"  {num}: Device not found\" or dev.number)\n        return\n\n    if num or dev.number < 8:\n        print(f\"  {int(num or dev.number)}: {dev.name}\")\n    else:\n        print(f\"{dev.name}\")\n    print(\"     Device path  :\", dev.path)\n    if dev.wpid:\n        print(f\"     WPID         : {dev.wpid}\")\n    if dev.product_id:\n        print(f\"     USB id       : {LOGITECH_VENDOR_ID:04x}:{dev.product_id}\")\n    print(\"     Codename     :\", dev.codename)\n    print(\"     Kind         :\", dev.kind)\n    if dev.protocol:\n        print(f\"     Protocol     : HID++ {dev.protocol:1.1f}\")\n    else:\n        print(\"     Protocol     : unknown (device is offline)\")\n    if dev.polling_rate:\n        print(\"     Report Rate :\", dev.polling_rate)\n    print(\"     Serial number:\", dev.serial)\n    if dev.modelId:\n        print(\"     Model ID:     \", dev.modelId)\n    if dev.unitId:\n        print(\"     Unit ID:      \", dev.unitId)\n    if dev.firmware:\n        for fw in dev.firmware:\n            print(f\"       {fw.kind:11}:\", (fw.name + \" \" + fw.version).strip())\n\n    if dev.power_switch_location:\n        print(f\"     The power switch is located on the {dev.power_switch_location}.\")\n\n    if dev.online:\n        notification_flags = _hidpp10.get_notification_flags(dev)\n        if notification_flags is not None:\n            if notification_flags:\n                notification_names = hidpp10_constants.NotificationFlag.flag_names(notification_flags)\n                print(f\"     Notifications: {', '.join(notification_names)} (0x{notification_flags:06X}).\")\n            else:\n                print(\"     Notifications: (none).\")\n        device_features = _hidpp10.get_device_features(dev)\n        if device_features is not None:\n            if device_features:\n                device_features_names = hidpp10_constants.DeviceFeature.flag_names(device_features)\n                print(f\"     Features: {', '.join(device_features_names)} (0x{device_features:06X})\")\n            else:\n                print(\"     Features: (none)\")\n\n    if dev.online and dev.features:\n        print(f\"     Supports {len(dev.features)} HID++ 2.0 features:\")\n        dev_settings = []\n        settings_templates.check_feature_settings(dev, dev_settings)\n        for feature, index in dev.features.enumerate():\n            if isinstance(feature, str):\n                feature_bytes = bytes.fromhex(feature[-4:])\n            else:\n                feature_bytes = feature.to_bytes(2, byteorder=\"little\")\n            feature_int = int.from_bytes(feature_bytes, byteorder=\"little\")\n            try:\n                flags = dev.request(0x0000, feature_bytes)\n            except Exception:\n                print(\"        %2d: %-22s {%04X} - can't retrieve\" % (index, feature, feature_int))\n                continue\n            flags = 0 if flags is None else ord(flags[1:2])\n            flags = common.flag_names(hidpp20_constants.FeatureFlag, flags)\n            version = dev.features.get_feature_version(feature_int)\n            version = version if version else 0\n            print(\"        %2d: %-22s {%04X} V%s    %s \" % (index, feature, feature_int, version, \", \".join(flags)))\n            if feature == SupportedFeature.HIRES_WHEEL:\n                wheel = _hidpp20.get_hires_wheel(dev)\n                if wheel:\n                    multi, has_invert, has_switch, inv, res, target, ratchet = wheel\n                    print(f\"            Multiplier: {multi}\")\n                    if has_invert:\n                        print(\"            Has invert:\", \"Inverse wheel motion\" if inv else \"Normal wheel motion\")\n                    if has_switch:\n                        print(\"            Has ratchet switch:\", \"Normal wheel mode\" if ratchet else \"Free wheel mode\")\n                    if res:\n                        print(\"            High resolution mode\")\n                    else:\n                        print(\"            Low resolution mode\")\n                    if target:\n                        print(\"            HID++ notification\")\n                    else:\n                        print(\"            HID notification\")\n            elif feature == SupportedFeature.MOUSE_POINTER:\n                mouse_pointer = _hidpp20.get_mouse_pointer_info(dev)\n                if mouse_pointer:\n                    print(f\"            DPI: {mouse_pointer['dpi']}\")\n                    print(f\"            Acceleration: {mouse_pointer['acceleration']}\")\n                    if mouse_pointer[\"suggest_os_ballistics\"]:\n                        print(\"            Use OS ballistics\")\n                    else:\n                        print(\"            Override OS ballistics\")\n                    if mouse_pointer[\"suggest_vertical_orientation\"]:\n                        print(\"            Provide vertical tuning, trackball\")\n                    else:\n                        print(\"            No vertical tuning, standard mice\")\n            elif feature == SupportedFeature.VERTICAL_SCROLLING:\n                vertical_scrolling_info = _hidpp20.get_vertical_scrolling_info(dev)\n                if vertical_scrolling_info:\n                    print(f\"            Roller type: {vertical_scrolling_info['roller']}\")\n                    print(f\"            Ratchet per turn: {vertical_scrolling_info['ratchet']}\")\n                    print(f\"            Scroll lines: {vertical_scrolling_info['lines']}\")\n            elif feature == SupportedFeature.HI_RES_SCROLLING:\n                scrolling_mode, scrolling_resolution = _hidpp20.get_hi_res_scrolling_info(dev)\n                if scrolling_mode:\n                    print(\"            Hi-res scrolling enabled\")\n                else:\n                    print(\"            Hi-res scrolling disabled\")\n                if scrolling_resolution:\n                    print(f\"            Hi-res scrolling multiplier: {scrolling_resolution}\")\n            elif feature == SupportedFeature.POINTER_SPEED:\n                pointer_speed = _hidpp20.get_pointer_speed_info(dev)\n                if pointer_speed:\n                    print(f\"            Pointer Speed: {pointer_speed}\")\n            elif feature == SupportedFeature.LOWRES_WHEEL:\n                wheel_status = _hidpp20.get_lowres_wheel_status(dev)\n                if wheel_status:\n                    print(f\"            Wheel Reports: {wheel_status}\")\n            elif feature == SupportedFeature.NEW_FN_INVERSION:\n                inversion = _hidpp20.get_new_fn_inversion(dev)\n                if inversion:\n                    inverted, default_inverted = inversion\n                    print(\"            Fn-swap:\", \"enabled\" if inverted else \"disabled\")\n                    print(\"            Fn-swap default:\", \"enabled\" if default_inverted else \"disabled\")\n            elif feature == SupportedFeature.HOSTS_INFO:\n                host_names = _hidpp20.get_host_names(dev)\n                for host, (paired, name) in host_names.items():\n                    print(f\"            Host {host} ({'paired' if paired else 'unpaired'}): {name}\")\n            elif feature == SupportedFeature.DEVICE_NAME:\n                print(f\"            Name: {_hidpp20.get_name(dev)}\")\n                print(f\"            Kind: {_hidpp20.get_kind(dev)}\")\n            elif feature == SupportedFeature.DEVICE_FRIENDLY_NAME:\n                print(f\"            Friendly Name: {_hidpp20.get_friendly_name(dev)}\")\n            elif feature == SupportedFeature.DEVICE_FW_VERSION:\n                for fw in _hidpp20.get_firmware(dev):\n                    extras = strhex(fw.extras) if fw.extras else \"\"\n                    print(f\"            Firmware: {fw.kind} {fw.name} {fw.version} {extras}\")\n                ids = _hidpp20.get_ids(dev)\n                if ids:\n                    unitId, modelId, tid_map = ids\n                    print(f\"            Unit ID: {unitId}  Model ID: {modelId}  Transport IDs: {tid_map}\")\n            elif feature == SupportedFeature.REPORT_RATE or feature == SupportedFeature.EXTENDED_ADJUSTABLE_REPORT_RATE:\n                print(f\"            Report Rate: {_hidpp20.get_polling_rate(dev)}\")\n            elif feature == SupportedFeature.CONFIG_CHANGE:\n                response = dev.feature_request(SupportedFeature.CONFIG_CHANGE, 0x00)\n                print(f\"            Configuration: {response.hex()}\")\n            elif feature == SupportedFeature.REMAINING_PAIRING:\n                print(f\"            Remaining Pairings: {int(_hidpp20.get_remaining_pairing(dev))}\")\n            elif feature == SupportedFeature.ONBOARD_PROFILES:\n                if _hidpp20.get_onboard_mode(dev) == hidpp20_constants.OnboardMode.MODE_HOST:\n                    mode = \"Host\"\n                else:\n                    mode = \"On-Board\"\n                print(f\"            Device Mode: {mode}\")\n            elif hidpp20.battery_functions.get(feature, None):\n                print(\"\", end=\"       \")\n                _battery_line(dev)\n            for setting in dev_settings:\n                if setting.feature == feature:\n                    if (\n                        setting._device\n                        and getattr(setting._device, \"persister\", None)\n                        and setting._device.persister.get(setting.name) is not None\n                    ):\n                        v = setting.val_to_string(setting._device.persister.get(setting.name))\n                        print(f\"            {setting.label} (saved): {v}\")\n                    try:\n                        v = setting.read(False)\n                        v = setting.val_to_string(v)\n                    except exceptions.FeatureCallError as e:\n                        v = \"HID++ error \" + str(e)\n                    except AssertionError as e:\n                        v = \"AssertionError \" + str(e)\n                    print(f\"            {setting.label}        : {v}\")\n\n    if dev.online and dev.keys:\n        print(f\"     Has {len(dev.keys)} reprogrammable keys:\")\n        for k in dev.keys:\n            # TODO: add here additional variants for other REPROG_CONTROLS\n            if dev.keys.keyversion == SupportedFeature.REPROG_CONTROLS_V2:\n                print(\"        %2d: %-26s => %-27s   %s\" % (k.index, k.key, k.default_task, \", \".join(k.flags)))\n            if dev.keys.keyversion == SupportedFeature.REPROG_CONTROLS_V4:\n                print(\"        %2d: %-26s, default: %-27s => %-26s\" % (k.index, k.key, k.default_task, k.mapped_to))\n                gmask_fmt = \",\".join(k.group_mask)\n                gmask_fmt = gmask_fmt if gmask_fmt else \"empty\"\n                flag_names = list(common.flag_names(hidpp20.KeyFlag, k.flags.value))\n                print(\n                    f\"             {', '.join(flag_names)}, pos:{int(k.pos)}, group:{int(k.group):1}, group mask:{gmask_fmt}\"\n                )\n                report_fmt = list(common.flag_names(hidpp20.MappingFlag, k.mapping_flags.value))\n                report_fmt = report_fmt if report_fmt else \"default\"\n                print(f\"             reporting: {report_fmt}\")\n    if dev.online and dev.remap_keys:\n        print(f\"     Has {len(dev.remap_keys)} persistent remappable keys:\")\n        for k in dev.remap_keys:\n            print(\"        %2d: %-26s => %s%s\" % (k.index, k.key, k.action, \" (remapped)\" if k.cidStatus else \"\"))\n    if dev.online and dev.gestures:\n        print(\n            \"     Has %d gesture(s), %d param(s) and %d spec(s):\"\n            % (len(dev.gestures.gestures), len(dev.gestures.params), len(dev.gestures.specs))\n        )\n        for k in dev.gestures.gestures.values():\n            print(\n                \"        %-26s Enabled(%4s): %-5s  Diverted:(%4s) %s\"\n                % (k.gesture, k.index, k.enabled(), k.diversion_index, k.diverted())\n            )\n        for k in dev.gestures.params.values():\n            print(\"        %-26s Value  (%4s): %s [Default: %s]\" % (k.param, k.index, k.value, k.default_value))\n        for k in dev.gestures.specs.values():\n            print(\"        %-26s Spec   (%4s): %s\" % (k.spec, k.id, k.value))\n    if dev.online:\n        _battery_line(dev)\n    else:\n        print(\"     Battery: unknown (device is offline).\")\n\n\ndef run(devices, args, find_receiver, find_device):\n    assert devices\n    assert args.device\n\n    print(f\"{NAME.lower()} version {__version__}\")\n    print(\"\")\n\n    device_name = args.device.lower()\n\n    if device_name == \"all\":\n        for d in devices:\n            if isinstance(d, receiver.Receiver):\n                _print_receiver(d)\n                count = d.count()\n                if count:\n                    for dev in d:\n                        print(\"\")\n                        _print_device(dev, dev.number)\n                        count -= 1\n                        if not count:\n                            break\n                print(\"\")\n            else:\n                print(\"\")\n                _print_device(d)\n        return\n\n    dev = find_receiver(devices, device_name)\n    if dev and not dev.isDevice:\n        _print_receiver(dev)\n        return\n\n    dev = next(find_device(devices, device_name), None)\n    if not dev:\n        raise Exception(f\"no device found matching '{device_name}'\")\n\n    _print_device(dev)\n"
  },
  {
    "path": "lib/solaar/cli/unpair.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n\ndef run(receivers, args, find_receiver, find_device):\n    assert receivers\n    assert args.device\n\n    device_name = args.device.lower()\n    dev = next(find_device(receivers, device_name), None)\n    if not dev:\n        raise Exception(f\"no device found matching '{device_name}'\")\n\n    if not dev.receiver.may_unpair:\n        print(\n            f\"Receiver with USB id {dev.receiver.product_id} for {dev.name} [{dev.wpid}:{dev.serial}] does not unpair,\",\n            \"but attempting anyway.\",\n        )\n    try:\n        # query these now, it's last chance to get them\n        number, codename, wpid, serial = dev.number, dev.codename, dev.wpid, dev.serial\n        dev.receiver._unpair_device(number, True)  # force an unpair\n        print(f\"Unpaired {int(number)}: {dev.name} ({codename}) [{wpid}:{serial}]\")\n    except Exception as e:\n        raise e\n"
  },
  {
    "path": "lib/solaar/configuration.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport json\nimport logging\nimport os\nimport threading\n\nimport yaml\n\nfrom logitech_receiver.common import NamedInt\n\nfrom solaar import __version__\n\nlogger = logging.getLogger(__name__)\n\n_XDG_CONFIG_HOME = os.environ.get(\"XDG_CONFIG_HOME\") or os.path.expanduser(os.path.join(\"~\", \".config\"))\n_yaml_file_path = os.path.join(_XDG_CONFIG_HOME, \"solaar\", \"config.yaml\")\n_json_file_path = os.path.join(_XDG_CONFIG_HOME, \"solaar\", \"config.json\")\n\n_KEY_VERSION = \"_version\"\n_KEY_NAME = \"_NAME\"\n_KEY_WPID = \"_wpid\"\n_KEY_SERIAL = \"_serial\"\n_KEY_MODEL_ID = \"_modelId\"\n_KEY_UNIT_ID = \"_unitId\"\n_KEY_ABSENT = \"_absent\"\n_KEY_SENSITIVE = \"_sensitive\"\n_config = []\n\n\ndef _load():\n    loaded_config = []\n    if os.path.isfile(_yaml_file_path):\n        path = _yaml_file_path\n        try:\n            with open(_yaml_file_path) as config_file:\n                loaded_config = yaml.safe_load(config_file)\n        except Exception as e:\n            logger.error(\"failed to load from %s: %s\", _yaml_file_path, e)\n    elif os.path.isfile(_json_file_path):\n        path = _json_file_path\n        try:\n            with open(_json_file_path) as config_file:\n                loaded_config = json.load(config_file)\n        except Exception as e:\n            logger.error(\"failed to load from %s: %s\", _json_file_path, e)\n        loaded_config = _convert_json(loaded_config)\n    else:\n        path = None\n    logger.debug(\"load => %s\", loaded_config)\n    global _config\n    _config = _parse_config(loaded_config, path)\n\n\ndef _parse_config(loaded_config, config_path):\n    current_version = __version__\n    parsed_config = [current_version]\n    try:\n        if not loaded_config:\n            return parsed_config\n\n        loaded_version = loaded_config[0]\n        discard_derived_properties = loaded_version != current_version\n        if discard_derived_properties:\n            logger.info(\n                \"config file '%s' was generated by another version of solaar \"\n                \"(config: %s, current: %s). refreshing detected device capabilities\",\n                config_path,\n                loaded_version,\n                current_version,\n            )\n\n        for device in loaded_config[1:]:\n            assert isinstance(device, dict)\n            parsed_config.append(_device_entry_from_config_dict(device, discard_derived_properties))\n    except Exception as e:\n        logger.warning(\"Exception processing config file '%s', ignoring contents: %s\", config_path, e)\n    return parsed_config\n\n\ndef _device_entry_from_config_dict(data, discard_derived_properties):\n    divert = data.get(\"divert-keys\")\n    if divert:\n        sliding = data.get(\"dpi-sliding\")\n        if sliding:  # convert old-style dpi-sliding setting to divert-keys entry\n            divert[int(sliding)] = 3\n        data.pop(\"dpi-sliding\", None)\n        gestures = data.get(\"mouse-gestures\")\n        if gestures:  # convert old-style mouse-gestures setting to divert-keys entry\n            divert[int(gestures)] = 2\n        data.pop(\"mouse-gestures\", None)\n        # remove any string entries (from bad conversions)\n        data[\"divert-keys\"] = {k: v for k, v in divert.items() if isinstance(k, int)}\n    if data.get(\"_sensitive\", None) is None:  # make scroll wheel settings default to ignore\n        data[\"_sensitive\"] = {\n            \"hires-smooth-resolution\": \"ignore\",\n            \"hires-smooth-invert\": \"ignore\",\n            \"hires-scroll-mode\": \"ignore\",\n        }\n    if discard_derived_properties:\n        data.pop(\"_absent\", None)\n        data.pop(\"_battery\", None)\n    return _DeviceEntry(**data)\n\n\nsave_timer = None\nconfiguration_lock = threading.Lock()\ndefer_saves = False  # don't allow configuration saves to be deferred\n\n\ndef save(defer=False):\n    global save_timer\n    if not _config:\n        return\n    dirname = os.path.dirname(_yaml_file_path)\n    if not os.path.isdir(dirname):\n        try:\n            os.makedirs(dirname)\n        except Exception:\n            logger.error(\"failed to create %s\", dirname)\n            return\n    if not defer or not defer_saves:\n        do_save()\n    else:\n        with configuration_lock:\n            if not save_timer:\n                save_timer = threading.Timer(5.0, do_save)\n                save_timer.start()\n\n\ndef do_save():\n    global save_timer\n    with configuration_lock:\n        if save_timer:\n            save_timer.cancel()\n            save_timer = None\n        try:\n            with open(_yaml_file_path, \"w\") as config_file:\n                yaml.dump(_config, config_file, default_flow_style=None, width=150)\n            logger.info(\"saved %s to %s\", _config, _yaml_file_path)\n        except Exception as e:\n            logger.error(\"failed to save to %s: %s\", _yaml_file_path, e)\n\n\ndef _convert_json(json_dict):\n    config = [json_dict.get(_KEY_VERSION)]\n    for key, dev in json_dict.items():\n        key = key.split(\":\")\n        if len(key) == 2:\n            dev[_KEY_WPID] = dev.get(_KEY_WPID) if dev.get(_KEY_WPID) else key[0]\n            dev[_KEY_SERIAL] = dev.get(_KEY_SERIAL) if dev.get(_KEY_SERIAL) else key[1]\n            for k, v in dev.items():\n                if isinstance(k, str) and not k.startswith(\"_\") and isinstance(v, dict):  # convert string keys to ints\n                    v = {int(dk) if isinstance(dk, str) else dk: dv for dk, dv in v.items()}\n                dev[k] = v\n            for k in [\"mouse-gestures\", \"dpi-sliding\"]:\n                v = dev.get(k, None)\n                if v is True or v is False:\n                    dev.pop(k)\n            if \"_name\" in dev:\n                dev[_KEY_NAME] = dev[\"_name\"]\n                dev.pop(\"_name\")\n            config.append(dev)\n    return config\n\n\nclass _DeviceEntry(dict):\n    def __init__(self, **kwargs):\n        super().__init__(**kwargs)\n\n    def __setitem__(self, key, value):\n        super().__setitem__(key, value)\n        save(defer=True)\n\n    def update(self, name, wpid, serial, modelId, unitId):\n        if name and name != self.get(_KEY_NAME):\n            super().__setitem__(_KEY_NAME, name)\n        if wpid and wpid != self.get(_KEY_WPID):\n            super().__setitem__(_KEY_WPID, wpid)\n        if serial and serial != self.get(_KEY_SERIAL):\n            super().__setitem__(_KEY_SERIAL, serial)\n        if modelId and modelId != self.get(_KEY_MODEL_ID):\n            super().__setitem__(_KEY_MODEL_ID, modelId)\n        if unitId and unitId != self.get(_KEY_UNIT_ID):\n            super().__setitem__(_KEY_UNIT_ID, unitId)\n\n    def get_sensitivity(self, name):\n        return self.get(_KEY_SENSITIVE, {}).get(name, False)\n\n    def set_sensitivity(self, name, value):\n        sensitives = self.get(_KEY_SENSITIVE, {})\n        if sensitives.get(name) != value:\n            sensitives[name] = value\n            self.__setitem__(_KEY_SENSITIVE, sensitives)\n\n\ndef device_representer(dumper, data):\n    return dumper.represent_mapping(\"tag:yaml.org,2002:map\", data)\n\n\nyaml.add_representer(_DeviceEntry, device_representer)\n\n\ndef named_int_representer(dumper, data):\n    return dumper.represent_scalar(\"tag:yaml.org,2002:int\", str(int(data)))\n\n\nyaml.add_representer(NamedInt, named_int_representer)\n\n\n# A device can be identified by a combination of WPID and serial number (for receiver-connected devices)\n# or a combination of modelId and unitId (for direct-connected devices).\n# But some devices have empty (all zero) modelIds and unitIds.  Use the device name as a backup for the modelId.\n# The worst situation is a receiver-connected device that Solaar has never seen on-line\n# that is directly connected.  Here there is no way to realize that the two devices are the same.\n# So new entries are not created for unseen off-line receiver-connected devices\ndef persister(device):\n    def match(wpid, serial, modelId, unitId, c):\n        return (\n            (wpid and wpid == c.get(_KEY_WPID) and serial and serial == c.get(_KEY_SERIAL))\n            or (modelId and modelId == c.get(_KEY_MODEL_ID) and unitId and unitId == c.get(_KEY_UNIT_ID))\n            or (\n                c.get(_KEY_WPID) is None\n                and c.get(_KEY_SERIAL) is None\n                and c.get(_KEY_UNIT_ID) is None\n                and modelId\n                and modelId == c.get(_KEY_MODEL_ID)\n            )\n        )\n\n    with configuration_lock:\n        if not _config:\n            _load()\n        entry = None\n        # some devices report modelId and unitId as zero so use name and serial for them\n        modelId = device.modelId if device.modelId != \"000000000000\" else device._name if device._name else None\n        unitId = device.unitId if device.unitId != \"00000000\" else device._serial if device._serial else None\n        for c in _config:\n            if isinstance(c, _DeviceEntry) and match(device.wpid, device._serial, modelId, unitId, c):\n                entry = c\n                break\n        if not entry:\n            if not device.online:  # don't create entry for offline devices\n                logger.info(\"not setting up persister for offline device %s\", device._name)\n                return\n            logger.info(\"setting up persister for device %s\", device.name)\n            entry = _DeviceEntry()\n            _config.append(entry)\n        entry.update(device.name, device.wpid, device.serial, modelId, unitId)\n        return entry\n\n\ndef attach_to(device):\n    pass\n"
  },
  {
    "path": "lib/solaar/custom_logger.py",
    "content": "import logging\n\n\nclass CustomLogger(logging.Logger):\n    \"\"\"Logger, that avoids unnecessary string computations.\n\n    Does not compute messages for disabled log levels.\n    \"\"\"\n\n    def debug(self, msg, *args, **kwargs):\n        if self.isEnabledFor(logging.DEBUG):\n            super().debug(msg, *args, **kwargs)\n\n    def info(self, msg, *args, **kwargs):\n        if self.isEnabledFor(logging.INFO):\n            super().info(msg, *args, **kwargs)\n\n    def warning(self, msg, *args, **kwargs):\n        if self.isEnabledFor(logging.WARNING):\n            super().warning(msg, *args, **kwargs)\n\n    def error(self, msg, *args, **kwargs):\n        if self.isEnabledFor(logging.ERROR):\n            super().error(msg, *args, **kwargs)\n\n    def critical(self, msg, *args, **kwargs):\n        if self.isEnabledFor(logging.CRITICAL):\n            super().critical(msg, *args, **kwargs)\n"
  },
  {
    "path": "lib/solaar/dbus.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nfrom __future__ import annotations\n\nimport logging\n\nfrom typing import Callable\n\nlogger = logging.getLogger(__name__)\n\ntry:\n    import dbus\n\n    from dbus.mainloop.glib import DBusGMainLoop  # integration into the main GLib loop\n\n    DBusGMainLoop(set_as_default=True)\n    bus = dbus.SystemBus()\n    assert bus\n\nexcept Exception:\n    # Either the dbus library is not available or the system dbus is not running\n    logger.warning(\"failed to set up dbus\")\n    bus = None\n\n\n_suspend_callback = None\n_resume_callback = None\n\n\ndef _suspend_or_resume(suspend):\n    if suspend and _suspend_callback:\n        _suspend_callback()\n    if not suspend and _resume_callback:\n        _resume_callback()\n\n\n_LOGIND_PATH = \"/org/freedesktop/login1\"\n_LOGIND_INTERFACE = \"org.freedesktop.login1.Manager\"\n\n\ndef watch_suspend_resume(\n    on_resume_callback: Callable[[], None] | None = None,\n    on_suspend_callback: Callable[[], None] | None = None,\n):\n    \"\"\"Register callback for suspend/resume events.\n    They are called only if the system DBus is running, and the Login daemon is available.\"\"\"\n    global _resume_callback, _suspend_callback\n    _suspend_callback = on_suspend_callback\n    _resume_callback = on_resume_callback\n    if bus is not None and on_resume_callback is not None or on_suspend_callback is not None:\n        bus.add_signal_receiver(\n            _suspend_or_resume,\n            \"PrepareForSleep\",\n            dbus_interface=_LOGIND_INTERFACE,\n            path=_LOGIND_PATH,\n        )\n    logger.info(\"connected to system dbus, watching for suspend/resume events\")\n\n\n_BLUETOOTH_PATH_PREFIX = \"/org/bluez/hci0/dev_\"\n_BLUETOOTH_INTERFACE = \"org.freedesktop.DBus.Properties\"\n\n_bluetooth_callbacks = {}\n\n\ndef watch_bluez_connect(serial, callback=None):\n    if _bluetooth_callbacks.get(serial):\n        _bluetooth_callbacks.get(serial).remove()\n    path = _BLUETOOTH_PATH_PREFIX + serial.replace(\":\", \"_\").upper()\n    if bus is not None and callback is not None:\n        _bluetooth_callbacks[serial] = bus.add_signal_receiver(\n            callback, \"PropertiesChanged\", path=path, dbus_interface=_BLUETOOTH_INTERFACE\n        )\n"
  },
  {
    "path": "lib/solaar/gtk.py",
    "content": "#!/usr/bin/env python3\n\n## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport argparse\nimport faulthandler\nimport importlib\nimport locale\nimport logging\nimport os.path\nimport platform\nimport signal\nimport sys\nimport tempfile\n\nfrom traceback import format_exc\n\nfrom solaar import NAME\nfrom solaar import __version__\nfrom solaar import cli\nfrom solaar import configuration\nfrom solaar import dbus\nfrom solaar import listener\nfrom solaar import ui\nfrom solaar.custom_logger import CustomLogger\n\nlogging.setLoggerClass(CustomLogger)\nlogger = logging.getLogger(__name__)\n\n\ndef _require(module, os_package, gi=None, gi_package=None, gi_version=None):\n    try:\n        if gi is not None:\n            gi.require_version(gi_package, gi_version)\n        return importlib.import_module(module)\n    except (ImportError, ValueError):\n        sys.exit(f\"{NAME.lower()}: missing required system package {os_package}\")\n\n\nbattery_icons_style = \"regular\"\ntray_icon_size = None\ntemp = tempfile.NamedTemporaryFile(prefix=\"Solaar_\", mode=\"w\", delete=True)\n\n\ndef create_parser():\n    arg_parser = argparse.ArgumentParser(\n        prog=NAME.lower(),\n        description=\"Solaar is a program to manage many Logitech devices, \"\n        \"changing how they operate and maintaining the changes whenever the device connects.\",\n        epilog=\"For more information see https://pwr-solaar.github.io/Solaar\",\n    )\n    arg_parser.add_argument(\n        \"-d\",\n        \"--debug\",\n        action=\"count\",\n        default=0,\n        help=\"print logging messages, for debugging purposes (may be repeated for extra verbosity)\",\n    )\n    arg_parser.add_argument(\n        \"-D\",\n        \"--hidraw\",\n        action=\"store\",\n        dest=\"hidraw_path\",\n        metavar=\"PATH\",\n        help=\"device or receiver path to use if needed. Example: /dev/hidraw2\",\n    )\n    arg_parser.add_argument(\n        \"--restart-on-wake-up\",\n        action=\"store_true\",\n        help=\"restart Solaar on sleep wake-up (experimental)\",\n    )\n    arg_parser.add_argument(\n        \"-w\",\n        \"--window\",\n        choices=(\"show\", \"hide\", \"only\"),\n        help=\"start with window showing / hidden / only (no tray icon)\",\n    )\n    arg_parser.add_argument(\n        \"-b\",\n        \"--battery-icons\",\n        choices=(\"regular\", \"symbolic\", \"solaar\"),\n        help=\"prefer regular battery / symbolic battery / solaar icons\",\n    )\n    arg_parser.add_argument(\"--tray-icon-size\", type=int, help=\"explicit size for tray icons\")\n    arg_parser.add_argument(\"-V\", \"--version\", action=\"version\", version=\"%(prog)s \" + __version__)\n    arg_parser.add_argument(\"--help-actions\", action=\"store_true\", help=\"describe the command-line actions\")\n    arg_parser.add_argument(\n        \"action\",\n        nargs=argparse.REMAINDER,\n        choices=cli.actions,\n        help=\"command-line action to perform (optional); append ' --help' to show args\",\n    )\n    return arg_parser\n\n\ndef _parse_arguments():\n    arg_parser = create_parser()\n    args = arg_parser.parse_args()\n\n    if args.help_actions:\n        cli.print_help()\n        return\n\n    if args.window is None:\n        args.window = \"show\"  # default behaviour is to show main window\n\n    global battery_icons_style\n    battery_icons_style = args.battery_icons if args.battery_icons is not None else \"regular\"\n    global tray_icon_size\n    tray_icon_size = args.tray_icon_size\n\n    log_format = \"%(asctime)s,%(msecs)03d %(levelname)8s [%(threadName)s] %(name)s: %(message)s\"\n    log_level = logging.ERROR - 10 * args.debug\n    logging.getLogger(\"\").setLevel(min(log_level, logging.WARNING))\n    file_handler = logging.StreamHandler(temp)\n    file_handler.setLevel(max(min(log_level, logging.WARNING), logging.INFO))\n    file_handler.setFormatter(logging.Formatter(log_format))\n    logging.getLogger(\"\").addHandler(file_handler)\n    if args.debug > 0:\n        stream_handler = logging.StreamHandler()\n        stream_handler.setFormatter(logging.Formatter(log_format))\n        stream_handler.setLevel(log_level)\n        logging.getLogger(\"\").addHandler(stream_handler)\n\n    if not args.action:\n        language, encoding = locale.getlocale()\n        logger.info(\"version %s, language %s (%s)\", __version__, language, encoding)\n\n    return args\n\n\n# On first SIGINT, dump threads to stderr; on second, exit\ndef _handlesig(signl, stack):\n    signal.signal(signal.SIGINT, signal.SIG_DFL)\n    signal.signal(signal.SIGTERM, signal.SIG_DFL)\n\n    if signl == int(signal.SIGINT):\n        if logger.isEnabledFor(logging.INFO):\n            faulthandler.dump_traceback()\n        sys.exit(f\"{NAME.lower()}: exit due to keyboard interrupt\")\n    else:\n        sys.exit(0)\n\n\ndef main():\n    if platform.system() not in (\"Darwin\", \"Windows\"):\n        _require(\"pyudev\", \"python3-pyudev\")\n\n    args = _parse_arguments()\n    if not args:\n        # explicit close before return\n        temp.close()\n        return\n    if args.action:\n        # if any argument, run comandline and exit\n        result = cli.run(args.action, args.hidraw_path)\n        # explicit close before return\n        temp.close()\n        return result\n\n    gi = _require(\"gi\", \"python3-gi (in Ubuntu) or python3-gobject (in Fedora)\")\n    _require(\"gi.repository.Gtk\", \"gir1.2-gtk-3.0\", gi, \"Gtk\", \"3.0\")\n\n    # handle ^C in console\n    signal.signal(signal.SIGINT, signal.SIG_DFL)\n    signal.signal(signal.SIGINT, _handlesig)\n    signal.signal(signal.SIGTERM, _handlesig)\n\n    udev_file = \"42-logitech-unify-permissions.rules\"\n    if (\n        platform.system() == \"Linux\"\n        and logger.isEnabledFor(logging.WARNING)\n        and not os.path.isfile(\"/etc/udev/rules.d/\" + udev_file)\n        and not os.path.isfile(\"/usr/lib/udev/rules.d/\" + udev_file)\n        and not os.path.isfile(\"/usr/local/lib/udev/rules.d/\" + udev_file)\n    ):\n        logger.warning(\"Solaar udev file not found in expected location\")\n        logger.warning(\"See https://pwr-solaar.github.io/Solaar/installation for more information\")\n    try:\n        listener.setup_scanner(ui.status_changed, ui.setting_changed, ui.common.error_dialog)\n\n        if args.restart_on_wake_up:\n            dbus.watch_suspend_resume(listener.start_all, listener.stop_all)\n        else:\n            dbus.watch_suspend_resume(lambda: listener.ping_all(True))\n\n        configuration.defer_saves = True  # allow configuration saves to be deferred\n\n        # main UI event loop\n        ui.run_loop(listener.start_all, listener.stop_all, args.window != \"only\", args.window != \"hide\")\n    except Exception:\n        sys.exit(f\"{NAME.lower()}: error: {format_exc()}\")\n\n    temp.close()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "lib/solaar/i18n.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport gettext\nimport locale\nimport logging\nimport os\nimport sys\n\nfrom glob import glob\n\nfrom solaar import NAME\n\n_LOCALE_DOMAIN = NAME.lower()\n\nlogger = logging.getLogger(__name__)\n\n\ndef _find_locale_path(locale_domain: str) -> str:\n    prefix_share = os.path.normpath(os.path.join(os.path.realpath(sys.path[0]), \"..\"))\n    src_share = os.path.normpath(os.path.join(os.path.realpath(sys.path[0]), \"..\", \"share\"))\n\n    for location in prefix_share, src_share:\n        mo_files = glob(os.path.join(location, \"locale\", \"*\", \"LC_MESSAGES\", f\"{locale_domain}.mo\"))\n        if mo_files:\n            return os.path.join(location, \"locale\")\n    raise FileNotFoundError(f\"Could not find locale path for {locale_domain}\")\n\n\ndef set_locale_to_system_default() -> None:\n    \"\"\"Sets locale for translations to the system default.\n\n    If locale is unsupported, fallback to standard English without\n    translation 'C'.\n\n    Set LC_ALL environment variable to enforce a locale setting e.g.\n    'de_DE.UTF-8'. Run Solaar with your desired localization, for German\n    use:\n    'LC_ALL=de_DE.UTF-8 solaar'\n    \"\"\"\n    try:\n        locale.setlocale(locale.LC_ALL, \"\")  # system default\n    except locale.Error:\n        logger.error(\"User locale not supported by system, using no translation.\")\n        locale.setlocale(locale.LC_ALL, \"C\")  # untranslated (English)\n        return\n\n    try:\n        path = _find_locale_path(_LOCALE_DOMAIN)\n    except FileNotFoundError:\n        path = None\n    gettext.bindtextdomain(_LOCALE_DOMAIN, path)\n    gettext.textdomain(_LOCALE_DOMAIN)\n    gettext.install(_LOCALE_DOMAIN)\n\n\nset_locale_to_system_default()\n\n_ = gettext.gettext\nngettext = gettext.ngettext\n"
  },
  {
    "path": "lib/solaar/listener.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom __future__ import annotations\n\nimport errno\nimport logging\nimport subprocess\nimport time\nimport typing\n\nfrom collections import namedtuple\nfrom functools import partial\nfrom typing import Callable\n\nimport gi\nimport logitech_receiver\n\nfrom logitech_receiver import base\nfrom logitech_receiver import exceptions\nfrom logitech_receiver import hidpp10_constants\nfrom logitech_receiver import listener\nfrom logitech_receiver import notifications\n\nfrom . import configuration\nfrom . import dbus\nfrom . import i18n\nfrom .ui import common\n\nif typing.TYPE_CHECKING:\n    from hidapi.common import DeviceInfo\n\ngi.require_version(\"Gtk\", \"3.0\")  # NOQA: E402\nfrom gi.repository import GLib  # NOQA: E402 # isort:skip\n\nif typing.TYPE_CHECKING:\n    from logitech_receiver.device import Device\n\nlogger = logging.getLogger(__name__)\n\nACTION_ADD = \"add\"\n\n_GHOST_DEVICE = namedtuple(\"_GHOST_DEVICE\", (\"receiver\", \"number\", \"name\", \"kind\", \"online\", \"path\"))\n_GHOST_DEVICE.__bool__ = lambda self: False\n_GHOST_DEVICE.__nonzero__ = _GHOST_DEVICE.__bool__\n\n\ndef _ghost(device):\n    return _GHOST_DEVICE(\n        receiver=device.receiver, number=device.number, name=device.name, kind=device.kind, online=False, path=None\n    )\n\n\nclass SolaarListener(listener.EventsListener):\n    \"\"\"Keeps the status of a Receiver or Device (member name is receiver but it can also be a device).\"\"\"\n\n    def __init__(self, receiver, status_changed_callback):\n        assert status_changed_callback\n        super().__init__(receiver, self._notifications_handler)\n        self.status_changed_callback = status_changed_callback\n        receiver.status_callback = self._status_changed\n\n    def has_started(self):\n        logger.info(\"%s: notifications listener has started (%s)\", self.receiver, self.receiver.handle)\n        nfs = self.receiver.enable_connection_notifications()\n        if not self.receiver.isDevice and (not nfs or not (nfs & hidpp10_constants.NotificationFlag.WIRELESS)):\n            logger.warning(\n                \"Receiver on %s might not support connection notifications, GUI might not show its devices\",\n                self.receiver.path,\n            )\n        self.receiver.notification_flags = nfs\n        self.receiver.notify_devices()\n        self._status_changed(self.receiver)\n\n    def has_stopped(self):\n        r, self.receiver = self.receiver, None\n        assert r is not None\n        logger.info(\"%s: notifications listener has stopped\", r)\n\n        # because udev is not notifying us about device removal, make sure to clean up in _all_listeners\n        _all_listeners.pop(r.path, None)\n\n        # this causes problems but what is it doing (pfps) - r.status = _('The receiver was unplugged.')\n        if r:\n            try:\n                r.close()\n            except Exception:\n                logger.exception(f\"closing receiver {r.path}\")\n        self.status_changed_callback(r)\n\n    def _status_changed(self, device, alert=None, reason=None):\n        assert device is not None\n        if logger.isEnabledFor(logging.INFO):\n            try:\n                if device.kind is None:\n                    logger.info(\n                        \"status_changed %r: %s (%X) %s\",\n                        device,\n                        \"present\" if bool(device) else \"removed\",\n                        alert if alert is not None else 0,\n                        reason or \"\",\n                    )\n                else:\n                    device.ping()\n                    logger.info(\n                        \"status_changed %r: %s %s (%X) %s\",\n                        device,\n                        \"paired\" if bool(device) else \"unpaired\",\n                        \"online\" if device.online else \"offline\",\n                        alert if alert is not None else 0,\n                        reason or \"\",\n                    )\n            except Exception as e:\n                logger.info(\"status_changed for unknown device: %s\", e)\n\n        if device.kind is None:\n            assert device == self.receiver\n            # the status of the receiver changed\n            self.status_changed_callback(device, alert, reason)\n            return\n\n        # not true for wired devices - assert device.receiver == self.receiver\n        if not device:\n            # Device was unpaired, and isn't valid anymore.\n            # We replace it with a ghost so that the UI has something to work with while cleaning up.\n            logger.info(\"device %s was unpaired, ghosting\", device)\n            device = _ghost(device)\n\n        self.status_changed_callback(device, alert, reason)\n\n        if not device:\n            # the device was just unpaired, need to update the status of the receiver as well\n            self.status_changed_callback(self.receiver)\n\n    def _notifications_handler(self, n):\n        assert self.receiver\n        if n.devnumber == 0xFF:\n            # a receiver notification\n            notifications.process(self.receiver, n)\n            return\n\n        # a notification that came in to the device listener - strange, but nothing needs to be done here\n        if self.receiver.isDevice:\n            logger.debug(\"Notification %s via device %s being ignored.\", n, self.receiver)\n            return\n\n        # DJ pairing notification - ignore - hid++ 1.0 pairing notification is all that is needed\n        if n.sub_id == 0x41 and n.report_id == base.DJ_MESSAGE_ID:\n            logger.info(\"ignoring DJ pairing notification %s\", n)\n            return\n\n        # a device notification\n        if not (0 < n.devnumber <= 16):  # some receivers have devices past their max # devices\n            logger.warning(\"Unexpected device number (%s) in notification %s.\", n.devnumber, n)\n            return\n        already_known = n.devnumber in self.receiver\n\n        # FIXME: hacky fix for kernel/hardware race condition\n        # If the device was just turned on or woken up from sleep, it may not be ready to receive commands.\n        # The \"payload\" bit of the wireless status notification seems to tell us this. If this is the case, we\n        # must wait a short amount of time to avoid causing a broken pipe error.\n        device_ready = not bool(ord(n.data[0:1]) & 0x80) or n.sub_id != 0x41\n        if not device_ready:\n            time.sleep(0.01)\n\n        if n.sub_id == 0x40 and not already_known:\n            return  # disconnecting something that is not known - nothing to do\n\n        if n.sub_id == 0x41:\n            if not already_known:\n                if n.address == 0x0A and not self.receiver.receiver_kind == \"bolt\":\n                    # some Nanos send a notification even if no new pairing - check that there really is a device there\n                    if (\n                        self.receiver.read_register(\n                            hidpp10_constants.Registers.RECEIVER_INFO,\n                            hidpp10_constants.InfoSubRegisters.PAIRING_INFORMATION + n.devnumber - 1,\n                        )\n                        is None\n                    ):\n                        return\n                dev = self.receiver.register_new_device(n.devnumber, n)\n            elif self.receiver.pairing.lock_open and self.receiver.re_pairs and not ord(n.data[0:1]) & 0x40:\n                dev = self.receiver[n.devnumber]\n                del self.receiver[n.devnumber]  # get rid of information on device re-paired away\n                self._status_changed(dev)  # signal that this device has changed\n                dev = self.receiver.register_new_device(n.devnumber, n)\n                self.receiver.pairing.new_device = self.receiver[n.devnumber]\n            else:\n                dev = self.receiver[n.devnumber]\n        else:\n            dev = self.receiver[n.devnumber]\n\n        if not dev:\n            logger.warning(\"%s: received %s for invalid device %d: %r\", self.receiver, n, n.devnumber, dev)\n            return\n\n        # Apply settings every time the device connects\n        if n.sub_id == 0x41:\n            logger.info(\"connection %s for device wpid %s kind %s serial %s\", n, dev.wpid, dev.kind, dev._serial)\n            # If there are saved configs, bring the device's settings up-to-date.\n            # They will be applied when the device is marked as online.\n            configuration.attach_to(dev)\n            dev.status_callback = self._status_changed\n            # the receiver changed status as well\n            self._status_changed(self.receiver)\n\n        notifications.process(dev, n)\n\n        if self.receiver.pairing.lock_open and not already_known:\n            # this should be the first notification after a device was paired\n            logger.warning(\"first notification was not a connection notification\")\n            logger.info(\"%s: pairing detected new device\", self.receiver)\n            self.receiver.pairing.new_device = dev\n        elif dev.online is None:\n            dev.ping()\n\n    def __str__(self):\n        return f\"<SolaarListener({self.receiver.path},{self.receiver.handle})>\"\n\n\ndef _process_bluez_dbus(device: Device, path, dictionary: dict, signature):\n    \"\"\"Process bluez dbus property changed signals for device status\n    changes to discover disconnections and connections.\n    \"\"\"\n    if device:\n        if dictionary.get(\"Connected\") is not None:\n            connected = dictionary.get(\"Connected\")\n            logger.info(\"bluez dbus for %s: %s\", device, \"CONNECTED\" if connected else \"DISCONNECTED\")\n            device.changed(connected, reason=i18n._(\"connected\") if connected else i18n._(\"disconnected\"))\n    elif device is not None:\n        logger.info(\"bluez cleanup for %s\", device)\n        _cleanup_bluez_dbus(device)\n\n\ndef _cleanup_bluez_dbus(device: Device):\n    \"\"\"Remove dbus signal receiver for device\"\"\"\n    logger.info(\"bluez cleanup for %s\", device)\n    dbus.watch_bluez_connect(device.hid_serial, None)\n\n\n_all_listeners = {}  # all known receiver listeners, listeners that stop on their own may remain here\n\n\ndef _start(device_info: DeviceInfo):\n    assert _status_callback and _setting_callback\n\n    if not device_info.isDevice:\n        receiver_ = logitech_receiver.receiver.create_receiver(base, device_info, _setting_callback)\n    else:\n        receiver_ = logitech_receiver.device.create_device(base, device_info, _setting_callback)\n        if receiver_:\n            configuration.attach_to(receiver_)\n            if receiver_.bluetooth and receiver_.hid_serial:\n                dbus.watch_bluez_connect(receiver_.hid_serial, partial(_process_bluez_dbus, receiver_))\n                receiver_.cleanups.append(_cleanup_bluez_dbus)\n\n    if receiver_:\n        rl = SolaarListener(receiver_, _status_callback)\n        rl.start()\n        _all_listeners[device_info.path] = rl\n        return rl\n\n    logger.warning(\"failed to open %s\", device_info)\n\n\ndef start_all():\n    stop_all()  # just in case this it called twice in a row...\n    logger.info(\"starting receiver listening threads\")\n    for device_info in base.receivers_and_devices():\n        _process_receiver_event(ACTION_ADD, device_info)\n\n\ndef stop_all():\n    listeners = list(_all_listeners.values())\n    _all_listeners.clear()\n    if listeners:\n        logger.info(\"stopping receiver listening threads %s\", listeners)\n        for listener_thread in listeners:\n            listener_thread.stop()\n    configuration.save()\n    if listeners:\n        for listener_thread in listeners:\n            listener_thread.join()\n\n\n# after a resume, the device may have been off so mark its saved status to ensure\n# that the status is pushed to the device when it comes back\ndef ping_all(resuming=False):\n    logger.info(\"ping all devices%s\", \" when resuming\" if resuming else \"\")\n    for listener_thread in _all_listeners.values():\n        if listener_thread.receiver.isDevice:\n            if resuming:\n                listener_thread.receiver._active = None  # ensure that settings are pushed\n            if listener_thread.receiver.ping():\n                listener_thread.receiver.changed(active=True, push=True)\n            listener_thread._status_changed(listener_thread.receiver)\n        else:\n            count = listener_thread.receiver.count()\n            if count:\n                for dev in listener_thread.receiver:\n                    if resuming:\n                        dev._active = None  # ensure that settings are pushed\n                    count -= 1\n                    try:  # sometimes the device is not set up already, it should come back later\n                        if dev.ping():\n                            dev.changed(active=True, push=True)\n                        listener_thread._status_changed(dev)\n                    except exceptions.NoSuchDevice:\n                        logger.debug(\"can't ping device on resume: %s\", dev)\n                    if not count:\n                        break\n\n\n_status_callback = None  # GUI callback to change UI in response to changes to receiver or device status\n_setting_callback = None  # GUI callback to change UI in response to changes to status\n_error_callback = None  # GUI callback to report errors\n\n\ndef setup_scanner(status_changed_callback: Callable, setting_changed_callback: Callable, error_callback: Callable):\n    global _status_callback, _error_callback, _setting_callback\n    assert _status_callback is None, \"scanner was already set-up\"\n    _status_callback = status_changed_callback\n    _setting_callback = setting_changed_callback\n    _error_callback = error_callback\n    base.notify_on_receivers_glib(GLib, _process_receiver_event)\n\n\ndef _process_add(device_info: DeviceInfo, retry):\n    try:\n        _start(device_info)\n    except OSError as e:\n        if e.errno == errno.EACCES:\n            try:\n                output = subprocess.check_output([\"getfacl\", \"-p\", device_info.path], text=True)\n                logger.warning(\"Missing permissions on %s\\n%s.\", device_info.path, output)\n            except Exception:\n                pass\n            if retry:\n                GLib.timeout_add(2000.0, _process_add, device_info, retry - 1)\n            else:\n                _error_callback(common.ErrorReason.PERMISSIONS, device_info.path)\n        else:\n            _error_callback(common.ErrorReason.NO_DEVICE, device_info.path)\n    except exceptions.NoReceiver:\n        _error_callback(common.ErrorReason.NO_DEVICE, device_info.path)\n\n\n# receiver add/remove events will start/stop listener threads\ndef _process_receiver_event(action, device_info):\n    assert action is not None\n    assert device_info is not None\n    assert _error_callback\n    logger.info(\"receiver event %s %s\", action, device_info)\n    # whatever the action, stop any previous receivers at this path\n    listener_thread = _all_listeners.pop(device_info.path, None)\n    if listener_thread is not None:\n        assert isinstance(listener_thread, SolaarListener)\n        listener_thread.stop()\n    if action == ACTION_ADD:\n        _process_add(device_info, 3)\n    return False\n"
  },
  {
    "path": "lib/solaar/tasks.py",
    "content": "#!/usr/bin/env python3\n\n## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport logging\n\nfrom threading import Thread\n\nlogger = logging.getLogger(__name__)\n\ntry:\n    from Queue import Queue\nexcept ImportError:\n    from queue import Queue\n\n\nclass TaskRunner(Thread):\n    def __init__(self, name):\n        super().__init__(name=name)\n        self.daemon = True\n        self.queue = Queue(16)\n        self.alive = False\n\n    def __call__(self, function, *args, **kwargs):\n        task = (function, args, kwargs)\n        self.queue.put(task)\n\n    def stop(self):\n        self.alive = False\n        self.queue.put(None)\n\n    def run(self):\n        self.alive = True\n\n        logger.debug(\"started\")\n\n        while self.alive:\n            task = self.queue.get()\n            if task:\n                function, args, kwargs = task\n                assert function\n                try:\n                    function(*args, **kwargs)\n                except Exception:\n                    logger.exception(\"calling %s\", function)\n\n        logger.debug(\"stopped\")\n"
  },
  {
    "path": "lib/solaar/ui/__init__.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport logging\n\nfrom enum import Enum\nfrom typing import Callable\n\nimport gi\nimport yaml\n\nfrom logitech_receiver.common import Alert\n\nfrom solaar.i18n import _\nfrom solaar.ui.config_panel import change_setting\nfrom solaar.ui.config_panel import record_setting\nfrom solaar.ui.window import find_device\n\nfrom . import common\nfrom . import desktop_notifications\nfrom . import diversion_rules\nfrom . import tray\nfrom . import window\n\ngi.require_version(\"Gtk\", \"3.0\")\nfrom gi.repository import Gio  # NOQA: E402\nfrom gi.repository import GLib  # NOQA: E402\nfrom gi.repository import Gtk  # NOQA: E402\n\nlogger = logging.getLogger(__name__)\n\nassert Gtk.get_major_version() > 2, \"Solaar requires Gtk 3 python bindings\"\n\n\nAPP_ID = \"io.github.pwr_solaar.solaar\"\n\n\nclass GtkSignal(Enum):\n    ACTIVATE = \"activate\"\n    COMMAND_LINE = \"command-line\"\n    SHUTDOWN = \"shutdown\"\n\n\ndef _startup(app, startup_hook, use_tray, show_window):\n    logger.debug(\"startup registered=%s, remote=%s\", app.get_is_registered(), app.get_is_remote())\n    common.start_async()\n    desktop_notifications.init()\n    if use_tray:\n        tray.init(lambda _ignore: window.destroy())\n    window.init(show_window, use_tray)\n    startup_hook()\n\n\ndef _activate(app):\n    logger.debug(\"activate\")\n    if app.get_windows():\n        window.popup()\n    else:\n        app.add_window(window._window)\n\n\ndef _command_line(app, command_line):\n    args = command_line.get_arguments()\n    args = yaml.safe_load(\"\".join(args)) if args else args\n    if not args:\n        _activate(app)\n    elif args[0] == \"config\":  # config call from remote instance\n        logger.info(\"remote command line %s\", args)\n        dev = find_device(args[1])\n        if dev:\n            setting = next((s for s in dev.settings if s.name == args[2]), None)\n            if setting:\n                change_setting(dev, setting, args[3:])\n    return 0\n\n\ndef _shutdown(_app, shutdown_hook):\n    logger.debug(\"shutdown\")\n    shutdown_hook()\n    common.stop_async()\n    tray.destroy()\n    desktop_notifications.uninit()\n\n\ndef run_loop(\n    startup_hook: Callable[[], None],\n    shutdown_hook: Callable[[], None],\n    use_tray: bool,\n    show_window: bool,\n):\n    assert use_tray or show_window, \"need either tray or visible window\"\n\n    application = Gtk.Application.new(APP_ID, Gio.ApplicationFlags.HANDLES_COMMAND_LINE)\n\n    application.connect(\n        \"startup\",\n        lambda app, startup_hook: _startup(app, startup_hook, use_tray, show_window),\n        startup_hook,\n    )\n    application.connect(GtkSignal.COMMAND_LINE.value, _command_line)\n    application.connect(GtkSignal.ACTIVATE.value, _activate)\n    application.connect(GtkSignal.SHUTDOWN.value, _shutdown, shutdown_hook)\n\n    application.register()\n    if application.get_is_remote():\n        print(_(\"Another Solaar process is already running so just expose its window\"))\n    application.run()\n\n\ndef _status_changed(device, alert, reason, refresh=False):\n    if device is None:\n        logger.debug(\"status changed on nil device: %s (%s) %s\", device, alert, reason)\n        return\n    logger.debug(\"status changed: %s (%s) %s\", device, alert, reason)\n    if alert is None:\n        alert = Alert.NONE\n\n    tray.update(device)\n    if alert & Alert.ATTENTION:\n        tray.attention(reason)\n\n    need_popup = alert & Alert.SHOW_WINDOW\n    window.update(device, need_popup, refresh)\n    diversion_rules.update_devices()\n\n    if alert & (Alert.NOTIFICATION | Alert.ATTENTION):\n        desktop_notifications.show(device, reason)\n\n\ndef status_changed(device, alert=Alert.NONE, reason=None, refresh=False):\n    GLib.idle_add(_status_changed, device, alert, reason, refresh)\n\n\ndef setting_changed(device, setting_class, vals):\n    record_setting(device, setting_class, vals)\n"
  },
  {
    "path": "lib/solaar/ui/about/__init__.py",
    "content": ""
  },
  {
    "path": "lib/solaar/ui/about/about.py",
    "content": "## Copyright (C) Solaar Contributors\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom solaar.ui.about.model import AboutModel\nfrom solaar.ui.about.presenter import Presenter\nfrom solaar.ui.about.view import AboutView\n\n\ndef show(_=None, model=None, view=None):\n    \"\"\"Opens the About dialog.\"\"\"\n    if model is None:\n        model = AboutModel()\n    if view is None:\n        view = AboutView()\n    presenter = Presenter(model, view)\n    presenter.run()\n\n\nif __name__ == \"__main__\":\n    from gi.repository import Gtk\n\n    show(None)\n    Gtk.main()\n"
  },
  {
    "path": "lib/solaar/ui/about/model.py",
    "content": "## Copyright (C) Solaar Contributors\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom __future__ import annotations\n\nfrom datetime import datetime\nfrom typing import List\nfrom typing import Tuple\n\nfrom solaar import __version__\nfrom solaar.i18n import _\n\n\ndef _get_current_year() -> int:\n    return datetime.now().year\n\n\nclass AboutModel:\n    def get_version(self) -> str:\n        return __version__\n\n    def get_description(self) -> str:\n        return _(\"Manages Logitech receivers,\\nkeyboards, mice, and tablets.\")\n\n    def get_copyright(self) -> str:\n        return f\"© 2012-{_get_current_year()} Daniel Pavel and contributors to the Solaar project\"\n\n    def get_authors(self) -> List[str]:\n        return [\n            \"Daniel Pavel http://github.com/pwr\",\n        ]\n\n    def get_translators(self) -> List[str]:\n        return [\n            \"gogo (croatian)\",\n            \"Papoteur, David Geiger, Damien Lallement (français)\",\n            \"Michele Olivo (italiano)\",\n            \"Adrian Piotrowicz (polski)\",\n            \"Drovetto, JrBenito (Portuguese-BR)\",\n            \"Daniel Pavel (română)\",\n            \"Daniel Zippert, Emelie Snecker (svensk)\",\n            \"Dimitriy Ryazantcev (Russian)\",\n            \"El Jinete Sin Cabeza (Español)\",\n            \"Ferdina Kusumah (Indonesia)\",\n            \"John Erling Blad (Norwegian Bokmål, Norwegian Nynorsk)\",\n            \"Oleksandr Afanasiev (Ukrainian)\",\n        ]\n\n    def get_credit_sections(self) -> List[Tuple[str, List[str]]]:\n        return [\n            (_(\"Additional Programming\"), [\"Filipe Laíns\", \"Peter F. Patel-Schneider\"]),\n            (_(\"GUI design\"), [\"Julien Gascard\", \"Daniel Pavel\"]),\n            (\n                _(\"Testing\"),\n                [\n                    \"Douglas Wagner\",\n                    \"Julien Gascard\",\n                    \"Peter Wu http://www.lekensteyn.nl/logitech-unifying.html\",\n                ],\n            ),\n            (\n                _(\"Logitech documentation\"),\n                [\n                    \"Julien Danjou http://julien.danjou.info/blog/2012/logitech-unifying-upower\",\n                    \"Nestor Lopez Casado http://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28\",\n                ],\n            ),\n        ]\n\n    def get_website(self):\n        return \"https://pwr-solaar.github.io/Solaar\"\n"
  },
  {
    "path": "lib/solaar/ui/about/presenter.py",
    "content": "## Copyright (C) Solaar Contributors\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom __future__ import annotations\n\nfrom typing_extensions import Protocol\n\nfrom solaar.ui.about.model import AboutModel\n\n\nclass AboutViewProtocol(Protocol):\n    def init_ui(self) -> None:\n        ...\n\n    def update_version_info(self, version: str) -> None:\n        ...\n\n    def update_description(self, comments: str) -> None:\n        ...\n\n    def update_copyright(self, copyright_text: str) -> None:\n        ...\n\n    def update_authors(self, authors: list[str]) -> None:\n        ...\n\n    def update_translators(self, translators: list[str]) -> None:\n        ...\n\n    def update_website(self, website):\n        ...\n\n    def update_credits(self, credit_sections: list[tuple[str, list[str]]]) -> None:\n        ...\n\n    def show(self) -> None:\n        ...\n\n\nclass Presenter:\n    def __init__(self, model: AboutModel, view: AboutViewProtocol) -> None:\n        self.model = model\n        self.view = view\n\n    def update_version_info(self) -> None:\n        version = self.model.get_version()\n        self.view.update_version_info(version)\n\n    def update_credits(self) -> None:\n        credit_sections = self.model.get_credit_sections()\n        self.view.update_credits(credit_sections)\n\n    def update_description(self) -> None:\n        comments = self.model.get_description()\n        self.view.update_description(comments)\n\n    def update_copyright(self) -> None:\n        copyright_text = self.model.get_copyright()\n        self.view.update_copyright(copyright_text)\n\n    def update_authors(self) -> None:\n        authors = self.model.get_authors()\n        self.view.update_authors(authors)\n\n    def update_translators(self) -> None:\n        translators = self.model.get_translators()\n        self.view.update_translators(translators)\n\n    def update_website(self) -> None:\n        website = self.model.get_website()\n        self.view.update_website(website)\n\n    def run(self) -> None:\n        self.view.init_ui()\n        self.update_version_info()\n        self.update_description()\n        self.update_website()\n        self.update_copyright()\n        self.update_authors()\n        self.update_credits()\n        self.update_translators()\n        self.view.show()\n"
  },
  {
    "path": "lib/solaar/ui/about/view.py",
    "content": "## Copyright (C) Solaar Contributors\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nfrom enum import Enum\nfrom typing import List\nfrom typing import Tuple\nfrom typing import Union\n\nfrom gi.repository import Gtk\n\nfrom solaar import NAME\n\n\nclass GtkSignal(Enum):\n    RESPONSE = \"response\"\n\n\nclass AboutView:\n    def __init__(self) -> None:\n        self.view: Union[Gtk.AboutDialog, None] = None\n\n    def init_ui(self) -> None:\n        self.view = Gtk.AboutDialog()\n        self.view.set_program_name(NAME)\n        self.view.set_logo_icon_name(NAME.lower())\n        self.view.set_license_type(Gtk.License.GPL_2_0)\n\n        self.view.connect(GtkSignal.RESPONSE.value, lambda x, y: self.handle_close(x))\n\n    def update_version_info(self, version: str) -> None:\n        self.view.set_version(version)\n\n    def update_description(self, comments: str) -> None:\n        self.view.set_comments(comments)\n\n    def update_copyright(self, copyright_text: str):\n        self.view.set_copyright(copyright_text)\n\n    def update_authors(self, authors: List[str]) -> None:\n        self.view.set_authors(authors)\n\n    def update_credits(self, credit_sections: List[Tuple[str, List[str]]]) -> None:\n        for section_name, people in credit_sections:\n            self.view.add_credit_section(section_name, people)\n\n    def update_translators(self, translators: List[str]) -> None:\n        translator_credits = \"\\n\".join(translators)\n        self.view.set_translator_credits(translator_credits)\n\n    def update_website(self, website):\n        self.view.set_website_label(NAME)\n        self.view.set_website(website)\n\n    def show(self) -> None:\n        self.view.present()\n\n    def handle_close(self, event) -> None:\n        event.hide()\n"
  },
  {
    "path": "lib/solaar/ui/action.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nfrom enum import Enum\n\nfrom gi.repository import Gdk\nfrom gi.repository import Gtk\n\nfrom solaar.i18n import _\nfrom solaar.ui import common\n\nfrom . import pair_window\n\n\nclass GtkSignal(Enum):\n    ACTIVATE = \"activate\"\n\n\ndef make_image_menu_item(label, icon_name, function, *args):\n    box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 6)\n    label = Gtk.Label(label=label)\n    icon = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.LARGE_TOOLBAR) if icon_name is not None else Gtk.Image()\n    box.add(icon)\n    box.add(label)\n    menu_item = Gtk.MenuItem()\n    menu_item.add(box)\n    menu_item.show_all()\n    menu_item.connect(GtkSignal.ACTIVATE.value, function, *args)\n    menu_item.label = label\n    menu_item.icon = icon\n    return menu_item\n\n\ndef make(name, label, function, stock_id=None, *args):\n    action = Gtk.Action(name=name, label=label, tooltip=label, stock_id=None)\n    action.set_icon_name(name)\n    if stock_id is not None:\n        action.set_stock_id(stock_id)\n    if function:\n        action.connect(GtkSignal.ACTIVATE.value, function, *args)\n    return action\n\n\ndef make_toggle(name, label, function, stock_id=None, *args):\n    action = Gtk.ToggleAction(name=name, label=label, tooltip=label, stock_id=None)\n    action.set_icon_name(name)\n    if stock_id is not None:\n        action.set_stock_id(stock_id)\n    action.connect(GtkSignal.ACTIVATE.value, function, *args)\n    return action\n\n\ndef pair(window, receiver):\n    assert receiver\n    assert receiver.kind is None\n\n    pair_dialog = pair_window.create(receiver)\n    pair_dialog.set_transient_for(window)\n    pair_dialog.set_destroy_with_parent(True)\n    pair_dialog.set_modal(True)\n    pair_dialog.set_type_hint(Gdk.WindowTypeHint.DIALOG)\n    pair_dialog.set_position(Gtk.WindowPosition.CENTER)\n    pair_dialog.present()\n\n\ndef unpair(window, device):\n    assert device\n    assert device.kind is not None\n\n    qdialog = Gtk.MessageDialog(\n        transient_for=window,\n        flags=0,\n        message_type=Gtk.MessageType.QUESTION,\n        buttons=Gtk.ButtonsType.NONE,\n        text=_(\"Unpair\") + \" \" + device.name + \" ?\",\n    )\n    qdialog.set_icon_name(\"remove\")\n    qdialog.add_button(_(\"Cancel\"), Gtk.ResponseType.CANCEL)\n    qdialog.add_button(_(\"Unpair\"), Gtk.ResponseType.ACCEPT)\n    choice = qdialog.run()\n    qdialog.destroy()\n    if choice == Gtk.ResponseType.ACCEPT:\n        receiver = device.receiver\n        assert receiver\n        device_number = device.number\n\n        try:\n            del receiver[device_number]\n        except Exception:\n            common.error_dialog(common.ErrorReason.UNPAIR, device)\n"
  },
  {
    "path": "lib/solaar/ui/common.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport logging\n\nfrom enum import Enum\nfrom typing import Tuple\n\nimport gi\n\nfrom solaar.i18n import _\nfrom solaar.tasks import TaskRunner\n\ngi.require_version(\"Gtk\", \"3.0\")\nfrom gi.repository import GLib  # NOQA: E402\nfrom gi.repository import Gtk  # NOQA: E402\n\nlogger = logging.getLogger(__name__)\n\n\nclass ErrorReason(Enum):\n    PERMISSIONS = \"Permissions\"\n    NO_DEVICE = \"No device\"\n    UNPAIR = \"Unpair\"\n\n\ndef _create_error_text(reason: ErrorReason, object_) -> Tuple[str, str]:\n    if reason == ErrorReason.PERMISSIONS:\n        title = _(\"Permissions error\")\n        text = (\n            _(\"Found a Logitech receiver or device (%s), but did not have permission to open it.\") % object_\n            + \"\\n\\n\"\n            + _(\"If you've just installed Solaar, try disconnecting the receiver or device and then reconnecting it.\")\n        )\n    elif reason == ErrorReason.NO_DEVICE:\n        title = _(\"Cannot connect to device error\")\n        text = (\n            _(\"Found a Logitech receiver or device at %s, but encountered an error connecting to it.\") % object_\n            + \"\\n\\n\"\n            + _(\"Try disconnecting the device and then reconnecting it or turning it off and then on.\")\n        )\n    elif reason == ErrorReason.UNPAIR:\n        title = _(\"Unpairing failed\")\n        text = (\n            _(\"Failed to unpair %{device} from %{receiver}.\").format(\n                device=object_.name,\n                receiver=object_.receiver.name,\n            )\n            + \"\\n\\n\"\n            + _(\"The receiver returned an error, with no further details.\")\n        )\n    else:\n        raise Exception(\"ui.error_dialog: don't know how to handle (%s, %s)\", reason.name, object_)\n    return title, text\n\n\ndef _error_dialog(reason: ErrorReason, object_):\n    logger.error(\"error: %s %s\", reason, object_)\n    title, text = _create_error_text(reason, object_)\n\n    m = Gtk.MessageDialog(None, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, text)\n    m.set_title(title)\n    m.run()\n    m.destroy()\n\n\ndef error_dialog(reason: ErrorReason, object_):\n    GLib.idle_add(_error_dialog, reason, object_)\n\n\n_task_runner = None\n\n\ndef start_async():\n    global _task_runner\n    _task_runner = TaskRunner(\"AsyncUI\")\n    _task_runner.start()\n\n\ndef stop_async():\n    global _task_runner\n    _task_runner.stop()\n    _task_runner = None\n\n\ndef ui_async(function, *args, **kwargs):\n    \"\"\"Runs a function asynchronously.\"\"\"\n    if _task_runner:\n        _task_runner(function, *args, **kwargs)\n"
  },
  {
    "path": "lib/solaar/ui/config_panel.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport logging\n\nfrom enum import Enum\nfrom threading import Timer\n\nimport gi\n\nfrom logitech_receiver import hidpp20\nfrom logitech_receiver import settings\n\nfrom solaar.i18n import _\nfrom solaar.i18n import ngettext\n\nfrom .common import ui_async\n\ngi.require_version(\"Gtk\", \"3.0\")\nfrom gi.repository import Gdk  # NOQA: E402\nfrom gi.repository import GLib  # NOQA: E402\nfrom gi.repository import Gtk  # NOQA: E402\n\nlogger = logging.getLogger(__name__)\n\n\nclass GtkSignal(Enum):\n    ACTIVATE = \"activate\"\n    CHANGED = \"changed\"\n    CLICKED = \"clicked\"\n    MATCH_SELECTED = \"match_selected\"\n    NOTIFY_ACTIVE = \"notify::active\"\n    TOGGLED = \"toggled\"\n    VALUE_CHANGED = \"value-changed\"\n    COLOR_SET = \"color-set\"\n\n\ndef _read_async(setting, force_read, sbox, device_is_online, sensitive):\n    def _do_read(s, force, sb, online, sensitive):\n        try:\n            v = s.read(not force)\n        except Exception as e:\n            v = None\n            logger.warning(\"%s: error reading so use None (%s): %s\", s.name, s._device, repr(e))\n        GLib.idle_add(_update_setting_item, sb, v, online, sensitive, True, priority=99)\n\n    ui_async(_do_read, setting, force_read, sbox, device_is_online, sensitive)\n\n\ndef _write_async(setting, value, sbox, sensitive=True, key=None):\n    def _do_write(_s, v, sb, key):\n        try:\n            if key is None:\n                v = setting.write(v)\n            else:\n                v = setting.write_key_value(key, v)\n                v = {key: v}\n        except Exception:\n            v = None\n        if sb:\n            GLib.idle_add(_update_setting_item, sb, v, True, sensitive, priority=99)\n\n    if sbox:\n        sbox._control.set_sensitive(False)\n        sbox._failed.set_visible(False)\n        sbox._spinner.set_visible(True)\n        sbox._spinner.start()\n    ui_async(_do_write, setting, value, sbox, key)\n\n\nclass ComboBoxText(Gtk.ComboBoxText):\n    def get_value(self):\n        return int(self.get_active_id())\n\n    def set_value(self, value):\n        return self.set_active_id(str(int(value)))\n\n\nclass Scale(Gtk.Scale):\n    def get_value(self):\n        return int(super().get_value())\n\n\nclass Control:\n    def __init__(self, **kwargs):\n        self.sbox = None\n        self.delegate = None\n\n    def init(self, sbox, delegate):\n        self.sbox = sbox\n        self.delegate = delegate if delegate else self\n\n    def changed(self, *args):\n        if self.get_sensitive():\n            self.delegate.update()\n\n    def update(self):\n        _write_async(self.sbox.setting, self.get_value(), self.sbox)\n\n    def layout(self, sbox, label, change, spinner, failed):\n        sbox.pack_start(label, False, False, 0)\n        sbox.pack_end(change, False, False, 0)\n        fill = sbox.setting.kind == settings.Kind.RANGE or sbox.setting.kind == settings.Kind.HETERO\n        sbox.pack_end(self, fill, fill, 0)\n        sbox.pack_end(spinner, False, False, 0)\n        sbox.pack_end(failed, False, False, 0)\n        return self\n\n\nclass ToggleControl(Gtk.Switch, Control):\n    def __init__(self, sbox, delegate=None):\n        super().__init__(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER)\n        self.init(sbox, delegate)\n        self.connect(GtkSignal.NOTIFY_ACTIVE.value, self.changed)\n\n    def set_value(self, value):\n        if value is not None:\n            self.set_state(value)\n\n    def get_value(self):\n        return self.get_state()\n\n\nclass SliderControl(Gtk.Scale, Control):\n    def __init__(self, sbox, delegate=None):\n        super().__init__(halign=Gtk.Align.FILL)\n        self.init(sbox, delegate)\n        self.timer = None\n        self.set_range(*self.sbox.setting.range)\n        self.set_round_digits(0)\n        self.set_digits(0)\n        self.set_increments(1, 5)\n        self.connect(GtkSignal.VALUE_CHANGED.value, self.changed)\n\n    def set_value(self, value):\n        if isinstance(value, dict):\n            value = next(iter(value.values()))\n        return super().set_value(value)\n\n    def get_value(self):\n        return int(super().get_value())\n\n    def changed(self, *args):\n        if self.get_sensitive():\n            if self.timer:\n                self.timer.cancel()\n            self.timer = Timer(0.5, lambda: GLib.idle_add(self.do_change))\n            self.timer.start()\n\n    def do_change(self):\n        self.timer.cancel()\n        self.update()\n\n\ndef _create_choice_control(sbox, delegate=None, choices=None):\n    if 50 > len(choices if choices else sbox.setting.choices):\n        return ChoiceControlLittle(sbox, choices=choices, delegate=delegate)\n    else:\n        return ChoiceControlBig(sbox, choices=choices, delegate=delegate)\n\n\n# GTK boxes have property lists, but the keys must be strings\nclass ChoiceControlLittle(Gtk.ComboBoxText, Control):\n    def __init__(self, sbox, delegate=None, choices=None):\n        super().__init__(halign=Gtk.Align.FILL)\n        self.init(sbox, delegate)\n        self.choices = choices if choices is not None else sbox.setting.choices\n        for entry in self.choices:\n            self.append(str(int(entry)), str(entry))\n        self.connect(GtkSignal.CHANGED.value, self.changed)\n\n    def get_value(self):\n        return int(self.get_active_id()) if self.get_active_id() is not None else None\n\n    def set_value(self, value):\n        if value is not None:\n            self.set_active_id(str(int(value)))\n\n    def get_choice(self):\n        id = self.get_value()\n        return next((x for x in self.choices if x == id), None)\n\n    def set_choices(self, choices):\n        self.remove_all()\n        for choice in choices:\n            self.append(str(int(choice)), _(str(choice)))\n\n\nclass ChoiceControlBig(Gtk.Entry, Control):\n    def __init__(self, sbox, delegate=None, choices=None):\n        super().__init__(halign=Gtk.Align.FILL)\n        self.init(sbox, delegate)\n        self.choices = choices if choices is not None else sbox.setting.choices\n        self.value = None\n        self.set_width_chars(max([len(str(x)) for x in self.choices]) + 5)\n        liststore = Gtk.ListStore(int, str)\n        for v in self.choices:\n            liststore.append((int(v), str(v)))\n        completion = Gtk.EntryCompletion()\n        completion.set_model(liststore)\n\n        def norm(s):\n            return s.replace(\"_\", \"\").replace(\" \", \"\").lower()\n\n        completion.set_match_func(lambda completion, key, it: norm(key) in norm(completion.get_model()[it][1]))\n        completion.set_text_column(1)\n        self.set_completion(completion)\n        self.connect(GtkSignal.CHANGED.value, self.changed)\n        self.connect(GtkSignal.ACTIVATE.value, self.activate)\n        completion.connect(GtkSignal.MATCH_SELECTED.value, self.select)\n\n    def get_value(self):\n        choice = self.get_choice()\n        return int(choice) if choice is not None else None\n\n    def set_value(self, value):\n        if value is not None:\n            self.set_text(str(next((x for x in self.choices if x == value), None)))\n\n    def get_choice(self):\n        key = self.get_text()\n        return next((x for x in self.choices if x == key), None)\n\n    def set_choices(self, choices):\n        self.choices = choices\n\n    def changed(self, *args):\n        self.value = self.get_choice()\n        icon = \"dialog-warning\" if self.value is None else \"dialog-question\" if self.get_sensitive() else \"\"\n        self.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n        tooltip = _(\"Incomplete\") if self.value is None else _(\"Complete - ENTER to change\")\n        self.set_icon_tooltip_text(Gtk.EntryIconPosition.SECONDARY, tooltip)\n\n    def activate(self, *_args):\n        if self.value is not None and self.get_sensitive():\n            self.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, \"\")\n            self.delegate.update()\n\n    def select(self, _completion, model, iter):\n        self.set_value(model.get(iter, 0)[0])\n        if self.value and self.get_sensitive():\n            self.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, \"\")\n            self.delegate.update()\n\n\nclass MapChoiceControl(Gtk.HBox, Control):\n    def __init__(self, sbox, delegate=None):\n        super().__init__(homogeneous=False, spacing=6)\n        self.init(sbox, delegate)\n        self.keyBox = Gtk.ComboBoxText()\n        for entry in sbox.setting.choices:\n            self.keyBox.append(str(int(entry)), _(str(entry)))\n        self.keyBox.set_active(0)\n        key_choice = int(self.keyBox.get_active_id())\n        self.value_choices = self.sbox.setting.choices[key_choice]\n        self.valueBox = _create_choice_control(sbox.setting, choices=self.value_choices, delegate=self)\n        self.pack_start(self.keyBox, False, False, 0)\n        self.pack_end(self.valueBox, False, False, 0)\n        self.keyBox.connect(GtkSignal.CHANGED.value, self.map_value_notify_key)\n\n    def get_value(self):\n        key_choice = int(self.keyBox.get_active_id())\n        if key_choice is not None and self.valueBox.get_value() is not None:\n            return self.valueBox.get_value()\n\n    def set_value(self, value):\n        if value is None:\n            return\n        self.valueBox.set_sensitive(self.get_sensitive())\n        key = int(self.keyBox.get_active_id())\n        if value.get(key) is not None:\n            self.valueBox.set_value(value.get(key))\n        self.valueBox.set_sensitive(True)\n\n    def map_populate_value_box(self, key_choice):\n        choices = self.sbox.setting.choices[key_choice]\n        if choices != self.value_choices:\n            self.value_choices = choices\n            self.valueBox.set_choices(choices)\n        current = self.sbox.setting._value.get(key_choice) if self.sbox.setting._value else None\n        if current is not None:\n            self.valueBox.set_value(current)\n\n    def map_value_notify_key(self, *_args):\n        key_choice = int(self.keyBox.get_active_id())\n        if self.keyBox.get_sensitive():\n            self.map_populate_value_box(key_choice)\n\n    def update(self):\n        key_choice = int(self.keyBox.get_active_id())\n        value = self.get_value()\n        if value is not None and self.valueBox.get_sensitive() and self.sbox.setting._value.get(key_choice) != value:\n            self.sbox.setting._value[int(key_choice)] = value\n            _write_async(self.sbox.setting, value, self.sbox, key=int(key_choice))\n\n\nclass MultipleControl(Gtk.ListBox, Control):\n    def __init__(self, sbox, change, button_label=\"...\", delegate=None):\n        super().__init__()\n        self.init(sbox, delegate)\n        self.set_selection_mode(Gtk.SelectionMode.NONE)\n        self.set_no_show_all(True)\n        self._showing = True\n        self.setup(sbox.setting)  # set up the data and boxes for the sub-controls\n        btn = Gtk.Button(label=button_label)\n        btn.connect(GtkSignal.CLICKED.value, self.toggle_display)\n        self._button = btn\n        hbox = Gtk.HBox(homogeneous=False, spacing=6)\n        hbox.pack_end(change, False, False, 0)\n        hbox.pack_end(btn, False, False, 0)\n        self._header = hbox\n        vbox = Gtk.VBox(homogeneous=False, spacing=6)\n        vbox.pack_start(hbox, True, True, 0)\n        vbox.pack_end(self, True, True, 0)\n        self.vbox = vbox\n        self.toggle_display()\n        _disable_listbox_highlight_bg(self)\n\n    def layout(self, sbox, label, change, spinner, failed):\n        self._header.pack_start(label, False, False, 0)\n        self._header.pack_end(spinner, False, False, 0)\n        self._header.pack_end(failed, False, False, 0)\n        sbox.pack_start(self.vbox, True, True, 0)\n        sbox._button = self._button\n        return True\n\n    def toggle_display(self, *_args):\n        self._showing = not self._showing\n        if not self._showing:\n            for c in self.get_children():\n                c.hide()\n            self.hide()\n        else:\n            self.show()\n            for c in self.get_children():\n                c.show_all()\n\n\nclass MultipleToggleControl(MultipleControl):\n    def setup(self, setting):\n        self._label_control_pairs = []\n        for k in setting._validator.get_options():\n            h = Gtk.HBox(homogeneous=False, spacing=0)\n            lbl_text = str(k)\n            lbl_tooltip = None\n            if hasattr(setting, \"_labels\"):\n                l1, l2 = setting._labels.get(k, (None, None))\n                lbl_text = l1 if l1 else lbl_text\n                lbl_tooltip = l2 if l2 else lbl_tooltip\n            lbl = Gtk.Label(label=lbl_text)\n            h.set_tooltip_text(lbl_tooltip or \" \")\n            control = Gtk.Switch()\n            control._setting_key = int(k)\n            control.connect(GtkSignal.NOTIFY_ACTIVE.value, self.toggle_notify)\n            h.pack_start(lbl, False, False, 0)\n            h.pack_end(control, False, False, 0)\n            lbl.set_margin_start(30)\n            self.add(h)\n            self._label_control_pairs.append((lbl, control))\n\n    def toggle_notify(self, switch, _active):\n        if switch.get_sensitive():\n            key = switch._setting_key\n            new_state = switch.get_state()\n            if self.sbox.setting._value[key] != new_state:\n                self.sbox.setting._value[key] = new_state\n                _write_async(self.sbox.setting, new_state, self.sbox, key=int(key))\n\n    def set_value(self, value):\n        if value is None:\n            return\n        active = 0\n        total = len(self._label_control_pairs)\n        to_join = []\n        for lbl, elem in self._label_control_pairs:\n            v = value.get(elem._setting_key, None)\n            if v is not None:\n                elem.set_state(v)\n            if elem.get_state():\n                active += 1\n            to_join.append(f\"{lbl.get_text()}: {str(elem.get_state())}\")\n        b = \", \".join(to_join)\n        self._button.set_label(f\"{active} / {total}\")\n        self._button.set_tooltip_text(b)\n\n\nclass MultipleRangeControl(MultipleControl):\n    def setup(self, setting):\n        self._items = []\n        for item in setting._validator.items:\n            lbl_text = str(item)\n            lbl_tooltip = None\n            if hasattr(setting, \"_labels\"):\n                l1, l2 = setting._labels.get(int(item), (None, None))\n                lbl_text = l1 if l1 else lbl_text\n                lbl_tooltip = l2 if l2 else lbl_tooltip\n            item_lbl = Gtk.Label(label=lbl_text)\n            self.add(item_lbl)\n            self.set_tooltip_text(lbl_tooltip or \" \")\n            item_lb = Gtk.ListBox()\n            item_lb.set_selection_mode(Gtk.SelectionMode.NONE)\n            item_lb._sub_items = []\n            for sub_item in setting._validator.sub_items[item]:\n                h = Gtk.HBox(homogeneous=False, spacing=20)\n                lbl_text = str(sub_item)\n                lbl_tooltip = None\n                if hasattr(setting, \"_labels_sub\"):\n                    l1, l2 = setting._labels_sub.get(str(sub_item), (None, None))\n                    lbl_text = l1 if l1 else lbl_text\n                    lbl_tooltip = l2 if l2 else lbl_tooltip\n                sub_item_lbl = Gtk.Label(label=lbl_text)\n                h.set_tooltip_text(lbl_tooltip or \" \")\n                h.pack_start(sub_item_lbl, False, False, 0)\n                sub_item_lbl.set_margin_start(30)\n                if sub_item.widget == \"Scale\":\n                    control = Gtk.Scale.new_with_range(\n                        Gtk.Orientation.HORIZONTAL,\n                        sub_item.minimum,\n                        sub_item.maximum,\n                        1,\n                    )\n                    control.set_round_digits(0)\n                    control.set_digits(0)\n                    h.pack_end(control, True, True, 0)\n                elif sub_item.widget == \"SpinButton\":\n                    control = Gtk.SpinButton.new_with_range(sub_item.minimum, sub_item.maximum, 1)\n                    control.set_digits(0)\n                    h.pack_end(control, False, False, 0)\n                else:\n                    raise NotImplementedError\n                control.connect(GtkSignal.VALUE_CHANGED.value, self.changed, item, sub_item)\n                item_lb.add(h)\n                h._setting_sub_item = sub_item\n                h._label, h._control = sub_item_lbl, control\n                item_lb._sub_items.append(h)\n            item_lb._setting_item = item\n            _disable_listbox_highlight_bg(item_lb)\n            self.add(item_lb)\n            self._items.append(item_lb)\n\n    def changed(self, control, item, sub_item):\n        if control.get_sensitive():\n            if hasattr(control, \"_timer\"):\n                control._timer.cancel()\n            control._timer = Timer(0.5, lambda: GLib.idle_add(self._write, control, item, sub_item))\n            control._timer.start()\n\n    def _write(self, control, item, sub_item):\n        control._timer.cancel()\n        delattr(control, \"_timer\")\n        new_state = int(control.get_value())\n        if self.sbox.setting._value[int(item)][str(sub_item)] != new_state:\n            self.sbox.setting._value[int(item)][str(sub_item)] = new_state\n            _write_async(self.sbox.setting, self.sbox.setting._value[int(item)], self.sbox, key=int(item))\n\n    def set_value(self, value):\n        if value is None:\n            return\n        b = \"\"\n        n = 0\n        for ch in self._items:\n            item = ch._setting_item\n            v = value.get(int(item), None)\n            if v is not None:\n                b += f\"{str(item)}: (\"\n                to_join = []\n                for c in ch._sub_items:\n                    sub_item = c._setting_sub_item\n                    try:\n                        sub_item_value = v[str(sub_item)]\n                    except KeyError:\n                        sub_item_value = c._control.get_value()\n                    c._control.set_value(sub_item_value)\n                    n += 1\n                    to_join.append(f\"{str(sub_item)}={sub_item_value}\")\n                b += \", \".join(to_join) + \") \"\n        lbl_text = ngettext(\"%d value\", \"%d values\", n) % n\n        self._button.set_label(lbl_text)\n        self._button.set_tooltip_text(b)\n\n\nclass PackedRangeControl(MultipleRangeControl):\n    def setup(self, setting):\n        self._items = []\n        validator = setting._validator\n        for item in range(validator.count):\n            h = Gtk.HBox(homogeneous=False, spacing=0)\n            lbl = Gtk.Label(label=str(validator.keys[item]))\n            control = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, validator.min_value, validator.max_value, 1)\n            control.set_round_digits(0)\n            control.set_digits(0)\n            control.connect(GtkSignal.VALUE_CHANGED.value, self.changed, validator.keys[item])\n            h.pack_start(lbl, False, False, 0)\n            h.pack_end(control, True, True, 0)\n            h._setting_item = validator.keys[item]\n            h.control = control\n            lbl.set_margin_start(30)\n            self.add(h)\n            self._items.append(h)\n\n    def changed(self, control, item):\n        if control.get_sensitive():\n            if hasattr(control, \"_timer\"):\n                control._timer.cancel()\n            control._timer = Timer(0.5, lambda: GLib.idle_add(self._write, control, item))\n            control._timer.start()\n\n    def _write(self, control, item):\n        control._timer.cancel()\n        delattr(control, \"_timer\")\n        new_state = int(control.get_value())\n        if self.sbox.setting._value[int(item)] != new_state:\n            self.sbox.setting._value[int(item)] = new_state\n            _write_async(self.sbox.setting, self.sbox.setting._value[int(item)], self.sbox, key=int(item))\n\n    def set_value(self, value):\n        if value is None:\n            return\n        b = \"\"\n        n = len(self._items)\n        for h in self._items:\n            item = h._setting_item\n            v = value.get(int(item), None)\n            if v is not None:\n                h.control.set_value(v)\n            else:\n                v = self.sbox.setting._value[int(item)]\n            b += f\"{str(item)}: ({str(v)}) \"\n        lbl_text = ngettext(\"%d value\", \"%d values\", n) % n\n        self._button.set_label(lbl_text)\n        self._button.set_tooltip_text(b)\n\n\n# control with an ID key that determines what else to show\nclass HeteroKeyControl(Gtk.HBox, Control):\n    def __init__(self, sbox, delegate=None):\n        super().__init__(homogeneous=False, spacing=6)\n        self.init(sbox, delegate)\n        self._items = {}\n        for item in sbox.setting.possible_fields:\n            if item[\"label\"]:\n                item_lblbox = Gtk.Label(label=item[\"label\"])\n                self.pack_start(item_lblbox, False, False, 0)\n                item_lblbox.set_visible(False)\n            else:\n                item_lblbox = None\n\n            item_box = ComboBoxText()\n            if item[\"kind\"] == settings.Kind.CHOICE:\n                for entry in item[\"choices\"]:\n                    item_box.append(str(int(entry)), str(entry))\n                item_box.set_active(0)\n                item_box.connect(GtkSignal.CHANGED.value, self.changed)\n                self.pack_start(item_box, False, False, 0)\n            elif item[\"kind\"] == settings.Kind.COLOR:\n                item_box = Gtk.ColorButton()\n                item_box.connect(GtkSignal.COLOR_SET.value, self.changed)\n                self.pack_start(item_box, False, False, 0)\n            elif item[\"kind\"] == settings.Kind.RANGE:\n                item_box = Scale()\n                item_box.set_range(item[\"min\"], item[\"max\"])\n                item_box.set_round_digits(0)\n                item_box.set_digits(0)\n                item_box.set_increments(1, 5)\n                item_box.connect(GtkSignal.VALUE_CHANGED.value, self.changed)\n                self.pack_start(item_box, True, True, 0)\n            item_box.set_visible(False)\n            self._items[str(item[\"name\"])] = (item_lblbox, item_box)\n\n    def get_value(self):\n        result = {}\n        for k, (_lblbox, box) in self._items.items():\n            if isinstance(box, Gtk.ColorButton):\n                rgba = box.get_rgba()\n                r = int(rgba.red * 255)\n                g = int(rgba.green * 255)\n                b = int(rgba.blue * 255)\n                result[str(k)] = (r << 16) | (g << 8) | b\n            else:\n                result[str(k)] = box.get_value()\n        result = hidpp20.LEDEffectSetting(**result)\n        return result\n\n    def set_value(self, value):\n        self.set_sensitive(False)\n        if value is not None:\n            for k, v in value.__dict__.items():\n                if k in self._items:\n                    (lblbox, box) = self._items[k]\n                    if isinstance(box, Gtk.ColorButton):\n                        rgba = Gdk.RGBA()\n                        color_string = f\"#{v:06X}\"  # e.g. \"#FF0000\"\n                        rgba.parse(color_string)\n                        box.set_rgba(rgba)\n                    else:\n                        box.set_value(v)\n        else:\n            self.sbox._failed.set_visible(True)\n        self.setup_visibles(value.ID if value is not None else 0)\n\n    def setup_visibles(self, id_):\n        fields = self.sbox.setting.fields_map[id_][1] if id_ in self.sbox.setting.fields_map else {}\n        for name, (lblbox, box) in self._items.items():\n            visible = name in fields or name == \"ID\"\n            if lblbox:\n                lblbox.set_visible(visible)\n            box.set_visible(visible)\n\n    def changed(self, control):\n        if self.get_sensitive() and control.get_sensitive():\n            if \"ID\" in self._items and control == self._items[\"ID\"][1]:\n                self.setup_visibles(int(self._items[\"ID\"][1].get_value()))\n            if hasattr(control, \"_timer\"):\n                control._timer.cancel()\n            control._timer = Timer(0.3, lambda: GLib.idle_add(self._write, control))\n            control._timer.start()\n\n    def _write(self, control):\n        control._timer.cancel()\n        delattr(control, \"_timer\")\n        new_state = self.get_value()\n        if self.sbox.setting._value != new_state:\n            _write_async(self.sbox.setting, new_state, self.sbox)\n\n\n_allowables_icons = {True: \"changes-allow\", False: \"changes-prevent\", settings.SENSITIVITY_IGNORE: \"dialog-error\"}\n_allowables_tooltips = {\n    True: _(\"Changes allowed\"),\n    False: _(\"No changes allowed\"),\n    settings.SENSITIVITY_IGNORE: _(\"Ignore this setting\"),\n}\n_next_allowable = {True: False, False: settings.SENSITIVITY_IGNORE, settings.SENSITIVITY_IGNORE: True}\n_icons_allowables = {v: k for k, v in _allowables_icons.items()}\n\n\n# clicking on the lock icon changes from changeable to unchangeable to ignore\ndef _change_click(button, sbox):\n    icon = button.get_children()[0]\n    icon_name, _ = icon.get_icon_name()\n    allowed = _icons_allowables.get(icon_name, True)\n    new_allowed = _next_allowable[allowed]\n    sbox._control.set_sensitive(new_allowed is True)\n    _change_icon(new_allowed, icon)\n    if sbox.setting._device.persister:  # remember the new setting sensitivity\n        sbox.setting._device.persister.set_sensitivity(sbox.setting.name, new_allowed)\n    if allowed == settings.SENSITIVITY_IGNORE:  # update setting if it was being ignored\n        setting = next((s for s in sbox.setting._device.settings if s.name == sbox.setting.name), None)\n        if setting:\n            persisted = sbox.setting._device.persister.get(setting.name) if sbox.setting._device.persister else None\n            if setting.persist and persisted is not None:\n                _write_async(setting, persisted, sbox)\n            else:\n                _read_async(setting, True, sbox, bool(sbox.setting._device.online), sbox._control.get_sensitive())\n    return True\n\n\ndef _change_icon(allowed, icon):\n    if allowed in _allowables_icons:\n        icon._allowed = allowed\n        icon.set_from_icon_name(_allowables_icons[allowed], Gtk.IconSize.LARGE_TOOLBAR)\n        icon.set_tooltip_text(_allowables_tooltips[allowed])\n\n\ndef _create_sbox(s, _device):\n    if not s.display:\n        return\n    sbox = Gtk.HBox(homogeneous=False, spacing=6)\n    sbox.setting = s\n    sbox.kind = s.kind\n    if s.description:\n        sbox.set_tooltip_text(s.description)\n    lbl = Gtk.Label(label=s.label)\n    label = Gtk.EventBox()\n    label.add(lbl)\n    spinner = Gtk.Spinner()\n    spinner.set_tooltip_text(_(\"Working\") + \"...\")\n    sbox._spinner = spinner\n    failed = Gtk.Image.new_from_icon_name(\"dialog-warning\", Gtk.IconSize.SMALL_TOOLBAR)\n    failed.set_tooltip_text(_(\"Read/write operation failed.\"))\n    sbox._failed = failed\n    change_icon = Gtk.Image.new_from_icon_name(\"changes-prevent\", Gtk.IconSize.LARGE_TOOLBAR)\n    sbox._change_icon = change_icon\n    _change_icon(False, change_icon)\n    change = Gtk.Button()\n    change.set_relief(Gtk.ReliefStyle.NONE)\n    change.add(change_icon)\n    change.set_sensitive(True)\n    change.connect(GtkSignal.CLICKED.value, _change_click, sbox)\n\n    if s.kind == settings.Kind.TOGGLE:\n        control = ToggleControl(sbox)\n    elif s.kind == settings.Kind.RANGE:\n        control = SliderControl(sbox)\n    elif s.kind == settings.Kind.CHOICE:\n        control = _create_choice_control(sbox)\n    elif s.kind == settings.Kind.MAP_CHOICE:\n        control = MapChoiceControl(sbox)\n    elif s.kind == settings.Kind.MULTIPLE_TOGGLE:\n        control = MultipleToggleControl(sbox, change)\n    elif s.kind == settings.Kind.MULTIPLE_RANGE:\n        control = MultipleRangeControl(sbox, change)\n    elif s.kind == settings.Kind.PACKED_RANGE:\n        control = PackedRangeControl(sbox, change)\n    elif s.kind == settings.Kind.HETERO:\n        control = HeteroKeyControl(sbox, change)\n    else:\n        logger.warning(\"setting %s display not implemented\", s.label)\n        return None\n\n    control.set_sensitive(False)  # the first read will enable it\n    control.layout(sbox, label, change, spinner, failed)\n    sbox._control = control\n    sbox.show_all()\n    spinner.start()  # the first read will stop it\n    failed.set_visible(False)\n    return sbox\n\n\ndef _update_setting_item(sbox, value, is_online=True, sensitive=True, null_okay=False):\n    sbox._spinner.stop()\n    sensitive = sbox._change_icon._allowed if sensitive is None else sensitive\n    if value is None and not null_okay:\n        sbox._control.set_sensitive(sensitive is True)\n        _change_icon(sensitive, sbox._change_icon)\n        sbox._failed.set_visible(is_online)\n        return\n    sbox._failed.set_visible(False)\n    sbox._control.set_sensitive(False)\n    try:  # a call was producing a TypeError so guard against that\n        sbox._control.set_value(value)\n    except TypeError as e:\n        logger.warning(\"%s: error setting control value (%s): %s\", sbox.setting.name, sbox.setting._device, repr(e))\n    sbox._control.set_sensitive(sensitive is True)\n    _change_icon(sensitive, sbox._change_icon)\n\n\ndef _disable_listbox_highlight_bg(lb):\n    colour = Gdk.RGBA()\n    colour.parse(\"rgba(0,0,0,0)\")\n    for child in lb.get_children():\n        child.override_background_color(Gtk.StateFlags.PRELIGHT, colour)\n\n\n# config panel\n_box = None\n_items = {}\n\n\ndef create():\n    global _box\n    assert _box is None\n    _box = Gtk.VBox(homogeneous=False, spacing=4)\n    _box._last_device = None\n\n    config_scroll = Gtk.ScrolledWindow()\n    config_scroll.add(_box)\n    config_scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)\n    config_scroll.set_shadow_type(Gtk.ShadowType.NONE)  # was IN\n    config_scroll.set_size_request(0, 350)  # ask for enough vertical space for about eight settings\n\n    return config_scroll\n\n\ndef update(device, is_online=None):\n    assert _box is not None\n    assert device\n    device_id = (device.receiver.path if device.receiver else device.path, device.number)\n    if is_online is None:\n        is_online = bool(device.online)\n\n    # if the device changed since last update, clear the box first\n    if device_id != _box._last_device:\n        _box.set_visible(False)\n        _box._last_device = device_id\n\n    # hide controls belonging to other devices\n    for k, sbox in _items.items():\n        sbox = _items[k]\n        sbox.set_visible(k[0:2] == device_id)\n\n    for s in device.settings:\n        k = (device_id[0], device_id[1], s.name)\n        if k in _items:\n            sbox = _items[k]\n        else:\n            sbox = _create_sbox(s, device)\n            if sbox is None:\n                continue\n            _items[k] = sbox\n            _box.pack_start(sbox, False, False, 0)\n        sensitive = device.persister.get_sensitivity(s.name) if device.persister else True\n        _read_async(s, False, sbox, is_online, sensitive)\n\n    _box.set_visible(True)\n\n\ndef clean(device):\n    \"\"\"Remove the controls for a given device serial.\n    Needed after the device has been unpaired.\n    \"\"\"\n    assert _box is not None\n    device_id = (device.receiver.path if device.receiver else device.path, device.number)\n    for k in list(_items.keys()):\n        if k[0:2] == device_id:\n            _box.remove(_items[k])\n            del _items[k]\n\n\ndef destroy():\n    global _box\n    _box = None\n    _items.clear()\n\n\ndef change_setting(device, setting, values):\n    \"\"\"External interface to change a setting and have the GUI show the change\"\"\"\n    assert device == setting._device\n    GLib.idle_add(_change_setting, device, setting, values, priority=99)\n\n\ndef _change_setting(device, setting, values):\n    device_path = device.receiver.path if device.receiver else device.path\n    if (device_path, device.number, setting.name) in _items:\n        sbox = _items[(device_path, device.number, setting.name)]\n    else:\n        sbox = None\n    _write_async(setting, values[-1], sbox, None, key=values[0] if len(values) > 1 else None)\n\n\ndef record_setting(device, setting, values):\n    \"\"\"External interface to have the GUI show a change to a setting. Doesn't write to the device\"\"\"\n    GLib.idle_add(_record_setting, device, setting, values, priority=99)\n\n\ndef _record_setting(device, setting_class, values):\n    logger.debug(\"on %s changing setting %s to %s\", device, setting_class.name, values)\n    setting = next((s for s in device.settings if s.name == setting_class.name), None)\n    if setting is None:\n        logger.debug(\n            \"No setting for %s found on %s when trying to record a change made elsewhere\",\n            setting_class.name,\n            device,\n        )\n    if setting:\n        assert device == setting._device\n        if len(values) > 1:\n            setting.update_key_value(values[0], values[-1])\n            value = {values[0]: values[-1]}\n        else:\n            setting.update(values[-1])\n            value = values[-1]\n        device_path = device.receiver.path if device.receiver else device.path\n        if (device_path, device.number, setting.name) in _items:\n            sbox = _items[(device_path, device.number, setting.name)]\n            if sbox:\n                _update_setting_item(sbox, value, sensitive=None)\n"
  },
  {
    "path": "lib/solaar/ui/desktop_notifications.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nimport importlib\n\n# Optional desktop notifications.\nimport logging\n\nfrom solaar import NAME\nfrom solaar.i18n import _\n\nfrom . import icons\n\nlogger = logging.getLogger(__name__)\n\n\ndef notifications_available():\n    \"\"\"Checks if notification service is available.\"\"\"\n    notifications_supported = False\n    try:\n        import gi\n\n        gi.require_version(\"Notify\", \"0.7\")\n\n        importlib.util.find_spec(\"gi.repository.GLib\")\n        importlib.util.find_spec(\"gi.repository.Notify\")\n\n        notifications_supported = True\n    except ValueError as e:\n        logger.warning(f\"Notification service is not available: {e}\")\n    return notifications_supported\n\n\navailable = notifications_available()\n\nif available:\n    from gi.repository import GLib\n    from gi.repository import Notify\n\n    # cache references to shown notifications here, so if another status comes\n    # while its notification is still visible we don't create another one\n    _notifications = {}\n\n    def init():\n        \"\"\"Initialize desktop notifications.\"\"\"\n        global available\n        if available:\n            if not Notify.is_initted():\n                logger.info(\"starting desktop notifications\")\n                try:\n                    return Notify.init(NAME.lower())\n                except Exception:\n                    logger.exception(\"initializing desktop notifications\")\n                    available = False\n        return available and Notify.is_initted()\n\n    def uninit():\n        \"\"\"Stop desktop notifications.\"\"\"\n        if available and Notify.is_initted():\n            logger.info(\"stopping desktop notifications\")\n            _notifications.clear()\n            Notify.uninit()\n\n    def alert(reason, icon=None):\n        assert reason\n\n        if available and Notify.is_initted():\n            n = _notifications.get(NAME.lower())\n            if n is None:\n                n = _notifications[NAME.lower()] = Notify.Notification()\n\n            # we need to use the filename here because the notifications daemon\n            # is an external application that does not know about our icon sets\n            icon_file = icons.icon_file(NAME.lower()) if icon is None else icons.icon_file(icon)\n\n            n.update(NAME.lower(), reason, icon_file)\n            n.set_urgency(Notify.Urgency.NORMAL)\n            n.set_hint(\"desktop-entry\", GLib.Variant(\"s\", NAME.lower()))\n\n            try:\n                n.show()\n            except Exception:\n                logger.exception(\"showing %s\", n)\n\n    def show(dev, reason=None, icon=None, progress=None):\n        \"\"\"Show a notification with title and text.\n        Optionally displays the `progress` integer value\n        in [0, 100] as a progress bar.\"\"\"\n        if available and Notify.is_initted():\n            summary = dev.name\n\n            # if a notification with same name is already visible, reuse it to avoid spamming\n            n = _notifications.get(summary)\n            if n is None:\n                n = _notifications[summary] = Notify.Notification()\n\n            if reason:\n                message = reason\n            else:\n                message = _(\"unspecified reason\")\n\n            # we need to use the filename here because the notifications daemon\n            # is an external application that does not know about our icon sets\n            icon_file = icons.device_icon_file(dev.name, dev.kind) if icon is None else icons.icon_file(icon)\n\n            n.update(summary, message, icon_file)\n            n.set_urgency(Notify.Urgency.NORMAL)\n            n.set_hint(\"desktop-entry\", GLib.Variant(\"s\", NAME.lower()))\n            if progress:\n                n.set_hint(\"value\", GLib.Variant(\"i\", progress))\n\n            try:\n                return n.show()\n            except Exception:\n                logger.exception(f\"showing {n}\")\n\nelse:\n\n    def init():\n        return False\n\n    def uninit():\n        return None\n\n    # toggle = lambda action: False\n    def alert(reason):\n        return None\n\n    def show(dev, reason=None):\n        return None\n"
  },
  {
    "path": "lib/solaar/ui/diversion_rules.py",
    "content": "## Copyright (C) Solaar Contributors\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom __future__ import annotations\n\nimport dataclasses\nimport logging\nimport string\nimport threading\n\nfrom collections import defaultdict\nfrom copy import copy\nfrom dataclasses import dataclass\nfrom dataclasses import field\nfrom enum import Enum\nfrom shlex import quote as shlex_quote\nfrom typing import Any\nfrom typing import Callable\nfrom typing import Dict\nfrom typing import Optional\n\nfrom gi.repository import Gdk\nfrom gi.repository import GObject\nfrom gi.repository import Gtk\nfrom logitech_receiver import diversion\nfrom logitech_receiver.common import NamedInt\nfrom logitech_receiver.common import NamedInts\nfrom logitech_receiver.common import UnsortedNamedInts\nfrom logitech_receiver.settings import Kind\nfrom logitech_receiver.settings import Setting\nfrom logitech_receiver.settings_templates import SETTINGS\n\nfrom solaar.i18n import _\nfrom solaar.ui import rule_actions\nfrom solaar.ui import rule_conditions\nfrom solaar.ui.rule_base import RuleComponentUI\nfrom solaar.ui.rule_base import norm\nfrom solaar.ui.rule_conditions import ConditionUI\n\nlogger = logging.getLogger(__name__)\n\n_diversion_dialog = None\n_rule_component_clipboard = None\n\n\nclass GtkSignal(Enum):\n    ACTIVATE = \"activate\"\n    BUTTON_RELEASE_EVENT = \"button-release-event\"\n    CHANGED = \"changed\"\n    CLICKED = \"clicked\"\n    DELETE_EVENT = \"delete-event\"\n    KEY_PRESS_EVENT = \"key-press-event\"\n    NOTIFY_ACTIVE = \"notify::active\"\n    TOGGLED = \"toggled\"\n    VALUE_CHANGED = \"value_changed\"\n\n\ndef create_all_settings(all_settings: list[Setting]) -> dict[str, list[Setting]]:\n    settings = {}\n    for s in sorted(all_settings, key=lambda setting: setting.label):\n        if s.name not in settings:\n            settings[s.name] = [s]\n        else:\n            prev_setting = settings[s.name][0]\n            prev_kind = prev_setting.validator_class.kind\n            if prev_kind != s.validator_class.kind:\n                logger.warning(\n                    \"ignoring setting {} - same name of {}, but different kind ({} != {})\".format(\n                        s.__name__, prev_setting.__name__, prev_kind, s.validator_class.kind\n                    )\n                )\n                continue\n            settings[s.name].append(s)\n    return settings\n\n\nALL_SETTINGS = create_all_settings(SETTINGS)\n\n\nclass RuleComponentWrapper(GObject.GObject):\n    def __init__(self, component, level=0, editable=False):\n        self.component = component\n        self.level = level\n        self.editable = editable\n        GObject.GObject.__init__(self)\n\n    def display_left(self):\n        if isinstance(self.component, diversion.Rule):\n            if self.level == 0:\n                return _(\"Built-in rules\") if not self.editable else _(\"User-defined rules\")\n            if self.level == 1:\n                return \"  \" + _(\"Rule\")\n            return \"  \" + _(\"Sub-rule\")\n        if self.component is None:\n            return _(\"[empty]\")\n        return \"  \" + self.__component_ui().left_label(self.component)\n\n    def display_right(self):\n        if self.component is None:\n            return \"\"\n        return self.__component_ui().right_label(self.component)\n\n    def display_icon(self):\n        if self.component is None:\n            return \"\"\n        if isinstance(self.component, diversion.Rule) and self.level == 0:\n            return \"emblem-system\" if not self.editable else \"avatar-default\"\n        return self.__component_ui().icon_name()\n\n    def __component_ui(self):\n        return COMPONENT_UI.get(type(self.component), UnsupportedRuleComponentUI)\n\n\ndef _create_close_dialog(window: Gtk.Window) -> Gtk.MessageDialog:\n    \"\"\"Creates rule editor close dialog, when unsaved changes are present.\"\"\"\n    dialog = Gtk.MessageDialog(\n        window,\n        type=Gtk.MessageType.QUESTION,\n        title=_(\"Make changes permanent?\"),\n        flags=Gtk.DialogFlags.MODAL,\n    )\n    dialog.set_default_size(400, 100)\n    dialog.add_buttons(\n        _(\"Yes\"),\n        Gtk.ResponseType.YES,\n        _(\"No\"),\n        Gtk.ResponseType.NO,\n        _(\"Cancel\"),\n        Gtk.ResponseType.CANCEL,\n    )\n    dialog.set_markup(_(\"If you choose No, changes will be lost when Solaar is closed.\"))\n    return dialog\n\n\ndef _create_selected_rule_edit_panel() -> Gtk.Grid:\n    \"\"\"Creates the edit Condition/Actions panel for a rule.\n\n    Shows the UI for the selected rule component.\n    \"\"\"\n    grid = Gtk.Grid()\n    grid.set_margin_start(10)\n    grid.set_margin_end(10)\n    grid.set_row_spacing(10)\n    grid.set_column_spacing(10)\n    grid.set_halign(Gtk.Align.CENTER)\n    grid.set_valign(Gtk.Align.CENTER)\n    grid.set_size_request(0, 120)\n    return grid\n\n\ndef _populate_model(\n    model: Gtk.TreeStore,\n    it: Gtk.TreeIter,\n    rule_component: Any,\n    level: int = 0,\n    pos: int = -1,\n    editable: Optional[bool] = None,\n):\n    if isinstance(rule_component, list):\n        for c in rule_component:\n            _populate_model(model, it, c, level=level, pos=pos, editable=editable)\n            if pos >= 0:\n                pos += 1\n        return\n    if editable is None:\n        editable = model[it][0].editable if it is not None else False\n        if isinstance(rule_component, diversion.Rule):\n            editable = editable or (rule_component.source is not None)\n    wrapped = RuleComponentWrapper(rule_component, level, editable=editable)\n    piter = model.insert(it, pos, (wrapped,))\n    if isinstance(rule_component, (diversion.Rule, diversion.And, diversion.Or, diversion.Later)):\n        for c in rule_component.components:\n            ed = editable or (isinstance(c, diversion.Rule) and c.source is not None)\n            _populate_model(model, piter, c, level + 1, editable=ed)\n        if len(rule_component.components) == 0:\n            _populate_model(model, piter, None, level + 1, editable=editable)\n    elif isinstance(rule_component, diversion.Not):\n        _populate_model(model, piter, rule_component.component, level + 1, editable=editable)\n\n\n@dataclasses.dataclass\nclass AllowedActions:\n    c: Any\n    copy: bool\n    delete: bool\n    flatten: bool\n    insert: bool\n    insert_only_rule: bool\n    insert_root: bool\n    wrap: bool\n\n\ndef allowed_actions(m: Gtk.TreeStore, it: Gtk.TreeIter) -> AllowedActions:\n    row = m[it]\n    wrapped = row[0]\n    c = wrapped.component\n    parent_it = m.iter_parent(it)\n    parent_c = m[parent_it][0].component if wrapped.level > 0 else None\n\n    can_wrap = wrapped.editable and wrapped.component is not None and wrapped.level >= 2\n    can_delete = wrapped.editable and not isinstance(parent_c, diversion.Not) and c is not None and wrapped.level >= 1\n    can_insert = wrapped.editable and not isinstance(parent_c, diversion.Not) and wrapped.level >= 2\n    can_insert_only_rule = wrapped.editable and wrapped.level == 1\n    can_flatten = (\n        wrapped.editable\n        and not isinstance(parent_c, diversion.Not)\n        and isinstance(c, (diversion.Rule, diversion.And, diversion.Or))\n        and wrapped.level >= 2\n        and len(c.components)\n    )\n    can_copy = wrapped.level >= 1\n    can_insert_root = wrapped.editable and wrapped.level == 0\n    return AllowedActions(\n        c,\n        can_copy,\n        can_delete,\n        can_flatten,\n        can_insert,\n        can_insert_only_rule,\n        can_insert_root,\n        can_wrap,\n    )\n\n\nclass ActionMenu:\n    def __init__(\n        self,\n        window: Gtk.Window,\n        tree_view: Gtk.TreeView,\n        populate_model_func: Callable,\n        on_update: Callable,\n    ):\n        self.window = window\n        self.tree_view = tree_view\n        self._populate_model_func = populate_model_func\n        self._on_update = on_update\n\n    def create_menu_event_button_released(self, v, e):\n        if e.button == Gdk.BUTTON_SECONDARY:  # right click\n            menu = Gtk.Menu()\n            m, it = v.get_selection().get_selected()\n            enabled_actions = allowed_actions(m, it)\n            for item in self.get_insert_menus(m, it, enabled_actions):\n                menu.append(item)\n            if enabled_actions.flatten:\n                menu.append(self._menu_flatten(m, it))\n            if enabled_actions.wrap:\n                menu.append(self._menu_wrap(m, it))\n                menu.append(self._menu_negate(m, it))\n            if menu.get_children():\n                menu.append(Gtk.SeparatorMenuItem(visible=True))\n            if enabled_actions.delete:\n                menu.append(self._menu_cut(m, it))\n            if enabled_actions.copy and enabled_actions.c is not None:\n                menu.append(self._menu_copy(m, it))\n            if enabled_actions.insert and _rule_component_clipboard is not None:\n                p = self._menu_paste(m, it)\n                menu.append(p)\n                if enabled_actions.c is None:  # just a placeholder\n                    p.set_label(_(\"Paste here\"))\n                else:\n                    p.set_label(_(\"Paste above\"))\n                    p2 = self._menu_paste(m, it, below=True)\n                    p2.set_label(_(\"Paste below\"))\n                    menu.append(p2)\n            elif enabled_actions.insert_only_rule and isinstance(_rule_component_clipboard, diversion.Rule):\n                p = self._menu_paste(m, it)\n                menu.append(p)\n                if enabled_actions.c is None:\n                    p.set_label(_(\"Paste rule here\"))\n                else:\n                    p.set_label(_(\"Paste rule above\"))\n                    p2 = self._menu_paste(m, it, below=True)\n                    p2.set_label(_(\"Paste rule below\"))\n                    menu.append(p2)\n            elif enabled_actions.insert_root and isinstance(_rule_component_clipboard, diversion.Rule):\n                p = self._menu_paste(m, m.iter_nth_child(it, 0))\n                p.set_label(_(\"Paste rule\"))\n                menu.append(p)\n            if menu.get_children() and enabled_actions.delete:\n                menu.append(Gtk.SeparatorMenuItem(visible=True))\n            if enabled_actions.delete:\n                menu.append(self._menu_delete(m, it))\n            if menu.get_children():\n                menu.popup_at_pointer(e)\n\n    def get_insert_menus(self, m, it, enabled_actions: AllowedActions):\n        items = []\n        if enabled_actions.insert:\n            ins = self._menu_insert(m, it)\n            items.append(ins)\n            if enabled_actions.c is None:  # just a placeholder\n                ins.set_label(_(\"Insert here\"))\n            else:\n                ins.set_label(_(\"Insert above\"))\n                ins2 = self._menu_insert(m, it, below=True)\n                ins2.set_label(_(\"Insert below\"))\n                items.append(ins2)\n        elif enabled_actions.insert_only_rule:\n            ins = self._menu_create_rule(m, it)\n            items.append(ins)\n            if enabled_actions.c is None:\n                ins.set_label(_(\"Insert new rule here\"))\n            else:\n                ins.set_label(_(\"Insert new rule above\"))\n                ins2 = self._menu_create_rule(m, it, below=True)\n                ins2.set_label(_(\"Insert new rule below\"))\n                items.append(ins2)\n        elif enabled_actions.insert_root:\n            ins = self._menu_create_rule(m, m.iter_nth_child(it, 0))\n            items.append(ins)\n        return items\n\n    def menu_do_flatten(self, _mitem, m, it):\n        wrapped = m[it][0]\n        c = wrapped.component\n        parent_it = m.iter_parent(it)\n        parent_c = m[parent_it][0].component\n        idx = parent_c.components.index(c)\n        if isinstance(c, diversion.Not):\n            parent_c.components = [*parent_c.components[:idx], c.component, *parent_c.components[idx + 1 :]]\n            children = [next(m[it].iterchildren())[0].component]\n        else:\n            parent_c.components = [*parent_c.components[:idx], *c.components, *parent_c.components[idx + 1 :]]\n            children = [child[0].component for child in m[it].iterchildren()]\n        m.remove(it)\n        self._populate_model_func(m, parent_it, children, level=wrapped.level, pos=idx)\n        new_iter = m.iter_nth_child(parent_it, idx)\n        self.tree_view.expand_row(m.get_path(parent_it), True)\n        self.tree_view.get_selection().select_iter(new_iter)\n        self._on_update()\n\n    def _menu_flatten(self, m, it):\n        menu_flatten = Gtk.MenuItem(_(\"Flatten\"))\n        menu_flatten.connect(GtkSignal.ACTIVATE.value, self.menu_do_flatten, m, it)\n        menu_flatten.show()\n        return menu_flatten\n\n    def _menu_do_insert(self, _mitem, m, it, new_c, below=False):\n        wrapped = m[it][0]\n        c = wrapped.component\n        parent_it = m.iter_parent(it)\n        parent_c = m[parent_it][0].component\n        if len(parent_c.components) == 0:  # we had only a placeholder\n            idx = 0\n        else:\n            idx = parent_c.components.index(c)\n        if isinstance(new_c, diversion.Rule) and wrapped.level == 1:\n            new_c.source = diversion._file_path  # new rules will be saved to the YAML file\n        idx += int(below)\n        parent_c.components.insert(idx, new_c)\n        self._populate_model_func(m, parent_it, new_c, level=wrapped.level, pos=idx)\n        self._on_update()\n        if len(parent_c.components) == 1:\n            m.remove(it)  # remove placeholder in the end\n        new_iter = m.iter_nth_child(parent_it, idx)\n        self.tree_view.get_selection().select_iter(new_iter)\n        if isinstance(new_c, (diversion.Rule, diversion.And, diversion.Or, diversion.Not)):\n            self.tree_view.expand_row(m.get_path(new_iter), True)\n\n    def _menu_do_insert_new(self, _mitem, m, it, cls, initial_value, below=False):\n        new_c = cls(initial_value, warn=False)\n        return self._menu_do_insert(_mitem, m, it, new_c, below=below)\n\n    def _menu_insert(self, m, it, below=False):\n        elements = [\n            _(\"Insert\"),\n            [\n                (_(\"Sub-rule\"), diversion.Rule, []),\n                (_(\"Or\"), diversion.Or, []),\n                (_(\"And\"), diversion.And, []),\n                [\n                    _(\"Condition\"),\n                    [\n                        (_(\"Feature\"), diversion.Feature, rule_conditions.FeatureUI.FEATURES_WITH_DIVERSION[0]),\n                        (_(\"Report\"), diversion.Report, 0),\n                        (_(\"Process\"), diversion.Process, \"\"),\n                        (_(\"Mouse process\"), diversion.MouseProcess, \"\"),\n                        (_(\"Modifiers\"), diversion.Modifiers, []),\n                        (_(\"Key\"), diversion.Key, \"\"),\n                        (_(\"KeyIsDown\"), diversion.KeyIsDown, \"\"),\n                        (_(\"Active\"), diversion.Active, \"\"),\n                        (_(\"Device\"), diversion.Device, \"\"),\n                        (_(\"Host\"), diversion.Host, \"\"),\n                        (_(\"Setting\"), diversion.Setting, [None, \"\", None]),\n                        (_(\"Test\"), diversion.Test, next(iter(diversion.TESTS))),\n                        (_(\"Test bytes\"), diversion.TestBytes, [0, 1, 0]),\n                        (_(\"Mouse Gesture\"), diversion.MouseGesture, \"\"),\n                    ],\n                ],\n                [\n                    _(\"Action\"),\n                    [\n                        (_(\"Key press\"), diversion.KeyPress, \"space\"),\n                        (_(\"Mouse scroll\"), diversion.MouseScroll, [0, 0]),\n                        (_(\"Mouse click\"), diversion.MouseClick, [\"left\", 1]),\n                        (_(\"Set\"), diversion.Set, [None, \"\", None]),\n                        (_(\"Execute\"), diversion.Execute, [\"\"]),\n                        (_(\"Later\"), diversion.Later, [1]),\n                    ],\n                ],\n            ],\n        ]\n\n        def build(spec):\n            if isinstance(spec, list):  # has sub-menu\n                label, children = spec\n                item = Gtk.MenuItem(label)\n                submenu = Gtk.Menu()\n                item.set_submenu(submenu)\n                for child in children:\n                    submenu.append(build(child))\n                return item\n            elif isinstance(spec, tuple):  # has click action\n                label, feature, *args = spec\n                item = Gtk.MenuItem(label)\n                args = [a.copy() if isinstance(a, list) else a for a in args]\n                item.connect(GtkSignal.ACTIVATE.value, self._menu_do_insert_new, m, it, feature, *args, below)\n                return item\n            else:\n                return None\n\n        menu_insert = build(elements)\n        menu_insert.show_all()\n        return menu_insert\n\n    def _menu_create_rule(self, m, it, below=False) -> Gtk.MenuItem:\n        menu_create_rule = Gtk.MenuItem(_(\"Insert new rule\"))\n        menu_create_rule.connect(GtkSignal.ACTIVATE.value, self._menu_do_insert_new, m, it, diversion.Rule, [], below)\n        menu_create_rule.show()\n        return menu_create_rule\n\n    def menu_do_delete(self, _mitem, m, it):\n        wrapped = m[it][0]\n        c = wrapped.component\n        parent_it = m.iter_parent(it)\n        parent_c = m[parent_it][0].component\n        idx = parent_c.components.index(c)\n        parent_c.components.pop(idx)\n        if len(parent_c.components) == 0:  # placeholder\n            self._populate_model_func(m, parent_it, None, level=wrapped.level)\n        m.remove(it)\n        self.tree_view.get_selection().select_iter(m.iter_nth_child(parent_it, max(0, min(idx, len(parent_c.components) - 1))))\n        self._on_update()\n        return c\n\n    def _menu_delete(self, m, it) -> Gtk.MenuItem:\n        menu_delete = Gtk.MenuItem(_(\"Delete\"))\n        menu_delete.connect(GtkSignal.ACTIVATE.value, self.menu_do_delete, m, it)\n        menu_delete.show()\n        return menu_delete\n\n    def menu_do_negate(self, _mitem, m, it):\n        wrapped = m[it][0]\n        c = wrapped.component\n        parent_it = m.iter_parent(it)\n        parent_c = m[parent_it][0].component\n        if isinstance(c, diversion.Not):  # avoid double negation\n            self.menu_do_flatten(_mitem, m, it)\n            self.tree_view.expand_row(m.get_path(parent_it), True)\n        elif isinstance(parent_c, diversion.Not):  # avoid double negation\n            self.menu_do_flatten(_mitem, m, parent_it)\n        else:\n            idx = parent_c.components.index(c)\n            self._menu_do_insert_new(_mitem, m, it, diversion.Not, c, below=True)\n            self.menu_do_delete(_mitem, m, m.iter_nth_child(parent_it, idx))\n        self._on_update()\n\n    def _menu_negate(self, m, it) -> Gtk.MenuItem:\n        menu_negate = Gtk.MenuItem(_(\"Negate\"))\n        menu_negate.connect(GtkSignal.ACTIVATE.value, self.menu_do_negate, m, it)\n        menu_negate.show()\n        return menu_negate\n\n    def menu_do_wrap(self, _mitem, m, it, cls):\n        wrapped = m[it][0]\n        c = wrapped.component\n        parent_it = m.iter_parent(it)\n        parent_c = m[parent_it][0].component\n        if isinstance(parent_c, diversion.Not):\n            new_c = cls([c], warn=False)\n            parent_c.component = new_c\n            m.remove(it)\n            self._populate_model_func(m, parent_it, new_c, level=wrapped.level, pos=0)\n            self.tree_view.expand_row(m.get_path(parent_it), True)\n            self.tree_view.get_selection().select_iter(m.iter_nth_child(parent_it, 0))\n        else:\n            idx = parent_c.components.index(c)\n            self._menu_do_insert_new(_mitem, m, it, cls, [c], below=True)\n            self.menu_do_delete(_mitem, m, m.iter_nth_child(parent_it, idx))\n        self._on_update()\n\n    def _menu_wrap(self, m, it) -> Gtk.MenuItem:\n        menu_wrap = Gtk.MenuItem(_(\"Wrap with\"))\n        submenu_wrap = Gtk.Menu()\n        menu_sub_rule = Gtk.MenuItem(_(\"Sub-rule\"))\n        menu_and = Gtk.MenuItem(_(\"And\"))\n        menu_or = Gtk.MenuItem(_(\"Or\"))\n        menu_sub_rule.connect(GtkSignal.ACTIVATE.value, self.menu_do_wrap, m, it, diversion.Rule)\n        menu_and.connect(GtkSignal.ACTIVATE.value, self.menu_do_wrap, m, it, diversion.And)\n        menu_or.connect(GtkSignal.ACTIVATE.value, self.menu_do_wrap, m, it, diversion.Or)\n        submenu_wrap.append(menu_sub_rule)\n        submenu_wrap.append(menu_and)\n        submenu_wrap.append(menu_or)\n        menu_wrap.set_submenu(submenu_wrap)\n        menu_wrap.show_all()\n        return menu_wrap\n\n    def menu_do_copy(self, _mitem: Gtk.MenuItem, m: Gtk.TreeStore, it: Gtk.TreeIter):\n        global _rule_component_clipboard\n\n        wrapped = m[it][0]\n        c = wrapped.component\n        _rule_component_clipboard = diversion.RuleComponent().compile(c.data())\n\n    def menu_do_cut(self, _mitem, m, it):\n        global _rule_component_clipboard\n\n        c = self.menu_do_delete(_mitem, m, it)\n        self._on_update()\n        _rule_component_clipboard = c\n\n    def _menu_cut(self, m, it):\n        menu_cut = Gtk.MenuItem(_(\"Cut\"))\n        menu_cut.connect(GtkSignal.ACTIVATE.value, self.menu_do_cut, m, it)\n        menu_cut.show()\n        return menu_cut\n\n    def menu_do_paste(self, _mitem, m, it, below=False):\n        global _rule_component_clipboard\n\n        c = _rule_component_clipboard\n        _rule_component_clipboard = None\n        if c:\n            _rule_component_clipboard = diversion.RuleComponent().compile(c.data())\n            self._menu_do_insert(_mitem, m, it, new_c=c, below=below)\n            self._on_update()\n\n    def _menu_paste(self, m, it, below=False):\n        menu_paste = Gtk.MenuItem(_(\"Paste\"))\n        menu_paste.connect(GtkSignal.ACTIVATE.value, self.menu_do_paste, m, it, below)\n        menu_paste.show()\n        return menu_paste\n\n    def _menu_copy(self, m, it):\n        menu_copy = Gtk.MenuItem(_(\"Copy\"))\n        menu_copy.connect(GtkSignal.ACTIVATE.value, self.menu_do_copy, m, it)\n        menu_copy.show()\n        return menu_copy\n\n\nclass DiversionDialog:\n    def __init__(self, action_menu):\n        window = Gtk.Window()\n        window.set_title(_(\"Solaar Rule Editor\"))\n        window.connect(GtkSignal.DELETE_EVENT.value, self._closing)\n        vbox = Gtk.VBox()\n\n        self.top_panel, self.view = self._create_top_panel()\n        for col in self._create_view_columns():\n            self.view.append_column(col)\n        vbox.pack_start(self.top_panel, True, True, 0)\n\n        self._action_menu = action_menu(\n            window,\n            self.view,\n            populate_model_func=_populate_model,\n            on_update=self.on_update,\n        )\n\n        self.dirty = False  # if dirty, there are pending changes to be saved\n\n        self.type_ui = {}\n        self.update_ui = {}\n        self.selected_rule_edit_panel = _create_selected_rule_edit_panel()\n        self.ui = defaultdict(lambda: UnsupportedRuleComponentUI(self.selected_rule_edit_panel))\n        self.ui.update(\n            {  # one instance per type\n                rc_class: rc_ui_class(self.selected_rule_edit_panel, on_update=self.on_update)\n                for rc_class, rc_ui_class in COMPONENT_UI.items()\n            }\n        )\n        vbox.pack_start(self.selected_rule_edit_panel, False, False, 10)\n\n        self.model = self._create_model()\n        self.view.set_model(self.model)\n        self.view.expand_all()\n\n        window.add(vbox)\n\n        geometry = Gdk.Geometry()\n        geometry.min_width = 600  # don't ask for so much space\n        geometry.min_height = 400\n        window.set_geometry_hints(None, geometry, Gdk.WindowHints.MIN_SIZE)\n        window.set_position(Gtk.WindowPosition.CENTER)\n\n        window.show_all()\n\n        window.connect(GtkSignal.DELETE_EVENT.value, lambda w, e: w.hide_on_delete() or True)\n\n        style = window.get_style_context()\n        style.add_class(\"solaar\")\n        self.window = window\n        self._editing_component = None\n\n    def _closing(self, window: Gtk.Window, e: Gdk.Event):\n        if self.dirty:\n            dialog = _create_close_dialog(window)\n            response = dialog.run()\n            dialog.destroy()\n            if response == Gtk.ResponseType.NO:\n                window.hide()\n            elif response == Gtk.ResponseType.YES:\n                self._save_yaml_file()\n                window.hide()\n            else:\n                # don't close\n                return True\n        else:\n            window.hide()\n\n    def _reload_yaml_file(self):\n        self.discard_btn.set_sensitive(False)\n        self.save_btn.set_sensitive(False)\n        self.dirty = False\n        for c in self.selected_rule_edit_panel.get_children():\n            self.selected_rule_edit_panel.remove(c)\n        diversion.load_config_rule_file()\n        self.model = self._create_model()\n        self.view.set_model(self.model)\n        self.view.expand_all()\n\n    def _save_yaml_file(self):\n        if diversion._save_config_rule_file():\n            self.dirty = False\n            self.save_btn.set_sensitive(False)\n            self.discard_btn.set_sensitive(False)\n\n    def _create_top_panel(self):\n        sw = Gtk.ScrolledWindow()\n        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.ALWAYS)\n        view = Gtk.TreeView()\n        view.set_headers_visible(False)\n        view.set_enable_tree_lines(True)\n        view.set_reorderable(False)\n\n        view.connect(GtkSignal.KEY_PRESS_EVENT.value, self._event_key_pressed)\n        view.connect(GtkSignal.BUTTON_RELEASE_EVENT.value, self._event_button_released)\n        view.get_selection().connect(GtkSignal.CHANGED.value, self._selection_changed)\n        sw.add(view)\n        sw.set_size_request(0, 300)  # don't ask for so much height\n\n        button_box = Gtk.HBox(spacing=20)\n        self.save_btn = Gtk.Button.new_from_icon_name(\"document-save\", Gtk.IconSize.BUTTON)\n        self.save_btn.set_label(_(\"Save changes\"))\n        self.save_btn.set_always_show_image(True)\n        self.save_btn.set_sensitive(False)\n        self.save_btn.set_valign(Gtk.Align.CENTER)\n        self.discard_btn = Gtk.Button.new_from_icon_name(\"document-revert\", Gtk.IconSize.BUTTON)\n        self.discard_btn.set_label(_(\"Discard changes\"))\n        self.discard_btn.set_always_show_image(True)\n        self.discard_btn.set_sensitive(False)\n        self.discard_btn.set_valign(Gtk.Align.CENTER)\n        self.save_btn.connect(GtkSignal.CLICKED.value, lambda *_args: self._save_yaml_file())\n        self.discard_btn.connect(GtkSignal.CLICKED.value, lambda *_args: self._reload_yaml_file())\n        button_box.pack_start(self.save_btn, False, False, 0)\n        button_box.pack_start(self.discard_btn, False, False, 0)\n        button_box.set_halign(Gtk.Align.CENTER)\n        button_box.set_valign(Gtk.Align.CENTER)\n        button_box.set_size_request(0, 50)\n\n        vbox = Gtk.VBox()\n        vbox.pack_start(button_box, False, False, 0)\n        vbox.pack_start(sw, True, True, 0)\n\n        return vbox, view\n\n    def _create_model(self):\n        model = Gtk.TreeStore(RuleComponentWrapper)\n        if len(diversion.rules.components) == 1:\n            # only built-in rules - add empty user rule list\n            diversion.rules.components.insert(0, diversion.Rule([], source=diversion._file_path))\n        _populate_model(model, None, diversion.rules.components)\n        return model\n\n    def _create_view_columns(self):\n        cell_icon = Gtk.CellRendererPixbuf()\n        cell1 = Gtk.CellRendererText()\n        col1 = Gtk.TreeViewColumn(\"Type\")\n        col1.pack_start(cell_icon, False)\n        col1.pack_start(cell1, True)\n        col1.set_cell_data_func(cell1, lambda _c, c, m, it, _d: c.set_property(\"text\", m.get_value(it, 0).display_left()))\n        cell2 = Gtk.CellRendererText()\n        col2 = Gtk.TreeViewColumn(\"Summary\")\n        col2.pack_start(cell2, True)\n        col2.set_cell_data_func(cell2, lambda _c, c, m, it, _d: c.set_property(\"text\", m.get_value(it, 0).display_right()))\n        col2.set_cell_data_func(\n            cell_icon, lambda _c, c, m, it, _d: c.set_property(\"icon-name\", m.get_value(it, 0).display_icon())\n        )\n        return col1, col2\n\n    def on_update(self):\n        self.view.queue_draw()\n        self.dirty = True\n        self.save_btn.set_sensitive(True)\n        self.discard_btn.set_sensitive(True)\n\n    def _selection_changed(self, selection):\n        self.selected_rule_edit_panel.set_sensitive(False)\n        (model, it) = selection.get_selected()\n        if it is None:\n            return\n        wrapped = model[it][0]\n        component = wrapped.component\n        self._editing_component = component\n        self.ui[type(component)].show(component, wrapped.editable)\n        self.selected_rule_edit_panel.set_sensitive(wrapped.editable)\n\n    def _event_key_pressed(self, v, e):\n        \"\"\"\n        Shortcuts:\n            Ctrl + I                insert component\n            Ctrl + Delete           delete row\n            &                       wrap with And\n            |                       wrap with Or\n            Shift + R               wrap with Rule\n            !                       negate\n            Ctrl + X                cut\n            Ctrl + C                copy\n            Ctrl + V                paste below (or here if empty)\n            Ctrl + Shift + V        paste above\n            *                       flatten\n            Ctrl + S                save changes\n        \"\"\"\n        state = e.state & (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK)\n        m, it = v.get_selection().get_selected()\n        enabled_actions = allowed_actions(m, it)\n        if state & Gdk.ModifierType.CONTROL_MASK:\n            if enabled_actions.delete and e.keyval in [Gdk.KEY_x, Gdk.KEY_X]:\n                self._action_menu.menu_do_cut(None, m, it)\n            elif enabled_actions.copy and e.keyval in [Gdk.KEY_c, Gdk.KEY_C] and enabled_actions.c is not None:\n                self._action_menu.menu_do_copy(None, m, it)\n            elif enabled_actions.insert and _rule_component_clipboard is not None and e.keyval in [Gdk.KEY_v, Gdk.KEY_V]:\n                self._action_menu.menu_do_paste(\n                    None, m, it, below=enabled_actions.c is not None and not (state & Gdk.ModifierType.SHIFT_MASK)\n                )\n            elif (\n                enabled_actions.insert_only_rule\n                and isinstance(_rule_component_clipboard, diversion.Rule)\n                and e.keyval in [Gdk.KEY_v, Gdk.KEY_V]\n            ):\n                self._action_menu.menu_do_paste(\n                    None, m, it, below=enabled_actions.c is not None and not (state & Gdk.ModifierType.SHIFT_MASK)\n                )\n            elif (\n                enabled_actions.insert_root\n                and isinstance(_rule_component_clipboard, diversion.Rule)\n                and e.keyval in [Gdk.KEY_v, Gdk.KEY_V]\n            ):\n                self._action_menu.menu_do_paste(None, m, m.iter_nth_child(it, 0))\n            elif enabled_actions.delete and e.keyval in [Gdk.KEY_KP_Delete, Gdk.KEY_Delete]:\n                self._action_menu.menu_do_delete(None, m, it)\n            elif (enabled_actions.insert or enabled_actions.insert_only_rule or enabled_actions.insert_root) and e.keyval in [\n                Gdk.KEY_i,\n                Gdk.KEY_I,\n            ]:\n                menu = Gtk.Menu()\n                for item in self._action_menu.get_insert_menus(\n                    m,\n                    it,\n                    enabled_actions,\n                ):\n                    menu.append(item)\n                menu.show_all()\n                rect = self.view.get_cell_area(m.get_path(it), self.view.get_column(1))\n                menu.popup_at_rect(self.window.get_window(), rect, Gdk.Gravity.WEST, Gdk.Gravity.CENTER, e)\n            elif self.dirty and e.keyval in [Gdk.KEY_s, Gdk.KEY_S]:\n                self._save_yaml_file()\n        else:\n            if enabled_actions.wrap:\n                if e.keyval == Gdk.KEY_exclam:\n                    self._action_menu.menu_do_negate(None, m, it)\n                elif e.keyval == Gdk.KEY_ampersand:\n                    self._action_menu.menu_do_wrap(None, m, it, diversion.And)\n                elif e.keyval == Gdk.KEY_bar:\n                    self._action_menu.menu_do_wrap(None, m, it, diversion.Or)\n                elif e.keyval in [Gdk.KEY_r, Gdk.KEY_R] and (state & Gdk.ModifierType.SHIFT_MASK):\n                    self._action_menu.menu_do_wrap(None, m, it, diversion.Rule)\n            if enabled_actions.flatten and e.keyval in [Gdk.KEY_asterisk, Gdk.KEY_KP_Multiply]:\n                self._action_menu.menu_do_flatten(None, m, it)\n\n    def _event_button_released(self, v, e):\n        self._action_menu.create_menu_event_button_released(v, e)\n\n    def update_devices(self):\n        for rc in self.ui.values():\n            rc.update_devices()\n        self.view.queue_draw()\n\n\nclass CompletionEntry(Gtk.Entry):\n    def __init__(self, values, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        CompletionEntry.add_completion_to_entry(self, values)\n\n    @classmethod\n    def add_completion_to_entry(cls, entry, values):\n        completion = entry.get_completion()\n        if not completion:\n            liststore = Gtk.ListStore(str)\n            completion = Gtk.EntryCompletion()\n            completion.set_model(liststore)\n            completion.set_match_func(lambda completion, key, it: norm(key) in norm(completion.get_model()[it][0]))\n            completion.set_text_column(0)\n            entry.set_completion(completion)\n        else:\n            liststore = completion.get_model()\n            liststore.clear()\n        for v in sorted(set(values), key=str.casefold):\n            liststore.append((v,))\n\n\nclass SmartComboBox(Gtk.ComboBox):\n    \"\"\"A custom ComboBox with some extra features.\n\n    The constructor requires a collection of allowed values.\n    Each element must be a single value or a non-empty tuple containing:\n    - a value (any hashable object)\n    - a name (optional; str(value) is used if not provided)\n    - alternative names.\n    Example: (some_object, 'object name', 'other name', 'also accept this').\n\n    It is assumed that the same string cannot be the name or an\n    alternative name of more than one value.\n\n    The widget displays the names, but the alternative names are also suggested and accepted as input.\n\n    If `has_entry` is `True`, then the user can insert arbitrary text (possibly with auto-complete if `completion` is True).\n    Otherwise, only a drop-down list is shown, with an extra blank item in the beginning (correspondent to `None`).\n    The display text of the blank item is defined by the parameter `blank`.\n\n    If `case_insensitive` is `True`, then upper-case and lower-case letters are treated as equal.\n\n    If `replace_with_default_name`, then the field text is immediately replaced with the default name of a value\n    as soon as the user finishes typing any accepted name.\n\n    \"\"\"\n\n    def __init__(\n        self, all_values, blank=\"\", completion=False, case_insensitive=False, replace_with_default_name=False, **kwargs\n    ):\n        super().__init__(**kwargs)\n        self._name_to_idx = {}\n        self._value_to_idx = {}\n        self._hidden_idx = set()\n        self._all_values = []\n        self._blank = blank\n        self._model = None\n        self._completion = completion\n        self._case_insensitive = case_insensitive\n        self._norm = lambda s: None if s is None else s if not case_insensitive else str(s).upper()\n        self._replace_with_default_name = replace_with_default_name\n\n        def replace_with(value):\n            if self.get_has_entry() and self._replace_with_default_name and value is not None:\n                item = self._all_values[self._value_to_idx[value]]\n                name = item[1] if len(item) > 1 else str(item[0])\n                if name != self.get_child().get_text():\n                    self.get_child().set_text(name)\n\n        self.connect(GtkSignal.CHANGED.value, lambda *a: replace_with(self.get_value(invalid_as_str=False)))\n\n        self.set_id_column(0)\n        if self.get_has_entry():\n            self.set_entry_text_column(1)\n        else:\n            renderer = Gtk.CellRendererText()\n            self.pack_start(renderer, True)\n            self.add_attribute(renderer, \"text\", 1)\n        self.set_all_values(all_values)\n        self.set_active_id(\"\")\n\n    @classmethod\n    def new_model(cls):\n        model = Gtk.ListStore(str, str, bool)\n        # (index: int converted to str, name: str, visible: bool)\n        filtered_model = model.filter_new()\n        filtered_model.set_visible_column(2)\n        return model, filtered_model\n\n    def set_all_values(self, all_values, visible_fn=(lambda value: True)):\n        old_value = self.get_value()\n        self._name_to_idx = {}\n        self._value_to_idx = {}\n        self._hidden_idx = set()\n        self._all_values = [v if isinstance(v, tuple) else (v,) for v in all_values]\n\n        model, filtered_model = SmartComboBox.new_model()\n        # creating a new model seems to be necessary to avoid firing 'changed' event once per inserted item\n        model.append((\"\", self._blank, True))\n        self._model = model\n\n        to_complete = [self._blank]\n        for idx, item in enumerate(self._all_values):\n            value, *names = item if isinstance(item, tuple) else (item,)\n            visible = visible_fn(value)\n            self._include(model, idx, value, visible, *names)\n            if visible:\n                to_complete += names if names else [str(value).strip()]\n        self.set_model(filtered_model)\n        if self.get_has_entry() and self._completion:\n            CompletionEntry.add_completion_to_entry(self.get_child(), to_complete)\n        if self._find_idx(old_value) is not None:\n            self.set_value(old_value)\n        else:\n            self.set_value(self._blank)\n        self.queue_draw()\n\n    def _include(self, model, idx, value, visible, *names):\n        name = str(names[0]) if names else str(value).strip()\n        self._name_to_idx[self._norm(name)] = idx\n        if isinstance(value, NamedInt):\n            self._name_to_idx[self._norm(str(name))] = idx\n        model.append((str(idx), name, visible))\n        for alt in names[1:]:\n            self._name_to_idx[self._norm(str(alt).strip())] = idx\n        self._value_to_idx[value] = idx\n        if self._case_insensitive and isinstance(value, str):\n            self._name_to_idx[self._norm(value)] = idx\n\n    def get_value(self, invalid_as_str=True, accept_hidden=True):\n        \"\"\"Return the selected value or the typed text.\n\n        If the typed or selected text corresponds to one of the allowed values (or their names and\n        alternative names), then the value is returned.\n\n        Otherwise, the raw text is returned as string if the widget has an entry and `invalid_as_str`\n        is `True`; if the widget has no entry or `invalid_as_str` is `False`, then `None` is returned.\n\n        \"\"\"\n        tree_iter = self.get_active_iter()\n        if tree_iter is not None:\n            t = self.get_model()[tree_iter]\n            number = t[0]\n            return self._all_values[int(number)][0] if number != \"\" and (accept_hidden or t[2]) else None\n        elif self.get_has_entry():\n            text = self.get_child().get_text().strip()\n            if text == self._blank:\n                return None\n            idx = self._find_idx(text)\n            if idx is None:\n                return text if invalid_as_str else None\n            item = self._all_values[idx]\n            return item[0]\n        return None\n\n    def _find_idx(self, search):\n        if search == self._blank:\n            return None\n        try:\n            return self._value_to_idx[search]\n        except KeyError:\n            pass\n        try:\n            return self._name_to_idx[self._norm(search)]\n        except KeyError:\n            pass\n        return None\n\n    def set_value(self, value, accept_invalid=True):\n        \"\"\"Set a specific value.\n\n        Raw values, their names and alternative names are accepted.\n        Base-10 representations of int values as strings are also accepted.\n        The actual value is used in all cases.\n\n        If `value` is invalid, then the entry text is set to the provided value\n        if the widget has an entry and `accept_invalid` is True, or else the blank value is set.\n        \"\"\"\n        idx = self._find_idx(value) if value != self._blank else \"\"\n        if idx is not None:\n            self.set_active_id(str(idx))\n        else:\n            if self.get_has_entry() and accept_invalid:\n                self.get_child().set_text(str(value or \"\") if value != \"\" else self._blank)\n            else:\n                self.set_active_id(\"\")\n\n    def show_only(self, only, include_new=False):\n        \"\"\"Hide items not present in `only`.\n\n        Only values are accepted (not their names and alternative names).\n\n        If `include_new` is True, then the values in `only` not currently present\n        are included with their string representation as names; otherwise,\n        they are ignored.\n\n        If `only` is new, then the visibility status is reset and all values are shown.\n        \"\"\"\n        values = self._all_values[:]\n        if include_new and only is not None:\n            values += [v for v in only if v not in self._value_to_idx]\n        self.set_all_values(values, (lambda v: only is None or (v in only)))\n\n\n@dataclass\nclass DeviceInfo:\n    serial: str = \"\"\n    unitId: str = \"\"\n    codename: str = \"\"\n    settings: Dict[str, Setting] = field(default_factory=dict)\n\n    def __post_init__(self):\n        if self.serial is None or self.serial == \"?\":\n            self.serial = \"\"\n        if self.unitId is None or self.unitId == \"?\":\n            self.unitId = \"\"\n\n    @property\n    def id(self) -> str:\n        return self.serial or self.unitId or \"\"\n\n    @property\n    def identifiers(self) -> list[str]:\n        return [id for id in (self.serial, self.unitId) if id]\n\n    @property\n    def display_name(self) -> str:\n        return f\"{self.codename} ({self.id})\"\n\n    def matches(self, search: str) -> bool:\n        return search and search in (self.serial, self.unitId, self.display_name)\n\n    def update(self, device: DeviceInfo) -> None:\n        for k in (\"serial\", \"unitId\", \"codename\", \"settings\"):\n            if not getattr(self, k, None):\n                v = getattr(device, k, None)\n                if v and v != \"?\":\n                    setattr(self, k, copy(v) if k != \"settings\" else {s.name: s for s in v})\n\n\nclass DeviceInfoFactory:\n    @classmethod\n    def create_device_info(cls, device) -> DeviceInfo:\n        d = DeviceInfo()\n        d.update(device)\n        return d\n\n\nclass AllDevicesInfo:\n    def __init__(self):\n        self._devices: list[DeviceInfo] = []\n        self._lock = threading.Lock()\n\n    def __iter__(self):\n        return iter(self._devices)\n\n    def __getitem__(self, search):\n        if not search:\n            return search\n        assert isinstance(search, str)\n        # linear search - ok because it is always a small list\n        return next((d for d in self._devices if d.matches(search)), None)\n\n    def refresh(self):\n        updated = False\n\n        def dev_in_row(_store, _treepath, row):\n            nonlocal updated\n            device = _dev_model.get_value(row, 7)\n            if device and device.kind and (device.serial and device.serial != \"?\" or device.unitId and device.unitId != \"?\"):\n                existing = self[device.serial] or self[device.unitId]\n                if not existing:\n                    updated = True\n                    device_info = DeviceInfoFactory.create_device_info(device)\n                    self._devices.append(device_info)\n                elif not existing.settings and device.settings:\n                    updated = True\n                    existing.update(device)\n\n        with self._lock:\n            _dev_model.foreach(dev_in_row)\n        return updated\n\n\nclass UnsupportedRuleComponentUI(RuleComponentUI):\n    CLASS = None\n\n    def create_widgets(self):\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True)\n        self.label.set_text(_(\"This editor does not support the selected rule component yet.\") if self.component else \"\")\n        self.widgets[self.label] = (0, 0, 1, 1)\n\n    def collect_value(self):\n        return self.component.components[:]  # not editable on the bottom panel\n\n    @classmethod\n    def right_label(cls, component):\n        return str(component)\n\n\nclass RuleUI(RuleComponentUI):\n    CLASS = diversion.Rule\n\n    def create_widgets(self):\n        self.widgets = {}\n\n    def collect_value(self):\n        return self.component.components[:]  # not editable on the bottom panel\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Rule\")\n\n    @classmethod\n    def icon_name(cls):\n        return \"format-justify-fill\"\n\n\nclass AndUI(RuleComponentUI):\n    CLASS = diversion.And\n\n    def create_widgets(self):\n        self.widgets = {}\n\n    def collect_value(self):\n        return self.component.components[:]  # not editable on the bottom panel\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"And\")\n\n\nclass OrUI(RuleComponentUI):\n    CLASS = diversion.Or\n\n    def create_widgets(self):\n        self.widgets = {}\n\n    def collect_value(self):\n        return self.component.components[:]  # not editable on the bottom panel\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Or\")\n\n\nclass LaterUI(RuleComponentUI):\n    CLASS = diversion.Later\n    MIN_VALUE = 0.01\n    MAX_VALUE = 100\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True)\n        self.label.set_text(_(\"Number of seconds to delay.  Delay between 0 and 1 is done with higher precision.\"))\n        self.widgets[self.label] = (0, 0, 1, 1)\n        self.field = Gtk.SpinButton.new_with_range(self.MIN_VALUE, self.MAX_VALUE, 1)\n        self.field.set_digits(3)\n        self.field.set_halign(Gtk.Align.CENTER)\n        self.field.set_valign(Gtk.Align.CENTER)\n        self.field.set_hexpand(True)\n        self.field.connect(GtkSignal.VALUE_CHANGED.value, self._on_update)\n        self.widgets[self.field] = (0, 1, 1, 1)\n\n    def show(self, component, editable):\n        super().show(component, editable)\n        with self.ignore_changes():\n            self.field.set_value(component.delay)\n\n    def collect_value(self):\n        return [float(int((self.field.get_value() + 0.0001) * 1000)) / 1000] + self.component.components\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Later\")\n\n    @classmethod\n    def right_label(cls, component):\n        return str(component.delay)\n\n\nclass NotUI(RuleComponentUI):\n    CLASS = diversion.Not\n\n    def create_widgets(self):\n        self.widgets = {}\n\n    def collect_value(self):\n        return self.component.component  # not editable on the bottom panel\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Not\")\n\n\nclass ActionUI(RuleComponentUI):\n    CLASS = diversion.Action\n\n    @classmethod\n    def icon_name(cls):\n        return \"go-next\"\n\n\ndef _from_named_ints(v, all_values):\n    \"\"\"Obtain a NamedInt from NamedInts given its numeric value (as int) or name.\"\"\"\n    if all_values and (v in all_values):\n        return all_values[v]\n    return v\n\n\nclass SetValueControlKinds(Enum):\n    TOGGLE = \"toggle\"\n    RANGE = \"range\"\n    RANGE_WITH_KEY = \"range_with_key\"\n    CHOICE = \"choice\"\n\n\nclass SetValueControl(Gtk.HBox):\n    def __init__(self, on_change, *args, accept_toggle=True, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.on_change = on_change\n        self.toggle_widget = SmartComboBox(\n            [\n                *([(\"Toggle\", _(\"Toggle\"), \"~\")] if accept_toggle else []),\n                (True, _(\"True\"), \"True\", \"yes\", \"on\", \"t\", \"y\"),\n                (False, _(\"False\"), \"False\", \"no\", \"off\", \"f\", \"n\"),\n            ],\n            case_insensitive=True,\n        )\n        self.toggle_widget.connect(GtkSignal.CHANGED.value, self._changed)\n        self.range_widget = Gtk.SpinButton.new_with_range(0, 0xFFFF, 1)\n        self.range_widget.connect(GtkSignal.VALUE_CHANGED.value, self._changed)\n        self.choice_widget = SmartComboBox(\n            [], completion=True, has_entry=True, case_insensitive=True, replace_with_default_name=True\n        )\n        self.choice_widget.connect(GtkSignal.CHANGED.value, self._changed)\n        self.sub_key_widget = SmartComboBox([])\n        self.sub_key_widget.connect(GtkSignal.CHANGED.value, self._changed)\n        self.unsupported_label = Gtk.Label(label=_(\"Unsupported setting\"))\n        self.pack_start(self.sub_key_widget, False, False, 0)\n        self.sub_key_widget.set_hexpand(False)\n        self.sub_key_widget.set_size_request(120, 0)\n        self.sub_key_widget.hide()\n        for w in [self.toggle_widget, self.range_widget, self.choice_widget, self.unsupported_label]:\n            self.pack_end(w, True, True, 0)\n            w.hide()\n        self.unsupp_value = None\n        self.current_kind: Optional[SetValueControlKinds] = None\n        self.sub_key_range_items = None\n\n    def _changed(self, widget, *args):\n        if widget.get_visible():\n            value = self.get_value()\n            if self.current_kind == SetValueControlKinds.CHOICE:\n                value = widget.get_value()\n                icon = \"dialog-warning\" if widget._allowed_values and (value not in widget._allowed_values) else \"\"\n                widget.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n            elif self.current_kind == SetValueControlKinds.RANGE_WITH_KEY and widget == self.sub_key_widget:\n                key = self.sub_key_widget.get_value()\n                selected_item = (\n                    next((item for item in self.sub_key_range_items if key == item.id), None)\n                    if self.sub_key_range_items\n                    else None\n                )\n                (minimum, maximum) = (selected_item.minimum, selected_item.maximum) if selected_item else (0, 0xFFFF)\n                self.range_widget.set_range(minimum, maximum)\n            self.on_change(value)\n\n    def _hide_all(self):\n        for w in self.get_children():\n            w.hide()\n\n    def get_value(self):\n        if self.current_kind == SetValueControlKinds.TOGGLE:\n            return self.toggle_widget.get_value()\n        if self.current_kind == SetValueControlKinds.RANGE:\n            return int(self.range_widget.get_value())\n        if self.current_kind == SetValueControlKinds.RANGE_WITH_KEY:\n            return {self.sub_key_widget.get_value(): int(self.range_widget.get_value())}\n        if self.current_kind == SetValueControlKinds.CHOICE:\n            return self.choice_widget.get_value()\n        return self.unsupp_value\n\n    def set_value(self, value):\n        if self.current_kind == SetValueControlKinds.TOGGLE:\n            self.toggle_widget.set_value(value if value is not None else \"\")\n        elif self.current_kind == SetValueControlKinds.RANGE:\n            minimum, maximum = self.range_widget.get_range()\n            try:\n                v = round(float(value))\n            except (ValueError, TypeError):\n                v = minimum\n            self.range_widget.set_value(max(minimum, min(maximum, v)))\n        elif self.current_kind == SetValueControlKinds.RANGE_WITH_KEY:\n            if not (isinstance(value, dict) and len(value) == 1):\n                value = {None: None}\n            key = next(iter(value.keys()))\n            selected_item = (\n                next((item for item in self.sub_key_range_items if key == item.id), None) if self.sub_key_range_items else None\n            )\n            (minimum, maximum) = (selected_item.minimum, selected_item.maximum) if selected_item else (0, 0xFFFF)\n            try:\n                v = round(float(next(iter(value.values()))))\n            except (ValueError, TypeError):\n                v = minimum\n            self.sub_key_widget.set_value(key or \"\")\n            self.range_widget.set_value(max(minimum, min(maximum, v)))\n        elif self.current_kind == SetValueControlKinds.CHOICE:\n            self.choice_widget.set_value(value)\n        else:\n            self.unsupp_value = value\n        if value is None or value == \"\":  # reset all\n            self.range_widget.set_range(0x0000, 0xFFFF)\n            self.range_widget.set_value(0)\n            self.toggle_widget.set_active_id(\"\")\n            self.sub_key_widget.set_value(\"\")\n            self.choice_widget.set_value(\"\")\n\n    def make_toggle(self):\n        self.current_kind = SetValueControlKinds.TOGGLE\n        self._hide_all()\n        self.toggle_widget.show()\n\n    def make_range(self, minimum, maximum):\n        self.current_kind = SetValueControlKinds.RANGE\n        self._hide_all()\n        self.range_widget.set_range(minimum, maximum)\n        self.range_widget.show()\n\n    def make_range_with_key(self, items, labels=None):\n        self.current_kind = SetValueControlKinds.RANGE_WITH_KEY\n        self._hide_all()\n        self.sub_key_range_items = items or None\n        if not labels:\n            labels = {}\n        self.sub_key_widget.set_all_values(\n            map(lambda item: (item.id, labels.get(item.id, [str(item.id)])[0]), items) if items else []\n        )\n        self.sub_key_widget.show()\n        self.range_widget.show()\n\n    def make_choice(self, values, extra=None):\n        # if extra is not in values, it is ignored\n        self.current_kind = SetValueControlKinds.CHOICE\n        self._hide_all()\n        sort_key = int if all((v == extra or str(v).isdigit()) for v in values) else str\n        if extra is not None and extra in values:\n            values = [extra] + sorted((v for v in values if v != extra), key=sort_key)\n        else:\n            values = sorted(values, key=sort_key)\n        self.choice_widget.set_all_values(values)\n        self.choice_widget._allowed_values = values\n        self.choice_widget.show()\n\n    def make_unsupported(self):\n        self.current_kind = None\n        self._hide_all()\n        self.unsupported_label.show()\n\n\nclass _DeviceUI:\n    label_text = \"\"\n\n    def show(self, component, editable):\n        super().show(component, editable)\n        with self.ignore_changes():\n            same = not component.devID\n            device = _all_devices[component.devID]\n            self.device_field.set_value(device.id if device else \"\" if same else component.devID or \"\")\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True)\n        self.label.set_text(self.label_text)\n        self.widgets[self.label] = (0, 0, 5, 1)\n        lbl = Gtk.Label(label=_(\"Device\"), halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True)\n        self.widgets[lbl] = (0, 1, 1, 1)\n        self.device_field = SmartComboBox(\n            [],\n            completion=True,\n            has_entry=True,\n            blank=_(\"Originating device\"),\n            case_insensitive=True,\n            replace_with_default_name=True,\n        )\n        self.device_field.set_value(\"\")\n        self.device_field.set_valign(Gtk.Align.CENTER)\n        self.device_field.set_size_request(400, 0)\n        self.device_field.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.device_field] = (1, 1, 1, 1)\n\n    def update_devices(self):\n        self._update_device_list()\n\n    def _update_device_list(self):\n        with self.ignore_changes():\n            self.device_field.set_all_values([(d.id, d.display_name, *d.identifiers[1:]) for d in _all_devices])\n\n    def collect_value(self):\n        device_str = self.device_field.get_value()\n        same = device_str in [\"\", _(\"Originating device\")]\n        device = None if same else _all_devices[device_str]\n        device_value = device.id if device else None if same else device_str\n        return device_value\n\n    @classmethod\n    def right_label(cls, component):\n        device = _all_devices[component.devID]\n        return device.display_name if device else shlex_quote(component.devID)\n\n\nclass ActiveUI(_DeviceUI, ConditionUI):\n    CLASS = diversion.Active\n    label_text = _(\"Device is active and its settings can be changed.\")\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Active\")\n\n\nclass DeviceUI(_DeviceUI, ConditionUI):\n    CLASS = diversion.Device\n    label_text = _(\"Device that originated the current notification.\")\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Device\")\n\n\nclass HostUI(ConditionUI):\n    CLASS = diversion.Host\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True)\n        self.label.set_text(_(\"Name of host computer.\"))\n        self.widgets[self.label] = (0, 0, 1, 1)\n        self.field = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True)\n        self.field.set_size_request(600, 0)\n        self.field.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.field] = (0, 1, 1, 1)\n\n    def show(self, component, editable):\n        super().show(component, editable)\n        with self.ignore_changes():\n            self.field.set_text(component.host)\n\n    def collect_value(self):\n        return self.field.get_text()\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Host\")\n\n    @classmethod\n    def right_label(cls, component):\n        return str(component.host)\n\n\nclass _SettingWithValueUI:\n    MULTIPLE = [Kind.MULTIPLE_TOGGLE, Kind.MAP_CHOICE, Kind.MULTIPLE_RANGE]\n    ACCEPT_TOGGLE = True\n\n    label_text = \"\"\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True)\n        self.label.set_text(self.label_text)\n        self.widgets[self.label] = (0, 0, 5, 1)\n\n        m = 20\n        lbl = Gtk.Label(label=_(\"Device\"), halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True, margin_top=m)\n        self.widgets[lbl] = (0, 1, 1, 1)\n        self.device_field = SmartComboBox(\n            [],\n            completion=True,\n            has_entry=True,\n            blank=_(\"Originating device\"),\n            case_insensitive=True,\n            replace_with_default_name=True,\n        )\n        self.device_field.set_value(\"\")\n        self.device_field.set_valign(Gtk.Align.CENTER)\n        self.device_field.set_size_request(400, 0)\n        self.device_field.set_margin_top(m)\n        self.device_field.connect(GtkSignal.CHANGED.value, self._changed_device)\n        self.device_field.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.device_field] = (1, 1, 1, 1)\n\n        lbl = Gtk.Label(\n            label=_(\"Setting\"),\n            halign=Gtk.Align.CENTER,\n            valign=Gtk.Align.CENTER,\n            hexpand=True,\n            vexpand=False,\n        )\n        self.widgets[lbl] = (0, 2, 1, 1)\n        self.setting_field = SmartComboBox([(s[0].name, s[0].label) for s in ALL_SETTINGS.values()])\n        self.setting_field.set_valign(Gtk.Align.CENTER)\n        self.setting_field.connect(GtkSignal.CHANGED.value, self._changed_setting)\n        self.setting_field.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.setting_field] = (1, 2, 1, 1)\n\n        self.value_lbl = Gtk.Label(\n            label=_(\"Value\"), halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True, vexpand=False\n        )\n        self.widgets[self.value_lbl] = (2, 2, 1, 1)\n        self.value_field = SetValueControl(self._on_update, accept_toggle=self.ACCEPT_TOGGLE)\n        self.value_field.set_valign(Gtk.Align.CENTER)\n        self.value_field.set_size_request(250, 35)\n        self.widgets[self.value_field] = (3, 2, 1, 1)\n\n        self.key_lbl = Gtk.Label(\n            label=_(\"Item\"), halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True, vexpand=False, margin_top=m\n        )\n        self.key_lbl.hide()\n        self.widgets[self.key_lbl] = (2, 1, 1, 1)\n        self.key_field = SmartComboBox(\n            [], has_entry=True, completion=True, case_insensitive=True, replace_with_default_name=True\n        )\n        self.key_field.set_margin_top(m)\n        self.key_field.hide()\n        self.key_field.set_valign(Gtk.Align.CENTER)\n        self.key_field.connect(GtkSignal.CHANGED.value, self._changed_key)\n        self.key_field.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.key_field] = (3, 1, 1, 1)\n\n    @classmethod\n    def _all_choices(cls, setting):  # choice and map-choice\n        \"\"\"Return a NamedInts instance with the choices for a setting.\n\n        If the argument `setting` is a Setting instance or subclass, then the choices are taken only from it.\n        If instead it is a name, then the function returns the union of the choices for each setting with that name.\n        Only one label per number is kept.\n\n        The function returns a 2-tuple whose first element is a NamedInts instance with the possible choices\n        (including the extra value if it exists) and the second element is the extra value to be pinned to\n        the start of the list (or `None` if there is no extra value).\n        \"\"\"\n        if isinstance(setting, Setting):\n            setting = type(setting)\n        if isinstance(setting, type) and issubclass(setting, Setting):\n            choices = UnsortedNamedInts()\n            universe = getattr(setting, \"choices_universe\", None)\n            if universe:\n                choices |= universe\n            extra = getattr(setting, \"choices_extra\", None)\n            if extra is not None:\n                choices |= NamedInts(**{str(extra): int(extra)})\n            return choices, extra\n        settings = ALL_SETTINGS.get(setting, [])\n        choices = UnsortedNamedInts()\n        extra = None\n        for s in settings:\n            ch, ext = cls._all_choices(s)\n            choices |= ch\n            if ext is not None:\n                extra = ext\n        return choices, extra\n\n    @classmethod\n    def _setting_attributes(cls, setting_name, device=None):\n        if device and setting_name in device.settings:\n            setting = device.settings.get(setting_name, None)\n            settings = [type(setting)] if setting else None\n        else:\n            settings = ALL_SETTINGS.get(setting_name, [None])\n            setting = settings[0]  # if settings have the same name, use the first one to get the basic data\n        val_class = setting.validator_class if setting else None\n        kind = val_class.kind if val_class else None\n        if kind in cls.MULTIPLE:\n            keys = UnsortedNamedInts()\n            for s in settings:\n                universe = getattr(s, \"keys_universe\" if kind == Kind.MAP_CHOICE else \"choices_universe\", None)\n                if universe:\n                    keys |= universe\n            # only one key per number is used\n        else:\n            keys = None\n        return setting, val_class, kind, keys\n\n    def _changed_device(self, *args):\n        device = _all_devices[self.device_field.get_value()]\n        setting_name = self.setting_field.get_value()\n        if not device or not device.settings or setting_name in device.settings:\n            kind = self._setting_attributes(setting_name, device)[2]\n            key = self.key_field.get_value() if kind in self.MULTIPLE else None\n        else:\n            setting_name = kind = key = None\n        with self.ignore_changes():\n            self._update_setting_list(device)\n            self._update_key_list(setting_name, device)\n            self._update_value_list(setting_name, device, key)\n\n    def _changed_setting(self, *args):\n        with self.ignore_changes():\n            device = _all_devices[self.device_field.get_value()]\n            setting_name = self.setting_field.get_value()\n            self._update_key_list(setting_name, device)\n            key = self.key_field.get_value()\n            self._update_value_list(setting_name, device, key)\n\n    def _changed_key(self, *args):\n        with self.ignore_changes():\n            setting_name = self.setting_field.get_value()\n            device = _all_devices[self.device_field.get_value()]\n            key = self.key_field.get_value()\n            self._update_value_list(setting_name, device, key)\n\n    def update_devices(self):\n        self._update_device_list()\n\n    def _update_device_list(self):\n        with self.ignore_changes():\n            self.device_field.set_all_values([(d.id, d.display_name, *d.identifiers[1:]) for d in _all_devices])\n\n    def _update_setting_list(self, device=None):\n        supported_settings = device.settings.keys() if device else {}\n        with self.ignore_changes():\n            self.setting_field.show_only(supported_settings or None)\n\n    def _update_key_list(self, setting_name, device=None):\n        setting, val_class, kind, keys = self._setting_attributes(setting_name, device)\n        multiple = kind in self.MULTIPLE\n        self.key_field.set_visible(multiple)\n        self.key_lbl.set_visible(multiple)\n        if not multiple:\n            return\n        labels = getattr(setting, \"_labels\", {})\n\n        def item(k):\n            lbl = labels.get(k, None)\n            if lbl and isinstance(lbl, tuple) and lbl[0]:\n                label = lbl[0]\n            else:\n                label = str(k)\n            return k, label\n\n        with self.ignore_changes():\n            self.key_field.set_all_values(sorted(map(item, keys), key=lambda k: k[1]))\n            ds = device.settings if device else {}\n            device_setting = ds.get(setting_name, None)\n            supported_keys = None\n            if device_setting:\n                val = device_setting._validator\n                if device_setting.kind == Kind.MULTIPLE_TOGGLE:\n                    supported_keys = val.get_options() or None\n                elif device_setting.kind == Kind.MAP_CHOICE:\n                    choices = val.choices or None\n                    supported_keys = choices.keys() if choices else None\n                elif device_setting.kind == Kind.MULTIPLE_RANGE:\n                    supported_keys = val.keys\n            self.key_field.show_only(supported_keys, include_new=True)\n            self._update_validation()\n\n    def _update_value_list(self, setting_name, device=None, key=None):\n        setting, val_class, kind, keys = self._setting_attributes(setting_name, device)\n        ds = device.settings if device else {}\n        device_setting = ds.get(setting_name, None)\n        if kind in (Kind.TOGGLE, Kind.MULTIPLE_TOGGLE):\n            self.value_field.make_toggle()\n        elif kind in (Kind.CHOICE, Kind.MAP_CHOICE):\n            all_values, extra = self._all_choices(device_setting or setting_name)\n            self.value_field.make_choice(all_values, extra)\n            supported_values = None\n            if device_setting:\n                val = device_setting._validator\n                choices = getattr(val, \"choices\", None) or None\n                if kind == Kind.CHOICE:\n                    supported_values = choices\n                elif kind == Kind.MAP_CHOICE and isinstance(choices, dict):\n                    supported_values = choices.get(key, None) or None\n            self.value_field.choice_widget.show_only(supported_values, include_new=True)\n            self._update_validation()\n        elif kind == Kind.RANGE:\n            self.value_field.make_range(val_class.min_value, val_class.max_value)\n        elif kind == Kind.MULTIPLE_RANGE:\n            self.value_field.make_range_with_key(\n                getattr(setting, \"sub_items_universe\", {}).get(key, {}) if setting else {},\n                getattr(setting, \"_labels_sub\", None) if setting else None,\n            )\n        else:\n            self.value_field.make_unsupported()\n\n    def _on_update(self, *_args):\n        if not self._ignore_changes and self.component:\n            self._update_validation()\n\n    def _update_validation(self):\n        device_str = self.device_field.get_value()\n        device = _all_devices[device_str]\n        if device_str and not device:\n            icon = (\n                \"dialog-question\"\n                if len(device_str) == 8 and all(c in string.hexdigits for c in device_str)\n                else \"dialog-warning\"\n            )\n        else:\n            icon = \"\"\n        self.device_field.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n        setting_name = self.setting_field.get_value()\n        setting, val_class, kind, keys = self._setting_attributes(setting_name, device)\n        multiple = kind in self.MULTIPLE\n        if multiple:\n            key = self.key_field.get_value(invalid_as_str=False, accept_hidden=False)\n            icon = \"dialog-warning\" if key is None else \"\"\n            self.key_field.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n        if kind in (Kind.CHOICE, Kind.MAP_CHOICE):\n            value = self.value_field.choice_widget.get_value(invalid_as_str=False, accept_hidden=False)\n            icon = \"dialog-warning\" if value is None else \"\"\n            self.value_field.choice_widget.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n\n    def show(self, component, editable):\n        a = iter(component.args)\n        with self.ignore_changes():\n            device_str = next(a, None)\n            same = not device_str\n            device = _all_devices[device_str]\n            self.device_field.set_value(device.id if device else \"\" if same else device_str or \"\")\n            setting_name = next(a, \"\")\n            setting, _v, kind, keys = self._setting_attributes(setting_name, device)\n            self.setting_field.set_value(setting.name if setting else \"\")\n            self._changed_setting()\n            key = None\n            if kind in self.MULTIPLE or kind is None and len(self.component.args) > 3:\n                key = _from_named_ints(next(a, \"\"), keys)\n            self.key_field.set_value(key)\n            self.value_field.set_value(next(a, \"\"))\n            self._update_validation()\n\n    def collect_value(self):\n        device_str = self.device_field.get_value()\n        same = device_str in [\"\", _(\"Originating device\")]\n        device = None if same else _all_devices[device_str]\n        device_value = device.id if device else None if same else device_str\n        setting_name = self.setting_field.get_value()\n        setting, val_class, kind, keys = self._setting_attributes(setting_name, device)\n        key_value = []\n        if kind in self.MULTIPLE or kind is None and len(self.component.args) > 3:\n            key = self.key_field.get_value()\n            key = _from_named_ints(key, keys)\n            key_value.append(key)\n        key_value.append(self.value_field.get_value())\n        return [device_value, setting_name, *key_value]\n\n    @classmethod\n    def right_label(cls, component):\n        a = iter(component.args)\n        device_str = next(a, None)\n        device = None if not device_str else _all_devices[device_str]\n        device_disp = _(\"Originating device\") if not device_str else device.display_name if device else shlex_quote(device_str)\n        setting_name = next(a, None)\n        setting, val_class, kind, keys = cls._setting_attributes(setting_name, device)\n        device_setting = (device.settings if device else {}).get(setting_name, None)\n        disp = [setting.label or setting.name if setting else setting_name]\n        key = None\n        if kind in cls.MULTIPLE:\n            key = next(a, None)\n            key = _from_named_ints(key, keys) if keys else key\n            key_label = getattr(setting, \"_labels\", {}).get(key, [None])[0] if setting else None\n            disp.append(key_label or key)\n        value = next(a, None)\n        if setting and (kind in (Kind.CHOICE, Kind.MAP_CHOICE)):\n            all_values = cls._all_choices(setting or setting_name)[0]\n            supported_values = None\n            if device_setting:\n                val = device_setting._validator\n                choices = getattr(val, \"choices\", None) or None\n                if kind == Kind.CHOICE:\n                    supported_values = choices\n                elif kind == Kind.MAP_CHOICE and isinstance(choices, dict):\n                    supported_values = choices.get(key, None) or None\n                if supported_values and isinstance(supported_values, NamedInts):\n                    value = supported_values[value]\n            if not supported_values and all_values and isinstance(all_values, NamedInts):\n                value = all_values[value]\n            disp.append(value)\n        elif kind == Kind.MULTIPLE_RANGE and isinstance(value, dict) and len(value) == 1:\n            k, v = next(iter(value.items()))\n            k = (getattr(setting, \"_labels_sub\", {}).get(k, (None,))[0] if setting else None) or k\n            disp.append(f\"{k}={v}\")\n        elif kind in (Kind.TOGGLE, Kind.MULTIPLE_TOGGLE):\n            disp.append(_(str(value)))\n        else:\n            disp.append(value)\n        return device_disp + \"  \" + \"  \".join(map(lambda s: shlex_quote(str(s)), [*disp, *a]))\n\n\nclass SetUI(_SettingWithValueUI, ActionUI):\n    CLASS = diversion.Set\n    ACCEPT_TOGGLE = True\n\n    label_text = _(\"Change setting on device\")\n\n    def show(self, component, editable):\n        ActionUI.show(self, component, editable)\n        _SettingWithValueUI.show(self, component, editable)\n\n    def _on_update(self, *_args):\n        if not self._ignore_changes and self.component:\n            ActionUI._on_update(self, *_args)\n            _SettingWithValueUI._on_update(self, *_args)\n\n\nclass SettingUI(_SettingWithValueUI, ConditionUI):\n    CLASS = diversion.Setting\n    ACCEPT_TOGGLE = False\n\n    label_text = _(\"Setting on device\")\n\n    def show(self, component, editable):\n        ConditionUI.show(self, component, editable)\n        _SettingWithValueUI.show(self, component, editable)\n\n    def _on_update(self, *_args):\n        if not self._ignore_changes and self.component:\n            ConditionUI._on_update(self, *_args)\n            _SettingWithValueUI._on_update(self, *_args)\n\n\nCOMPONENT_UI: dict[Any, RuleComponentUI] = {\n    diversion.Rule: RuleUI,\n    diversion.Not: NotUI,\n    diversion.Or: OrUI,\n    diversion.And: AndUI,\n    diversion.Later: LaterUI,\n    diversion.Process: rule_conditions.ProcessUI,\n    diversion.MouseProcess: rule_conditions.MouseProcessUI,\n    diversion.Active: ActiveUI,\n    diversion.Device: DeviceUI,\n    diversion.Host: HostUI,\n    diversion.Feature: rule_conditions.FeatureUI,\n    diversion.Report: rule_conditions.ReportUI,\n    diversion.Modifiers: rule_conditions.ModifiersUI,\n    diversion.Key: rule_conditions.KeyUI,\n    diversion.KeyIsDown: rule_conditions.KeyIsDownUI,\n    diversion.Test: rule_conditions.TestUI,\n    diversion.TestBytes: rule_conditions.TestBytesUI,\n    diversion.Setting: SettingUI,\n    diversion.MouseGesture: rule_conditions.MouseGestureUI,\n    diversion.KeyPress: rule_actions.KeyPressUI,\n    diversion.MouseScroll: rule_actions.MouseScrollUI,\n    diversion.MouseClick: rule_actions.MouseClickUI,\n    diversion.Execute: rule_actions.ExecuteUI,\n    diversion.Set: SetUI,\n    # type(None): RuleComponentUI,  # placeholders for empty rule/And/Or\n}\n\n_all_devices = AllDevicesInfo()\n_dev_model = None\n\n\ndef update_devices():\n    global _dev_model\n    global _all_devices\n    global _diversion_dialog\n    if _dev_model and _all_devices.refresh() and _diversion_dialog:\n        _diversion_dialog.update_devices()\n\n\ndef show_window(model: Gtk.TreeStore):\n    GObject.type_register(RuleComponentWrapper)\n    global _diversion_dialog\n    global _dev_model\n    _dev_model = model\n    if _diversion_dialog is None:\n        _diversion_dialog = DiversionDialog(ActionMenu)\n    update_devices()\n    _diversion_dialog.window.present()\n"
  },
  {
    "path": "lib/solaar/ui/icons.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport logging\n\nfrom gi.repository import Gtk\n\nimport solaar.gtk as gtk\n\nlogger = logging.getLogger(__name__)\n\nLARGE_SIZE = Gtk.IconSize.DIALOG  # was 64\nTRAY_INIT = \"solaar-init\"\nTRAY_OKAY = \"solaar\"\nTRAY_ATTENTION = \"solaar-attention\"\n\n_default_theme = None\n\n\ndef _init_icon_paths():\n    global _default_theme\n    if _default_theme:\n        return\n\n    _default_theme = Gtk.IconTheme.get_default()\n    logger.debug(\"icon theme paths: %s\", _default_theme.get_search_path())\n\n    if gtk.battery_icons_style == \"symbolic\":\n        global TRAY_OKAY\n        TRAY_OKAY = TRAY_INIT  # use monochrome tray icon\n        if not _default_theme.has_icon(\"battery-good-symbolic\"):\n            logger.warning(\"failed to detect symbolic icons\")\n            gtk.battery_icons_style = \"regular\"\n    if gtk.battery_icons_style == \"regular\":\n        if not _default_theme.has_icon(\"battery-good\"):\n            logger.warning(\"failed to detect icons\")\n            gtk.battery_icons_style = \"solaar\"\n\n\ndef battery(level=None, charging=False):\n    icon_name = _battery_icon_name(level, charging)\n    if not _default_theme.has_icon(icon_name):\n        logger.warning(\"icon %s not found in current theme\", icon_name)\n        return TRAY_OKAY  # use Solaar icon if battery icon not available\n    logger.debug(\"battery icon for %s:%s = %s\", level, charging, icon_name)\n    return icon_name\n\n\n# return first res where val >= guard\n# _first_res(val,((guard,res),...))\ndef _first_res(val, pairs):\n    return next((res for guard, res in pairs if val >= guard), None)\n\n\ndef _battery_icon_name(level, charging):\n    _init_icon_paths()\n\n    if level is None or level < 0:\n        return \"battery-missing\" + (\"-symbolic\" if gtk.battery_icons_style == \"symbolic\" else \"\")\n\n    level_name = _first_res(level, ((90, \"full\"), (30, \"good\"), (20, \"low\"), (5, \"caution\"), (0, \"empty\")))\n    return \"battery-%s%s%s\" % (\n        level_name,\n        \"-charging\" if charging else \"\",\n        \"-symbolic\" if gtk.battery_icons_style == \"symbolic\" else \"\",\n    )\n\n\ndef lux(level=None):\n    if level is None or level < 0:\n        return \"light_unknown\"\n    return f\"solaar-light_{int(20 * ((level + 50) // 100)):03}\"\n\n\n_ICON_SETS = {}\n\n\ndef device_icon_set(name=\"_\", kind=None):\n    icon_set = _ICON_SETS.get(name)\n    if icon_set is None:\n        # names of possible icons, in reverse desirability\n        icon_set = [\"preferences-desktop-peripherals\"]\n        if kind:\n            if str(kind) == \"numpad\":\n                icon_set += (\"input-keyboard\", \"input-dialpad\")\n            elif str(kind) == \"touchpad\":\n                icon_set += (\"input-mouse\", \"input-tablet\")\n            elif str(kind) == \"trackball\":\n                icon_set += (\"input-mouse\",)\n            elif str(kind) == \"headset\":\n                icon_set += (\"audio-headphones\", \"audio-headset\")\n            icon_set += (f\"input-{str(kind)}\",)\n        # icon_set += (name.replace(' ', '-'),)\n        _ICON_SETS[name] = icon_set\n    return icon_set\n\n\ndef device_icon_file(name, kind=None, size=LARGE_SIZE):\n    icon_name = device_icon_name(name, kind)\n    return _default_theme.lookup_icon(icon_name, size, 0).get_filename() if icon_name is not None else None\n\n\ndef device_icon_name(name, kind=None):\n    _init_icon_paths()\n    icon_set = device_icon_set(name, kind)\n    assert icon_set\n    for n in reversed(icon_set):\n        if _default_theme.has_icon(n):\n            return n\n\n\ndef icon_file(name, size=LARGE_SIZE):\n    _init_icon_paths()\n    # has_icon() somehow returned False while lookup_icon returns non-None.\n    # I guess it happens because share/solaar/icons/ has no hicolor and resolution subdirs\n    theme_icon = _default_theme.lookup_icon(name, size, 0)\n    if theme_icon:\n        file_name = theme_icon.get_filename()\n        return file_name\n    logger.warning(\"icon %s(%d) not found in current theme\", name, size)\n"
  },
  {
    "path": "lib/solaar/ui/pair_window.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport logging\n\nfrom enum import Enum\n\nfrom gi.repository import GLib\nfrom gi.repository import Gtk\nfrom logitech_receiver import hidpp10_constants\n\nfrom solaar.i18n import _\nfrom solaar.i18n import ngettext\n\nfrom . import icons\n\nlogger = logging.getLogger(__name__)\n\n_PAIRING_TIMEOUT = 30  # seconds\n_STATUS_CHECK = 500  # milliseconds\n\n\nclass GtkSignal(Enum):\n    CANCEL = \"cancel\"\n    CLOSE = \"close\"\n\n\ndef create(receiver):\n    receiver.reset_pairing()  # clear out any information on previous pairing\n    title = _(\"%(receiver_name)s: pair new device\") % {\"receiver_name\": receiver.name}\n    if receiver.receiver_kind == \"bolt\":\n        text = _(\"Bolt receivers are only compatible with Bolt devices.\")\n        text += \"\\n\\n\"\n        text += _(\"Press a pairing button or key until the pairing light flashes quickly.\")\n    else:\n        if receiver.receiver_kind == \"unifying\":\n            text = _(\"Unifying receivers are only compatible with Unifying devices.\")\n        else:\n            text = _(\"Other receivers are only compatible with a few devices.\")\n        text += \"\\n\\n\"\n        text += _(\"For most devices, turn on the device you want to pair.\")\n        text += _(\"If the device is already turned on, turn it off and on again.\")\n        text += \"\\n\"\n        text += _(\"The device must not be paired with a nearby powered-on receiver.\")\n        text += \"\\n\"\n        text += _(\n            \"For devices with multiple channels, \"\n            \"press, hold, and release the button for the channel you wish to pair\"\n            \"\\n\"\n            \"or use the channel switch button to select a channel \"\n            \"and then press, hold, and release the channel switch button.\"\n        )\n        text += \"\\n\"\n        text += _(\"The channel indicator light should be blinking rapidly.\")\n    if receiver.remaining_pairings() and receiver.remaining_pairings() >= 0:\n        text += (\n            ngettext(\n                \"\\n\\nThis receiver has %d pairing remaining.\",\n                \"\\n\\nThis receiver has %d pairings remaining.\",\n                receiver.remaining_pairings(),\n            )\n            % receiver.remaining_pairings()\n        )\n        text += _(\"\\nCancelling at this point will not use up a pairing.\")\n    ok = prepare(receiver)\n    assistant = _create_assistant(receiver, ok, _finish, title, text)\n    if ok:\n        GLib.timeout_add(_STATUS_CHECK, check_lock_state, assistant, receiver)\n    return assistant\n\n\ndef prepare(receiver):\n    if receiver.receiver_kind == \"bolt\":\n        if receiver.discover(timeout=_PAIRING_TIMEOUT):\n            return True\n        else:\n            receiver.pairing.error = \"discovery did not start\"\n            return False\n    elif receiver.set_lock(False, timeout=_PAIRING_TIMEOUT):\n        return True\n    else:\n        receiver.pairing.error = \"the pairing lock did not open\"\n        return False\n\n\ndef check_lock_state(assistant, receiver, count=2):\n    if not assistant.is_drawable():\n        logger.debug(\"assistant %s destroyed, bailing out\", assistant)\n        return False\n    return _check_lock_state(assistant, receiver, count)\n\n\ndef _check_lock_state(assistant, receiver, count):\n    if receiver.pairing.error:\n        _pairing_failed(assistant, receiver, receiver.pairing.error)\n        return False\n    elif receiver.pairing.new_device:\n        receiver.remaining_pairings(False)  # Update remaining pairings\n        _pairing_succeeded(assistant, receiver, receiver.pairing.new_device)\n        return False\n    elif not receiver.pairing.lock_open and not receiver.pairing.discovering:\n        if count > 0:\n            # the actual device notification may arrive later so have a little patience\n            GLib.timeout_add(_STATUS_CHECK, check_lock_state, assistant, receiver, count - 1)\n        else:\n            _pairing_failed(assistant, receiver, \"failed to open pairing lock\")\n        return False\n    elif receiver.pairing.lock_open and receiver.pairing.device_passkey:\n        _show_passcode(assistant, receiver, receiver.pairing.device_passkey)\n        return True\n    elif receiver.pairing.discovering and receiver.pairing.device_address and receiver.pairing.device_name:\n        add = receiver.pairing.device_address\n        ent = 20 if receiver.pairing.device_kind == hidpp10_constants.DEVICE_KIND.keyboard else 10\n        if receiver.pair_device(address=add, authentication=receiver.pairing.device_authentication, entropy=ent):\n            return True\n        else:\n            _pairing_failed(assistant, receiver, \"failed to open pairing lock\")\n            return False\n    return True\n\n\ndef _pairing_failed(assistant, receiver, error):\n    assistant.remove_page(0)  # needed to reset the window size\n    logger.debug(\"%s fail: %s\", receiver, error)\n    _create_failure_page(assistant, error)\n\n\ndef _pairing_succeeded(assistant, receiver, device):\n    assistant.remove_page(0)  # needed to reset the window size\n    logger.debug(\"%s success: %s\", receiver, device)\n    _create_success_page(assistant, device)\n\n\ndef _finish(assistant, receiver):\n    logger.debug(\"finish %s\", assistant)\n    assistant.destroy()\n    receiver.pairing.new_device = None\n    if receiver.pairing.lock_open:\n        if receiver.receiver_kind == \"bolt\":\n            receiver.pair_device(\"cancel\")\n        else:\n            receiver.set_lock()\n    if receiver.pairing.discovering:\n        receiver.discover(True)\n    if not receiver.pairing.lock_open and not receiver.pairing.discovering:\n        receiver.pairing.error = None\n\n\ndef _show_passcode(assistant, receiver, passkey):\n    logger.debug(\"%s show passkey: %s\", receiver, passkey)\n    name = receiver.pairing.device_name\n    authentication = receiver.pairing.device_authentication\n    intro_text = _(\"%(receiver_name)s: pair new device\") % {\"receiver_name\": receiver.name}\n    page_text = _(\"Enter passcode on %(name)s.\") % {\"name\": name}\n    page_text += \"\\n\"\n    if authentication & 0x01:\n        page_text += _(\"Type %(passcode)s and then press the enter key.\") % {\n            \"passcode\": receiver.pairing.device_passkey,\n        }\n    else:\n        passcode = \", \".join(\n            [_(\"right\") if bit == \"1\" else _(\"left\") for bit in f\"{int(receiver.pairing.device_passkey):010b}\"]\n        )\n        page_text += _(\"Press %(code)s\\nand then press left and right buttons simultaneously.\") % {\"code\": passcode}\n    page = _create_page(\n        assistant,\n        Gtk.AssistantPageType.PROGRESS,\n        intro_text,\n        \"preferences-desktop-peripherals\",\n        page_text,\n    )\n    assistant.set_page_complete(page, True)\n    assistant.next_page()\n\n\ndef _create_assistant(receiver, ok, finish, title, text):\n    assistant = Gtk.Assistant()\n    assistant.set_title(title)\n    assistant.set_icon_name(\"list-add\")\n    assistant.set_size_request(400, 240)\n    assistant.set_resizable(False)\n    assistant.set_role(\"pair-device\")\n    if ok:\n        page_intro = _create_page(\n            assistant,\n            Gtk.AssistantPageType.PROGRESS,\n            title,\n            \"preferences-desktop-peripherals\",\n            text,\n        )\n        spinner = Gtk.Spinner()\n        spinner.set_visible(True)\n        spinner.start()\n        page_intro.pack_end(spinner, True, True, 24)\n        assistant.set_page_complete(page_intro, True)\n    else:\n        page_intro = _create_failure_page(assistant, receiver.pairing.error)\n    assistant.connect(GtkSignal.CANCEL.value, finish, receiver)\n    assistant.connect(GtkSignal.CLOSE.value, finish, receiver)\n    return assistant\n\n\ndef _create_success_page(assistant, device):\n    def _check_encrypted(device, assistant, hbox):\n        if assistant.is_drawable() and device.link_encrypted is False:\n            hbox.pack_start(Gtk.Image.new_from_icon_name(\"security-low\", Gtk.IconSize.MENU), False, False, 0)\n            hbox.pack_start(Gtk.Label(label=_(\"The wireless link is not encrypted\")), False, False, 0)\n            hbox.show_all()\n        return False\n\n    page = _create_page(assistant, Gtk.AssistantPageType.SUMMARY)\n    header = Gtk.Label(label=_(\"Found a new device:\"))\n    page.pack_start(header, False, False, 0)\n    device_icon = Gtk.Image()\n    icon_name = icons.device_icon_name(device.name, device.kind)\n    device_icon.set_from_icon_name(icon_name, icons.LARGE_SIZE)\n    page.pack_start(device_icon, True, True, 0)\n    device_label = Gtk.Label()\n    device_label.set_markup(f\"<b>{device.name}</b>\")\n    page.pack_start(device_label, True, True, 0)\n    hbox = Gtk.HBox(homogeneous=False, spacing=8)\n    hbox.pack_start(Gtk.Label(label=\" \"), False, False, 0)\n    hbox.set_property(\"expand\", False)\n    hbox.set_property(\"halign\", Gtk.Align.CENTER)\n    page.pack_start(hbox, False, False, 0)\n    GLib.timeout_add(_STATUS_CHECK, _check_encrypted, device, assistant, hbox)  # wait a bit to check link status\n    page.show_all()\n    assistant.next_page()\n    assistant.commit()\n\n\ndef _create_failure_page(assistant, error) -> None:\n    header = _(\"Pairing failed\") + \": \" + _(str(error)) + \".\"\n    if \"timeout\" in str(error):\n        text = _(\"Make sure your device is within range, and has a decent battery charge.\")\n    elif str(error) == \"device not supported\":\n        text = _(\"A new device was detected, but it is not compatible with this receiver.\")\n    elif \"many\" in str(error):\n        text = _(\"More paired devices than receiver can support.\")\n    else:\n        text = _(\"No further details are available about the error.\")\n    _create_page(assistant, Gtk.AssistantPageType.SUMMARY, header, \"dialog-error\", text)\n    assistant.next_page()\n    assistant.commit()\n\n\ndef _create_page(assistant, kind, header=None, icon_name=None, text=None) -> Gtk.VBox:\n    p = Gtk.VBox(homogeneous=False, spacing=8)\n    assistant.append_page(p)\n    assistant.set_page_type(p, kind)\n    if header:\n        item = Gtk.HBox(homogeneous=False, spacing=16)\n        p.pack_start(item, False, True, 0)\n        label = Gtk.Label(label=header)\n        label.set_line_wrap(True)\n        item.pack_start(label, True, True, 0)\n        if icon_name:\n            icon = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.DIALOG)\n            item.pack_start(icon, False, False, 0)\n    if text:\n        label = Gtk.Label(label=text)\n        label.set_line_wrap(True)\n        p.pack_start(label, False, False, 0)\n    p.show_all()\n    return p\n"
  },
  {
    "path": "lib/solaar/ui/rule_actions.py",
    "content": "## Copyright (C) Solaar Contributors\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nfrom enum import Enum\nfrom shlex import quote as shlex_quote\n\nfrom gi.repository import Gtk\nfrom logitech_receiver import diversion\nfrom logitech_receiver.diversion import CLICK\nfrom logitech_receiver.diversion import DEPRESS\nfrom logitech_receiver.diversion import RELEASE\nfrom logitech_receiver.diversion import XK_KEYS\nfrom logitech_receiver.diversion import buttons\n\nfrom solaar.i18n import _\nfrom solaar.ui.rule_base import CompletionEntry\nfrom solaar.ui.rule_base import RuleComponentUI\n\n\nclass GtkSignal(Enum):\n    CHANGED = \"changed\"\n    CLICKED = \"clicked\"\n    TOGGLED = \"toggled\"\n\n\nclass ActionUI(RuleComponentUI):\n    CLASS = diversion.Action\n\n    @classmethod\n    def icon_name(cls):\n        return \"go-next\"\n\n\nclass KeyPressUI(ActionUI):\n    CLASS = diversion.KeyPress\n    KEY_NAMES = [k[3:] if k.startswith(\"XK_\") else k for k, v in XK_KEYS.items() if isinstance(v, int)]\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.fields = []\n        self.label = Gtk.Label(\n            label=_(\"Simulate a chorded key click or depress or release.\\nOn Wayland requires write access to /dev/uinput.\"),\n            halign=Gtk.Align.CENTER,\n            justify=Gtk.Justification.CENTER,\n        )\n        self.widgets[self.label] = (0, 0, 5, 1)\n        self.del_btns = []\n        self.add_btn = Gtk.Button(label=_(\"Add key\"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)\n        self.add_btn.connect(GtkSignal.CLICKED.value, self._clicked_add)\n        self.widgets[self.add_btn] = (1, 1, 1, 1)\n        self.action_clicked_radio = Gtk.RadioButton.new_with_label_from_widget(None, _(\"Click\"))\n        self.action_clicked_radio.connect(GtkSignal.TOGGLED.value, self._on_update, CLICK)\n        self.widgets[self.action_clicked_radio] = (0, 3, 1, 1)\n        self.action_pressed_radio = Gtk.RadioButton.new_with_label_from_widget(self.action_clicked_radio, _(\"Depress\"))\n        self.action_pressed_radio.connect(GtkSignal.TOGGLED.value, self._on_update, DEPRESS)\n        self.widgets[self.action_pressed_radio] = (1, 3, 1, 1)\n        self.action_released_radio = Gtk.RadioButton.new_with_label_from_widget(self.action_pressed_radio, _(\"Release\"))\n        self.action_released_radio.connect(GtkSignal.TOGGLED.value, self._on_update, RELEASE)\n        self.widgets[self.action_released_radio] = (2, 3, 1, 1)\n\n    def _create_field(self):\n        field_entry = CompletionEntry(self.KEY_NAMES, halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)\n        field_entry.connect(GtkSignal.CHANGED.value, self._on_update)\n        field_entry.set_size_request(250, -1)\n        self.fields.append(field_entry)\n        self.widgets[field_entry] = (len(self.fields) - 1, 1, 1, 1)\n        return field_entry\n\n    def _create_del_btn(self):\n        btn = Gtk.Button(label=_(\"Delete\"), halign=Gtk.Align.CENTER, valign=Gtk.Align.START, hexpand=True)\n        self.del_btns.append(btn)\n        self.widgets[btn] = (len(self.del_btns) - 1, 2, 1, 1)\n        btn.connect(GtkSignal.CLICKED.value, self._clicked_del, len(self.del_btns) - 1)\n        return btn\n\n    def _clicked_add(self, _btn):\n        keys, action = self.component.regularize_args(self.collect_value())\n        self.component.__init__([keys + [\"\"], action], warn=False)\n        self.show(self.component, editable=True)\n        self.fields[len(self.component.key_names) - 1].grab_focus()\n\n    def _clicked_del(self, _btn, pos):\n        keys, action = self.component.regularize_args(self.collect_value())\n        keys.pop(pos)\n        self.component.__init__([keys, action], warn=False)\n        self.show(self.component, editable=True)\n        self._on_update_callback()\n\n    def _on_update(self, *args):\n        super()._on_update(*args)\n        for i, f in enumerate(self.fields):\n            if f.get_visible():\n                icon = (\n                    \"dialog-warning\"\n                    if i < len(self.component.key_names) and self.component.key_names[i] not in self.KEY_NAMES\n                    else \"\"\n                )\n                f.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n\n    def show(self, component, editable=True):\n        n = len(component.key_names)\n        while len(self.fields) < n:\n            self._create_field()\n            self._create_del_btn()\n\n        self.widgets[self.add_btn] = (n, 1, 1, 1)\n        super().show(component, editable)\n        for i in range(n):\n            field_entry = self.fields[i]\n            with self.ignore_changes():\n                field_entry.set_text(component.key_names[i])\n            field_entry.show_all()\n            self.del_btns[i].show()\n        for i in range(n, len(self.fields)):\n            self.fields[i].hide()\n            self.del_btns[i].hide()\n\n    def collect_value(self):\n        action = (\n            CLICK if self.action_clicked_radio.get_active() else DEPRESS if self.action_pressed_radio.get_active() else RELEASE\n        )\n        return [[f.get_text().strip() for f in self.fields if f.get_visible()], action]\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Key press\")\n\n    @classmethod\n    def right_label(cls, component):\n        return \" + \".join(component.key_names) + (f\"  ({component.action})\" if component.action != CLICK else \"\")\n\n\nclass MouseScrollUI(ActionUI):\n    CLASS = diversion.MouseScroll\n    MIN_VALUE = -2000\n    MAX_VALUE = 2000\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(\n            label=_(\"Simulate a mouse scroll.\\nOn Wayland requires write access to /dev/uinput.\"),\n            halign=Gtk.Align.CENTER,\n            justify=Gtk.Justification.CENTER,\n        )\n        self.widgets[self.label] = (0, 0, 4, 1)\n        self.label_x = Gtk.Label(label=\"x\", halign=Gtk.Align.END, valign=Gtk.Align.END, hexpand=True)\n        self.label_y = Gtk.Label(label=\"y\", halign=Gtk.Align.END, valign=Gtk.Align.END, hexpand=True)\n        self.field_x = Gtk.SpinButton.new_with_range(self.MIN_VALUE, self.MAX_VALUE, 1)\n        self.field_y = Gtk.SpinButton.new_with_range(self.MIN_VALUE, self.MAX_VALUE, 1)\n        for f in [self.field_x, self.field_y]:\n            f.set_halign(Gtk.Align.CENTER)\n            f.set_valign(Gtk.Align.START)\n        self.field_x.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.field_y.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.label_x] = (0, 1, 1, 1)\n        self.widgets[self.field_x] = (1, 1, 1, 1)\n        self.widgets[self.label_y] = (2, 1, 1, 1)\n        self.widgets[self.field_y] = (3, 1, 1, 1)\n\n    @classmethod\n    def __parse(cls, v):\n        try:\n            # allow floats, but round them down\n            return int(float(v))\n        except (TypeError, ValueError):\n            return 0\n\n    def show(self, component, editable=True):\n        super().show(component, editable)\n        with self.ignore_changes():\n            self.field_x.set_value(self.__parse(component.amounts[0] if len(component.amounts) >= 1 else 0))\n            self.field_y.set_value(self.__parse(component.amounts[1] if len(component.amounts) >= 2 else 0))\n\n    def collect_value(self):\n        return [int(self.field_x.get_value()), int(self.field_y.get_value())]\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Mouse scroll\")\n\n    @classmethod\n    def right_label(cls, component):\n        x = y = 0\n        x = cls.__parse(component.amounts[0] if len(component.amounts) >= 1 else 0)\n        y = cls.__parse(component.amounts[1] if len(component.amounts) >= 2 else 0)\n        return f\"{x}, {y}\"\n\n\nclass MouseClickUI(ActionUI):\n    CLASS = diversion.MouseClick\n    MIN_VALUE = 1\n    MAX_VALUE = 9\n    BUTTONS = list(buttons.keys())\n    ACTIONS = [CLICK, DEPRESS, RELEASE]\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(\n            label=_(\"Simulate a mouse click.\\nOn Wayland requires write access to /dev/uinput.\"),\n            halign=Gtk.Align.CENTER,\n            justify=Gtk.Justification.CENTER,\n        )\n        self.widgets[self.label] = (0, 0, 4, 1)\n        self.label_b = Gtk.Label(label=_(\"Button\"), halign=Gtk.Align.END, valign=Gtk.Align.CENTER, hexpand=True)\n        self.label_c = Gtk.Label(\n            label=_(\"Action (and Count, if click)\"), halign=Gtk.Align.END, valign=Gtk.Align.CENTER, hexpand=True\n        )\n        self.field_b = CompletionEntry(self.BUTTONS)\n        self.field_c = Gtk.SpinButton.new_with_range(self.MIN_VALUE, self.MAX_VALUE, 1)\n        self.field_d = CompletionEntry(self.ACTIONS)\n        for f in [self.field_b, self.field_c]:\n            f.set_halign(Gtk.Align.CENTER)\n            f.set_valign(Gtk.Align.START)\n        self.field_b.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.field_c.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.field_d.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.label_b] = (0, 1, 1, 1)\n        self.widgets[self.field_b] = (1, 1, 1, 1)\n        self.widgets[self.label_c] = (2, 1, 1, 1)\n        self.widgets[self.field_c] = (4, 1, 1, 1)\n        self.widgets[self.field_d] = (3, 1, 1, 1)\n\n    def show(self, component, editable=True):\n        super().show(component, editable)\n        with self.ignore_changes():\n            self.field_b.set_text(component.button)\n            if isinstance(component.count, int):\n                self.field_c.set_value(component.count)\n                self.field_d.set_text(CLICK)\n            else:\n                self.field_c.set_value(1)\n                self.field_d.set_text(component.count)\n\n    def collect_value(self):\n        b, c, d = self.field_b.get_text(), int(self.field_c.get_value()), self.field_d.get_text()\n        if b not in self.BUTTONS:\n            b = \"unknown\"\n        if d != CLICK:\n            c = d\n        return [b, c]\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Mouse click\")\n\n    @classmethod\n    def right_label(cls, component):\n        return f'{component.button} ({\"x\" if isinstance(component.count, int) else \"\"}{component.count})'\n\n\nclass ExecuteUI(ActionUI):\n    CLASS = diversion.Execute\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(\n            label=_(\"Execute a command with arguments.\"), halign=Gtk.Align.CENTER, justify=Gtk.Justification.CENTER\n        )\n        self.widgets[self.label] = (0, 0, 5, 1)\n        self.fields = []\n        self.add_btn = Gtk.Button(label=_(\"Add argument\"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)\n        self.del_btns = []\n        self.add_btn.connect(GtkSignal.CLICKED.value, self._clicked_add)\n        self.widgets[self.add_btn] = (1, 1, 1, 1)\n\n    def _create_field(self):\n        field_entry = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)\n        field_entry.set_size_request(150, 0)\n        field_entry.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.fields.append(field_entry)\n        self.widgets[field_entry] = (len(self.fields) - 1, 1, 1, 1)\n        return field_entry\n\n    def _create_del_btn(self):\n        btn = Gtk.Button(label=_(\"Delete\"), halign=Gtk.Align.CENTER, valign=Gtk.Align.START, hexpand=True)\n        btn.set_size_request(150, 0)\n        self.del_btns.append(btn)\n        self.widgets[btn] = (len(self.del_btns) - 1, 2, 1, 1)\n        btn.connect(GtkSignal.CLICKED.value, self._clicked_del, len(self.del_btns) - 1)\n        return btn\n\n    def _clicked_add(self, *_args):\n        self.component.__init__(self.collect_value() + [\"\"], warn=False)\n        self.show(self.component, editable=True)\n        self.fields[len(self.component.args) - 1].grab_focus()\n\n    def _clicked_del(self, _btn, pos):\n        v = self.collect_value()\n        v.pop(pos)\n        self.component.__init__(v, warn=False)\n        self.show(self.component, editable=True)\n        self._on_update_callback()\n\n    def show(self, component, editable=True):\n        n = len(component.args)\n        while len(self.fields) < n:\n            self._create_field()\n            self._create_del_btn()\n        for i in range(n):\n            field_entry = self.fields[i]\n            with self.ignore_changes():\n                field_entry.set_text(component.args[i])\n            self.del_btns[i].show()\n        self.widgets[self.add_btn] = (n + 1, 1, 1, 1)\n        super().show(component, editable)\n        for i in range(n, len(self.fields)):\n            self.fields[i].hide()\n            self.del_btns[i].hide()\n        self.add_btn.set_valign(Gtk.Align.END if n >= 1 else Gtk.Align.CENTER)\n\n    def collect_value(self):\n        return [f.get_text() for f in self.fields if f.get_visible()]\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Execute\")\n\n    @classmethod\n    def right_label(cls, component):\n        return \" \".join([shlex_quote(a) for a in component.args])\n"
  },
  {
    "path": "lib/solaar/ui/rule_base.py",
    "content": "## Copyright (C) Solaar Contributors\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nimport abc\n\nfrom contextlib import contextmanager as contextlib_contextmanager\nfrom typing import Any\nfrom typing import Callable\n\nfrom gi.repository import Gtk\nfrom logitech_receiver import diversion\n\n\ndef norm(s):\n    return s.replace(\"_\", \"\").replace(\" \", \"\").lower()\n\n\nclass CompletionEntry(Gtk.Entry):\n    def __init__(self, values, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        CompletionEntry.add_completion_to_entry(self, values)\n\n    @classmethod\n    def add_completion_to_entry(cls, entry, values):\n        completion = entry.get_completion()\n        if not completion:\n            liststore = Gtk.ListStore(str)\n            completion = Gtk.EntryCompletion()\n            completion.set_model(liststore)\n            completion.set_match_func(lambda completion, key, it: norm(key) in norm(completion.get_model()[it][0]))\n            completion.set_text_column(0)\n            entry.set_completion(completion)\n        else:\n            liststore = completion.get_model()\n            liststore.clear()\n        for v in sorted(set(values), key=str.casefold):\n            liststore.append((v,))\n\n\nclass RuleComponentUI(abc.ABC):\n    CLASS = diversion.RuleComponent\n\n    def __init__(self, panel, on_update: Callable = None):\n        self.panel = panel\n        self.widgets = {}  # widget -> coord. in grid\n        self.component = None\n        self._ignore_changes = 0\n        self._on_update_callback = (lambda: None) if on_update is None else on_update\n        self.create_widgets()\n\n    @abc.abstractmethod\n    def create_widgets(self) -> dict:\n        pass\n\n    def show(self, component, editable=True):\n        self._show_widgets(editable)\n        self.component = component\n\n    @abc.abstractmethod\n    def collect_value(self) -> Any:\n        pass\n\n    @contextlib_contextmanager\n    def ignore_changes(self):\n        self._ignore_changes += 1\n        yield None\n        self._ignore_changes -= 1\n\n    def _on_update(self, *_args):\n        if not self._ignore_changes and self.component is not None:\n            value = self.collect_value()\n            self.component.__init__(value, warn=False)\n            self._on_update_callback()\n            return value\n        return None\n\n    def _show_widgets(self, editable):\n        self._remove_panel_items()\n        for widget, coord in self.widgets.items():\n            self.panel.attach(widget, *coord)\n            widget.set_sensitive(editable)\n            widget.show()\n\n    @classmethod\n    def left_label(cls, component) -> str:\n        return type(component).__name__\n\n    @classmethod\n    def right_label(cls, _component) -> str:\n        return \"\"\n\n    @classmethod\n    def icon_name(cls) -> str:\n        return \"\"\n\n    def _remove_panel_items(self):\n        for c in self.panel.get_children():\n            self.panel.remove(c)\n\n    def update_devices(self):  # noqa: B027\n        pass\n"
  },
  {
    "path": "lib/solaar/ui/rule_conditions.py",
    "content": "## Copyright (C) Solaar Contributors\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\nfrom dataclasses import dataclass\nfrom enum import Enum\n\nfrom gi.repository import Gtk\nfrom logitech_receiver import diversion\nfrom logitech_receiver.diversion import Key\nfrom logitech_receiver.hidpp20 import SupportedFeature\nfrom logitech_receiver.special_keys import CONTROL\n\nfrom solaar.i18n import _\nfrom solaar.ui.rule_base import CompletionEntry\nfrom solaar.ui.rule_base import RuleComponentUI\n\n\nclass GtkSignal(Enum):\n    CHANGED = \"changed\"\n    CLICKED = \"clicked\"\n    NOTIFY_ACTIVE = \"notify::active\"\n    TOGGLED = \"toggled\"\n    VALUE_CHANGED = \"value-changed\"\n\n\nclass ConditionUI(RuleComponentUI):\n    CLASS = diversion.Condition\n\n    @classmethod\n    def icon_name(cls):\n        return \"dialog-question\"\n\n\nclass ProcessUI(ConditionUI):\n    CLASS = diversion.Process\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER)\n        self.label.set_text(_(\"X11 active process. For use in X11 only.\"))\n        self.widgets[self.label] = (0, 0, 1, 1)\n        self.field = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True)\n        self.field.set_size_request(600, 0)\n        self.field.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.field] = (0, 1, 1, 1)\n\n    def show(self, component, editable=True):\n        super().show(component, editable)\n        with self.ignore_changes():\n            self.field.set_text(component.process)\n\n    def collect_value(self):\n        return self.field.get_text()\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Process\")\n\n    @classmethod\n    def right_label(cls, component):\n        return str(component.process)\n\n\nclass MouseProcessUI(ConditionUI):\n    CLASS = diversion.MouseProcess\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER)\n        self.label.set_text(_(\"X11 mouse process. For use in X11 only.\"))\n        self.widgets[self.label] = (0, 0, 1, 1)\n        self.field = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True)\n        self.field.set_size_request(600, 0)\n        self.field.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.field] = (0, 1, 1, 1)\n\n    def show(self, component, editable=True):\n        super().show(component, editable)\n        with self.ignore_changes():\n            self.field.set_text(component.process)\n\n    def collect_value(self):\n        return self.field.get_text()\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"MouseProcess\")\n\n    @classmethod\n    def right_label(cls, component):\n        return str(component.process)\n\n\nclass FeatureUI(ConditionUI):\n    CLASS = diversion.Feature\n    FEATURES_WITH_DIVERSION = [\n        str(SupportedFeature.CROWN),\n        str(SupportedFeature.THUMB_WHEEL),\n        str(SupportedFeature.LOWRES_WHEEL),\n        str(SupportedFeature.HIRES_WHEEL),\n        str(SupportedFeature.GESTURE_2),\n        str(SupportedFeature.REPROG_CONTROLS_V4),\n        str(SupportedFeature.GKEY),\n        str(SupportedFeature.MKEYS),\n        str(SupportedFeature.MR),\n    ]\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER)\n        self.label.set_text(_(\"Feature name of notification triggering rule processing.\"))\n        self.widgets[self.label] = (0, 0, 1, 1)\n        self.field = Gtk.ComboBoxText.new_with_entry()\n        self.field.append(\"\", \"\")\n        for feature in self.FEATURES_WITH_DIVERSION:\n            self.field.append(feature, feature)\n        self.field.set_valign(Gtk.Align.CENTER)\n        self.field.set_size_request(600, 0)\n        self.field.connect(GtkSignal.CHANGED.value, self._on_update)\n        all_features = [str(f) for f in SupportedFeature]\n        CompletionEntry.add_completion_to_entry(self.field.get_child(), all_features)\n        self.widgets[self.field] = (0, 1, 1, 1)\n\n    def show(self, component, editable=True):\n        super().show(component, editable)\n        with self.ignore_changes():\n            f = str(component.feature) if component.feature else \"\"\n            self.field.set_active_id(f)\n            if f not in self.FEATURES_WITH_DIVERSION:\n                self.field.get_child().set_text(f)\n\n    def collect_value(self):\n        return (self.field.get_active_text() or \"\").strip()\n\n    def _on_update(self, *args):\n        super()._on_update(*args)\n        icon = \"dialog-warning\" if not self.component.feature else \"\"\n        self.field.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Feature\")\n\n    @classmethod\n    def right_label(cls, component):\n        return f\"{str(component.feature)} ({int(component.feature or 0):04X})\"\n\n\nclass ReportUI(ConditionUI):\n    CLASS = diversion.Report\n    MIN_VALUE = -1  # for invalid values\n    MAX_VALUE = 15\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER)\n        self.label.set_text(_(\"Report number of notification triggering rule processing.\"))\n        self.widgets[self.label] = (0, 0, 1, 1)\n        self.field = Gtk.SpinButton.new_with_range(self.MIN_VALUE, self.MAX_VALUE, 1)\n        self.field.set_halign(Gtk.Align.CENTER)\n        self.field.set_valign(Gtk.Align.CENTER)\n        self.field.set_hexpand(True)\n        self.field.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.field] = (0, 1, 1, 1)\n\n    def show(self, component, editable=True):\n        super().show(component, editable)\n        with self.ignore_changes():\n            self.field.set_value(component.report)\n\n    def collect_value(self):\n        return int(self.field.get_value())\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Report\")\n\n    @classmethod\n    def right_label(cls, component):\n        return str(component.report)\n\n\nclass ModifiersUI(ConditionUI):\n    CLASS = diversion.Modifiers\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER)\n        self.label.set_text(_(\"Active keyboard modifiers. Not always available in Wayland.\"))\n        self.widgets[self.label] = (0, 0, 5, 1)\n        self.labels = {}\n        self.switches = {}\n        for i, m in enumerate(diversion.MODIFIERS):\n            switch = Gtk.Switch(halign=Gtk.Align.CENTER, valign=Gtk.Align.START, hexpand=True)\n            label = Gtk.Label(label=m, halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)\n            self.widgets[label] = (i, 1, 1, 1)\n            self.widgets[switch] = (i, 2, 1, 1)\n            self.labels[m] = label\n            self.switches[m] = switch\n            switch.connect(GtkSignal.NOTIFY_ACTIVE.value, self._on_update)\n\n    def show(self, component, editable=True):\n        super().show(component, editable)\n        with self.ignore_changes():\n            for m in diversion.MODIFIERS:\n                self.switches[m].set_active(m in component.modifiers)\n\n    def collect_value(self):\n        return [m for m, s in self.switches.items() if s.get_active()]\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Modifiers\")\n\n    @classmethod\n    def right_label(cls, component):\n        return \"+\".join(component.modifiers) or \"None\"\n\n\nclass KeyUI(ConditionUI):\n    CLASS = diversion.Key\n    KEY_NAMES = map(str, CONTROL)\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER)\n        self.label.set_text(\n            _(\n                \"Diverted key or button depressed or released.\\n\"\n                \"Use the Key/Button Diversion and Divert G Keys settings to divert keys and buttons.\"\n            )\n        )\n        self.widgets[self.label] = (0, 0, 5, 1)\n        self.key_field = CompletionEntry(self.KEY_NAMES, halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True)\n        self.key_field.set_size_request(600, 0)\n        self.key_field.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.key_field] = (0, 1, 2, 1)\n        self.action_pressed_radio = Gtk.RadioButton.new_with_label_from_widget(None, _(\"Key down\"))\n        self.action_pressed_radio.connect(GtkSignal.TOGGLED.value, self._on_update, Key.DOWN)\n        self.widgets[self.action_pressed_radio] = (2, 1, 1, 1)\n        self.action_released_radio = Gtk.RadioButton.new_with_label_from_widget(self.action_pressed_radio, _(\"Key up\"))\n        self.action_released_radio.connect(GtkSignal.TOGGLED.value, self._on_update, Key.UP)\n        self.widgets[self.action_released_radio] = (3, 1, 1, 1)\n\n    def show(self, component, editable=True):\n        super().show(component, editable)\n        with self.ignore_changes():\n            self.key_field.set_text(str(component.key) if self.component.key else \"\")\n            if not component.action or component.action == Key.DOWN:\n                self.action_pressed_radio.set_active(True)\n            else:\n                self.action_released_radio.set_active(True)\n\n    def collect_value(self):\n        action = Key.UP if self.action_released_radio.get_active() else Key.DOWN\n        return [self.key_field.get_text(), action]\n\n    def _on_update(self, *args):\n        super()._on_update(*args)\n        icon = \"dialog-warning\" if not self.component.key or not self.component.action else \"\"\n        self.key_field.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Key\")\n\n    @classmethod\n    def right_label(cls, component):\n        return f\"{str(component.key)} ({int(component.key):04X}) ({_(component.action)})\" if component.key else \"None\"\n\n\nclass KeyIsDownUI(ConditionUI):\n    CLASS = diversion.KeyIsDown\n    KEY_NAMES = map(str, CONTROL)\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER)\n        self.label.set_text(\n            _(\n                \"Diverted key or button is currently down.\\n\"\n                \"Use the Key/Button Diversion and Divert G Keys settings to divert keys and buttons.\"\n            )\n        )\n        self.widgets[self.label] = (0, 0, 5, 1)\n        self.key_field = CompletionEntry(self.KEY_NAMES, halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True)\n        self.key_field.set_size_request(600, 0)\n        self.key_field.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.key_field] = (0, 1, 1, 1)\n\n    def show(self, component, editable=True):\n        super().show(component, editable)\n        with self.ignore_changes():\n            self.key_field.set_text(str(component.key) if self.component.key else \"\")\n\n    def collect_value(self):\n        return self.key_field.get_text()\n\n    def _on_update(self, *args):\n        super()._on_update(*args)\n        icon = \"dialog-warning\" if not self.component.key else \"\"\n        self.key_field.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"KeyIsDown\")\n\n    @classmethod\n    def right_label(cls, component):\n        return f\"{str(component.key)} ({int(component.key):04X})\" if component.key else \"None\"\n\n\nclass TestUI(ConditionUI):\n    CLASS = diversion.Test\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER)\n        self.label.set_text(_(\"Test condition on notification triggering rule processing.\"))\n        self.widgets[self.label] = (0, 0, 4, 1)\n        lbl = Gtk.Label(label=_(\"Test\"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=False, vexpand=False)\n        self.widgets[lbl] = (0, 1, 1, 1)\n        lbl = Gtk.Label(label=_(\"Parameter\"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=False, vexpand=False)\n        self.widgets[lbl] = (2, 1, 1, 1)\n\n        self.test = Gtk.ComboBoxText.new_with_entry()\n        self.test.append(\"\", \"\")\n        for t in diversion.TESTS:\n            self.test.append(t, t)\n        self.test.set_halign(Gtk.Align.END)\n        self.test.set_valign(Gtk.Align.CENTER)\n        self.test.set_hexpand(False)\n        self.test.set_size_request(300, 0)\n        CompletionEntry.add_completion_to_entry(self.test.get_child(), diversion.TESTS)\n        self.test.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.test] = (1, 1, 1, 1)\n\n        self.parameter = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)\n        self.parameter.set_size_request(150, 0)\n        self.parameter.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.widgets[self.parameter] = (3, 1, 1, 1)\n\n    def show(self, component, editable=True):\n        super().show(component, editable)\n        with self.ignore_changes():\n            self.test.set_active_id(component.test)\n            self.parameter.set_text(str(component.parameter) if component.parameter is not None else \"\")\n            if component.test not in diversion.TESTS:\n                self.test.get_child().set_text(component.test)\n                self._change_status_icon()\n\n    def collect_value(self):\n        try:\n            param = int(self.parameter.get_text()) if self.parameter.get_text() else None\n        except Exception:\n            param = self.parameter.get_text()\n        test = (self.test.get_active_text() or \"\").strip()\n        return [test, param] if param is not None else [test]\n\n    def _on_update(self, *args):\n        super()._on_update(*args)\n        self._change_status_icon()\n\n    def _change_status_icon(self):\n        icon = \"dialog-warning\" if (self.test.get_active_text() or \"\").strip() not in diversion.TESTS else \"\"\n        self.test.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Test\")\n\n    @classmethod\n    def right_label(cls, component):\n        return component.test + (f\" {repr(component.parameter)}\" if component.parameter is not None else \"\")\n\n\n@dataclass\nclass TestBytesElement:\n    id: str\n    label: str\n    min: int\n    max: int\n\n\n@dataclass\nclass TestBytesMode:\n    label: str\n    elements: list\n    label_fn: callable\n\n\nclass TestBytesUI(ConditionUI):\n    CLASS = diversion.TestBytes\n\n    _common_elements = [\n        TestBytesElement(\"begin\", _(\"begin (inclusive)\"), 0, 16),\n        TestBytesElement(\"end\", _(\"end (exclusive)\"), 0, 16),\n    ]\n\n    _global_min = -(2**31)\n    _global_max = 2**31 - 1\n\n    _modes = {\n        \"range\": TestBytesMode(\n            _(\"range\"),\n            _common_elements\n            + [\n                TestBytesElement(\"minimum\", _(\"minimum\"), _global_min, _global_max),  # uint32\n                TestBytesElement(\"maximum\", _(\"maximum\"), _global_min, _global_max),\n            ],\n            lambda e: _(\"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\" % {str(i): v for i, v in enumerate(e)}),\n        ),\n        \"mask\": TestBytesMode(\n            _(\"mask\"),\n            _common_elements + [TestBytesElement(\"mask\", _(\"mask\"), _global_min, _global_max)],\n            lambda e: _(\"bytes %(0)d to %(1)d, mask %(2)d\" % {str(i): v for i, v in enumerate(e)}),\n        ),\n    }\n\n    def create_widgets(self):\n        self.fields = {}\n        self.field_labels = {}\n        self.widgets = {}\n        self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER)\n        self.label.set_text(_(\"Bit or range test on bytes in notification message triggering rule processing.\"))\n        self.widgets[self.label] = (0, 0, 5, 1)\n        col = 0\n        mode_col = 2\n        self.mode_field = Gtk.ComboBox.new_with_model(Gtk.ListStore(str, str))\n        mode_renderer = Gtk.CellRendererText()\n        self.mode_field.set_id_column(0)\n        self.mode_field.pack_start(mode_renderer, True)\n        self.mode_field.add_attribute(mode_renderer, \"text\", 1)\n        self.widgets[self.mode_field] = (mode_col, 2, 1, 1)\n        mode_label = Gtk.Label(label=_(\"type\"), margin_top=20)\n        self.widgets[mode_label] = (mode_col, 1, 1, 1)\n        for mode_id, mode in TestBytesUI._modes.items():\n            self.mode_field.get_model().append([mode_id, mode.label])\n            for element in mode.elements:\n                if element.id not in self.fields:\n                    field = Gtk.SpinButton.new_with_range(element.min, element.max, 1)\n                    field.set_value(0)\n                    field.set_size_request(150, 0)\n                    field.connect(GtkSignal.VALUE_CHANGED.value, self._on_update)\n                    label = Gtk.Label(label=element.label, margin_top=20)\n                    self.fields[element.id] = field\n                    self.field_labels[element.id] = label\n                    self.widgets[label] = (col, 1, 1, 1)\n                    self.widgets[field] = (col, 2, 1, 1)\n                    col += 1 if col != mode_col - 1 else 2\n        self.mode_field.connect(GtkSignal.CHANGED.value, lambda cb: (self._on_update(), self._only_mode(cb.get_active_id())))\n        self.mode_field.set_active_id(\"range\")\n\n    def show(self, component, editable=True):\n        super().show(component, editable)\n\n        with self.ignore_changes():\n            mode_id = {3: \"mask\", 4: \"range\"}.get(len(component.test), None)\n            self._only_mode(mode_id)\n            if not mode_id:\n                return\n            self.mode_field.set_active_id(mode_id)\n            if mode_id:\n                mode = TestBytesUI._modes[mode_id]\n                for i, element in enumerate(mode.elements):\n                    self.fields[element.id].set_value(component.test[i])\n\n    def collect_value(self):\n        mode_id = self.mode_field.get_active_id()\n        return [self.fields[element.id].get_value_as_int() for element in TestBytesUI._modes[mode_id].elements]\n\n    def _only_mode(self, mode_id):\n        if not mode_id:\n            return\n        keep = {element.id for element in TestBytesUI._modes[mode_id].elements}\n        for element_id, f in self.fields.items():\n            visible = element_id in keep\n            f.set_visible(visible)\n            self.field_labels[element_id].set_visible(visible)\n\n    def _on_update(self, *args):\n        super()._on_update(*args)\n        if not self.component:\n            return\n        begin, end, *etc = self.component.test\n        icon = \"dialog-warning\" if end <= begin else \"\"\n        self.fields[\"end\"].set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n        if len(self.component.test) == 4:\n            *etc, minimum, maximum = self.component.test\n            icon = \"dialog-warning\" if maximum < minimum else \"\"\n            self.fields[\"maximum\"].set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Test bytes\")\n\n    @classmethod\n    def right_label(cls, component):\n        mode_id = {3: \"mask\", 4: \"range\"}.get(len(component.test), None)\n        if not mode_id:\n            return str(component.test)\n        return TestBytesUI._modes[mode_id].label_fn(component.test)\n\n\nclass MouseGestureUI(ConditionUI):\n    CLASS = diversion.MouseGesture\n    MOUSE_GESTURE_NAMES = [\n        \"Mouse Up\",\n        \"Mouse Down\",\n        \"Mouse Left\",\n        \"Mouse Right\",\n        \"Mouse Up-left\",\n        \"Mouse Up-right\",\n        \"Mouse Down-left\",\n        \"Mouse Down-right\",\n    ]\n    MOVE_NAMES = list(map(str, CONTROL)) + MOUSE_GESTURE_NAMES\n\n    def create_widgets(self):\n        self.widgets = {}\n        self.fields = []\n        self.label = Gtk.Label(\n            label=_(\"Mouse gesture with optional initiating button followed by zero or more mouse movements.\"),\n            halign=Gtk.Align.CENTER,\n            justify=Gtk.Justification.CENTER,\n        )\n        self.widgets[self.label] = (0, 0, 5, 1)\n        self.del_btns = []\n        self.add_btn = Gtk.Button(label=_(\"Add movement\"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True)\n        self.add_btn.connect(GtkSignal.CLICKED.value, self._clicked_add)\n        self.widgets[self.add_btn] = (1, 1, 1, 1)\n\n    def _create_field(self):\n        field = Gtk.ComboBoxText.new_with_entry()\n        for g in self.MOUSE_GESTURE_NAMES:\n            field.append(g, g)\n        CompletionEntry.add_completion_to_entry(field.get_child(), self.MOVE_NAMES)\n        field.connect(GtkSignal.CHANGED.value, self._on_update)\n        self.fields.append(field)\n        self.widgets[field] = (len(self.fields) - 1, 1, 1, 1)\n        return field\n\n    def _create_del_btn(self):\n        btn = Gtk.Button(label=_(\"Delete\"), halign=Gtk.Align.CENTER, valign=Gtk.Align.START, hexpand=True)\n        self.del_btns.append(btn)\n        self.widgets[btn] = (len(self.del_btns) - 1, 2, 1, 1)\n        btn.connect(GtkSignal.CLICKED.value, self._clicked_del, len(self.del_btns) - 1)\n        return btn\n\n    def _clicked_add(self, _btn):\n        self.component.__init__(self.collect_value() + [\"\"], warn=False)\n        self.show(self.component, editable=True)\n        self.fields[len(self.component.movements) - 1].grab_focus()\n\n    def _clicked_del(self, _btn, pos):\n        v = self.collect_value()\n        v.pop(pos)\n        self.component.__init__(v, warn=False)\n        self.show(self.component, editable=True)\n        self._on_update_callback()\n\n    def _on_update(self, *args):\n        super()._on_update(*args)\n        for i, f in enumerate(self.fields):\n            if f.get_visible():\n                icon = (\n                    \"dialog-warning\"\n                    if i < len(self.component.movements) and self.component.movements[i] not in self.MOVE_NAMES\n                    else \"\"\n                )\n                f.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)\n\n    def show(self, component, editable=True):\n        n = len(component.movements)\n        while len(self.fields) < n:\n            self._create_field()\n            self._create_del_btn()\n        self.widgets[self.add_btn] = (n + 1, 1, 1, 1)\n        super().show(component, editable)\n        for i in range(n):\n            field = self.fields[i]\n            with self.ignore_changes():\n                field.get_child().set_text(component.movements[i])\n            field.show_all()\n            self.del_btns[i].show()\n        for i in range(n, len(self.fields)):\n            self.fields[i].hide()\n            self.del_btns[i].hide()\n        self.add_btn.set_valign(Gtk.Align.END if n >= 1 else Gtk.Align.CENTER)\n\n    def collect_value(self):\n        return [f.get_active_text().strip() for f in self.fields if f.get_visible()]\n\n    @classmethod\n    def left_label(cls, component):\n        return _(\"Mouse Gesture\")\n\n    @classmethod\n    def right_label(cls, component):\n        if len(component.movements) == 0:\n            return \"No-op\"\n        else:\n            return \" -> \".join(component.movements)\n"
  },
  {
    "path": "lib/solaar/ui/tray.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport logging\nimport os\n\nfrom enum import Enum\nfrom time import time\n\nimport gi\n\nfrom gi.repository import GLib\nfrom gi.repository import Gtk\nfrom gi.repository.Gdk import ScrollDirection\n\nimport solaar.gtk as gtk\n\nfrom solaar import NAME\nfrom solaar.i18n import _\n\nfrom . import action\nfrom . import icons\nfrom . import window\nfrom .about import about\n\nlogger = logging.getLogger(__name__)\n\n_TRAY_ICON_SIZE = 48\n_MENU_ICON_SIZE = Gtk.IconSize.LARGE_TOOLBAR\n\n\nclass GtkSignal(Enum):\n    ACTIVATE = \"activate\"\n    SCROLL_EVENT = \"scroll-event\"\n\n\ndef _create_menu(quit_handler):\n    # per-device menu entries will be generated as-needed\n    menu = Gtk.Menu()\n\n    no_receiver = Gtk.MenuItem.new_with_label(_(\"No supported device found\"))\n    no_receiver.set_sensitive(False)\n    menu.append(no_receiver)\n    menu.append(Gtk.SeparatorMenuItem.new())\n\n    menu.append(action.make_image_menu_item(_(\"About %s\") % NAME, \"help-about\", about.show))\n    menu.append(action.make_image_menu_item(_(\"Quit %s\") % NAME, \"application-exit\", quit_handler))\n\n    menu.show_all()\n    return menu\n\n\n_last_scroll = 0\n\n\ndef _scroll(tray_icon, event, direction=None):\n    if direction is None:\n        direction = event.direction\n        now = event.time / 1000.0\n    else:\n        now = None\n\n    if direction != ScrollDirection.UP and direction != ScrollDirection.DOWN:\n        # ignore all other directions\n        return\n\n    # don't bother even trying to scroll if less than two devices\n    if sum(map(lambda i: i[1] is not None, _devices_info)) < 2:\n        return\n\n    # scroll events come way too fast (at least 5-6 at once) so take a little break between them\n    global _last_scroll\n    now = now or time()\n    if now - _last_scroll < 0.33:  # seconds\n        return\n    _last_scroll = now\n\n    global _picked_device\n    candidate = None\n\n    if _picked_device is None:\n        for info in _devices_info:\n            # pick first peripheral found\n            if info[1] is not None:\n                candidate = info\n                break\n    else:\n        found = False\n        for info in _devices_info:\n            if not info[1]:\n                # only conside peripherals\n                continue\n            # compare peripherals\n            if info[0:2] == _picked_device[0:2]:\n                if direction == ScrollDirection.UP and candidate:\n                    # select previous device\n                    break\n                found = True\n            else:\n                if found:\n                    candidate = info\n                    if direction == ScrollDirection.DOWN:\n                        break\n                    # if direction is up, but no candidate found before _picked,\n                    # let it run through all candidates, will get stuck with the last one\n                else:\n                    if direction == ScrollDirection.DOWN:\n                        # only use the first one, in case no candidates are after _picked\n                        if candidate is None:\n                            candidate = info\n                    else:\n                        candidate = info\n\n        # if the last _picked_device is gone, clear it\n        # the candidate will be either the first or last one remaining,\n        # depending on the scroll direction\n        if not found:\n            _picked_device = None\n\n    _picked_device = candidate or _picked_device\n    logger.debug(\"scroll: picked %s\", _picked_device)\n    _update_tray_icon()\n\n\ntry:\n    try:\n        gi.require_version(\"AyatanaAppIndicator3\", \"0.1\")\n        from gi.repository import AyatanaAppIndicator3 as AppIndicator3\n\n        ayatana_appindicator_found = True\n    except ValueError:\n        try:\n            gi.require_version(\"AppIndicator3\", \"0.1\")\n            from gi.repository import AppIndicator3\n\n            ayatana_appindicator_found = False\n        except ValueError as exc:\n            # treat unavailable versions the same as unavailable packages\n            raise ImportError from exc\n\n    logger.debug(f\"using {'Ayatana ' if ayatana_appindicator_found else ''}AppIndicator3\")\n\n    # Defense against AppIndicator3 bug that treats files in current directory as icon files\n    # https://bugs.launchpad.net/ubuntu/+source/libappindicator/+bug/1363277\n    # Defense against bug that shows up in XFCE 4.16 where icons are not upscaled\n    def _icon_file(icon_name):\n        if gtk.tray_icon_size is None and not os.path.isfile(icon_name):\n            return icon_name\n        icon_info = Gtk.IconTheme.get_default().lookup_icon(\n            icon_name, gtk.tray_icon_size or _TRAY_ICON_SIZE, Gtk.IconLookupFlags.FORCE_SVG\n        )\n        return icon_info.get_filename() if icon_info else icon_name\n\n    def _create(menu):\n        icons._init_icon_paths()\n        ind = AppIndicator3.Indicator.new(\n            \"indicator-solaar\", _icon_file(icons.TRAY_INIT), AppIndicator3.IndicatorCategory.HARDWARE\n        )\n        ind.set_title(NAME)\n        ind.set_status(AppIndicator3.IndicatorStatus.ACTIVE)\n        # ind.set_attention_icon_full(_icon_file(icons.TRAY_ATTENTION), '') # works poorly for XFCE 16\n        # ind.set_label(NAME.lower(), NAME.lower())\n\n        ind.set_menu(menu)\n        ind.connect(GtkSignal.SCROLL_EVENT.value, _scroll)\n\n        return ind\n\n    def _hide(indicator):\n        indicator.set_status(AppIndicator3.IndicatorStatus.PASSIVE)\n\n    def _show(indicator):\n        indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)\n\n    def _update_tray_icon():\n        if _picked_device and gtk.battery_icons_style != \"solaar\":\n            _ignore, _ignore, name, device = _picked_device\n            battery_level = device.battery_info.level if device.battery_info is not None else None\n            battery_charging = device.battery_info.charging() if device.battery_info is not None else None\n            tray_icon_name = icons.battery(battery_level, battery_charging)\n            description = f\"{name}: {device.status_string()}\"\n        else:\n            # there may be a receiver, but no peripherals\n            tray_icon_name = icons.TRAY_OKAY if _devices_info else icons.TRAY_INIT\n\n            description_lines = _generate_description_lines()\n            description = \"\\n\".join(description_lines).rstrip(\"\\n\")\n\n        # icon_file = icons.icon_file(icon_name, _TRAY_ICON_SIZE)\n        _icon.set_icon_full(_icon_file(tray_icon_name), description)\n\n    def attention(reason=None):\n        if _icon.get_status() != AppIndicator3.IndicatorStatus.ATTENTION:\n            # _icon.set_attention_icon_full(_icon_file(icons.TRAY_ATTENTION), reason or '') # works poorly for XFCe 16\n            _icon.set_status(AppIndicator3.IndicatorStatus.ATTENTION)\n            GLib.timeout_add(10 * 1000, _icon.set_status, AppIndicator3.IndicatorStatus.ACTIVE)\n\nexcept ImportError:\n    logger.debug(\"using StatusIcon\")\n\n    def _create(menu):\n        icon = Gtk.StatusIcon.new_from_icon_name(icons.TRAY_INIT)\n        icon.set_name(NAME.lower())\n        icon.set_title(NAME)\n        icon.set_tooltip_text(NAME)\n        icon.connect(GtkSignal.ACTIVATE.value, window.toggle)\n        icon.connect(GtkSignal.SCROLL_EVENT.value, _scroll)\n        icon.connect(\n            \"popup-menu\",\n            lambda icon, button, time: menu.popup(None, None, icon.position_menu, icon, button, time),\n        )\n\n        return icon\n\n    def _hide(icon):\n        icon.set_visible(False)\n\n    def _show(icon):\n        icon.set_visible(True)\n\n    def _update_tray_icon():\n        tooltip_lines = _generate_tooltip_lines()\n        tooltip = \"\\n\".join(tooltip_lines).rstrip(\"\\n\")\n        _icon.set_tooltip_markup(tooltip)\n\n        if _picked_device and gtk.battery_icons_style != \"solaar\":\n            _ignore, _ignore, name, device = _picked_device\n            battery_level = device.battery_info.level if device.battery_info is not None else None\n            battery_charging = device.battery_info.charging() if device.battery_info is not None else None\n            tray_icon_name = icons.battery(battery_level, battery_charging)\n        else:\n            # there may be a receiver, but no peripherals\n            tray_icon_name = icons.TRAY_OKAY if _devices_info else icons.TRAY_ATTENTION\n        _icon.set_from_icon_name(tray_icon_name)\n\n    _icon_before_attention = None\n\n    def _blink(count):\n        global _icon_before_attention\n        if count % 2:\n            _icon.set_from_icon_name(icons.TRAY_ATTENTION)\n        else:\n            _icon.set_from_icon_name(_icon_before_attention)\n\n        if count > 0:\n            GLib.timeout_add(1000, _blink, count - 1)\n        else:\n            _icon_before_attention = None\n\n    def attention(reason=None):\n        global _icon_before_attention\n        if _icon_before_attention is None:\n            _icon_before_attention = _icon.get_icon_name()\n            GLib.idle_add(_blink, 9)\n\n\ndef _generate_tooltip_lines():\n    if not _devices_info:\n        yield f\"<b>{NAME}</b>: \" + _(\"no receiver\")\n        return\n\n    yield from _generate_description_lines()\n\n\ndef _generate_description_lines():\n    if not _devices_info:\n        yield _(\"no receiver\")\n        return\n\n    for _ignore, number, name, device in _devices_info:\n        if number is None:  # receiver\n            continue\n\n        p = device.status_string()\n        if p:  # does it have any properties to print?\n            yield f\"<b>{name}</b>\"\n            if device.online:\n                yield f\"\\t{p}\"\n            else:\n                yield f\"\\t{p} <small>(\" + _(\"offline\") + \")</small>\"\n        else:\n            if device.online:\n                yield f\"<b>{name}</b> <small>(\" + _(\"no status\") + \")</small>\"\n            else:\n                yield f\"<b>{name}</b> <small>(\" + _(\"offline\") + \")</small>\"\n\n\ndef _pick_device_with_lowest_battery():\n    if not _devices_info:\n        return None\n\n    picked = None\n    picked_level = 1000\n\n    for info in _devices_info:\n        if info[1] is None:  # is receiver\n            continue\n        level = info[-1].battery_info.level if info[-1].battery_info is not None else None\n        if level is not None and picked_level > level:\n            picked = info\n            picked_level = level or 0\n\n    logger.debug(\"picked device with lowest battery: %s\", picked)\n\n    return picked\n\n\ndef _add_device(device):\n    assert device\n\n    index = 0\n    receiver_path = device.receiver.path if device.receiver is not None else device.path\n    if device.receiver is not None:  # if receiver insert into devices for the receiver in device number order\n        for idx, (path, _ignore, _ignore, _ignore) in enumerate(_devices_info):\n            if path and path == receiver_path:\n                index = idx + 1  # the first entry matching the receiver serial should be for the receiver itself\n                break\n        while index < len(_devices_info):\n            path, number, _ignore, _ignore = _devices_info[index]\n            if not path == receiver_path:\n                break\n            assert number != device.number\n            if number > device.number:\n                break\n            index = index + 1\n\n    new_device_info = (receiver_path, device.number, device.name, device)\n    _devices_info.insert(index, new_device_info)\n\n    label = (\"   \" if device.number else \"\") + device.name\n    new_menu_item = action.make_image_menu_item(label, None, window.popup, receiver_path, device.number)\n    _menu.insert(new_menu_item, index)\n\n    return index\n\n\ndef _remove_device(index):\n    assert index is not None\n\n    menu_items = _menu.get_children()\n    _menu.remove(menu_items[index])\n\n    removed_device = _devices_info.pop(index)\n    global _picked_device\n    if _picked_device and _picked_device[0:2] == removed_device[0:2]:\n        # the current pick was unpaired\n        _picked_device = None\n\n\ndef _add_receiver(receiver):\n    index = len(_devices_info)\n    new_receiver_info = (receiver.path, None, receiver.name, None)\n    _devices_info.insert(index, new_receiver_info)\n    icon_name = icons.device_icon_name(receiver.name, receiver.kind)\n    new_menu_item = action.make_image_menu_item(receiver.name, icon_name, window.popup, receiver.path)\n    _menu.insert(new_menu_item, index)\n    return 0\n\n\ndef _remove_receiver(receiver):\n    index = 0\n    # remove all entries in devices_info that match this receiver\n    while index < len(_devices_info):\n        path, _ignore, _ignore, _ignore = _devices_info[index]\n        if path == receiver.path:\n            _remove_device(index)\n        else:\n            index += 1\n\n\ndef _update_menu_item(index, device):\n    if device is None:\n        logger.warning(\"updating an inactive device %s, assuming disconnected\", device)\n        return None\n    menu_items = _menu.get_children()\n    menu_item = menu_items[index]\n    level = device.battery_info.level if device.battery_info is not None else None\n    charging = device.battery_info.charging() if device.battery_info is not None else None\n    icon_name = icons.battery(level, charging)\n    menu_item.label.set_label((\"  \" if 0 < device.number <= 6 else \"\") + device.name + \": \" + device.status_string())\n    image_widget = menu_item.icon\n    image_widget.set_sensitive(bool(device.online))\n    image_widget.set_from_icon_name(icon_name, _MENU_ICON_SIZE)\n\n\n# for which device to show the battery info in systray, if more than one\n# it's actually an entry in _devices_info\n_picked_device = None\n\n# cached list of devices and some of their properties\n# contains tuples of (receiver path, device number, name, device)\n_devices_info = []\n\n_menu = None\n_icon = None\n\n\ndef init(_quit_handler):\n    global _menu, _icon\n    assert _menu is None\n    _menu = _create_menu(_quit_handler)\n    assert _icon is None\n    _icon = _create(_menu)\n    update()\n\n\ndef destroy():\n    global _icon, _menu, _devices_info\n    if _icon is not None:\n        i, _icon = _icon, None\n        _hide(i)\n        i = None\n\n    _icon = None\n    _menu = None\n    _devices_info = None\n\n\ndef update(device=None):\n    if _icon is None:\n        return\n\n    if device is not None:\n        if device.kind is None:\n            # receiver\n            is_alive = bool(device)\n            receiver_path = device.path\n            if is_alive:\n                index = None\n                for idx, (path, _ignore, _ignore, _ignore) in enumerate(_devices_info):\n                    if path == receiver_path:\n                        index = idx\n                        break\n\n                if index is None:\n                    _add_receiver(device)\n            else:\n                _remove_receiver(device)\n\n        else:\n            # peripheral\n            is_paired = bool(device)\n            receiver_path = device.receiver.path if device.receiver is not None else device.path\n            index = None\n            for idx, (path, number, _ignore, _ignore) in enumerate(_devices_info):\n                if path == receiver_path and number == device.number:\n                    index = idx\n\n            if is_paired:\n                if index is None:\n                    index = _add_device(device)\n                _update_menu_item(index, device)\n            else:  # was just unpaired or unplugged\n                if index is not None:\n                    _remove_device(index)\n\n        menu_items = _menu.get_children()\n        no_receivers_index = len(_devices_info)\n        menu_items[no_receivers_index].set_visible(not _devices_info)\n\n    global _picked_device\n    if (not _picked_device or _last_scroll == 0) and device is not None and device.kind is not None:\n        # if it's just a receiver update, it's unlikely the picked device would change\n        _picked_device = _pick_device_with_lowest_battery()\n\n    _update_tray_icon()\n\n    if _icon:\n        if not _devices_info:\n            _hide(_icon)\n        else:\n            _show(_icon)\n"
  },
  {
    "path": "lib/solaar/ui/window.py",
    "content": "## Copyright (C) 2012-2013  Daniel Pavel\n## Copyright (C) 2014-2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport logging\n\nfrom enum import Enum\nfrom enum import IntEnum\n\nimport gi\n\nfrom gi.repository.GObject import TYPE_PYOBJECT\nfrom logitech_receiver import hidpp10_constants\nfrom logitech_receiver.common import LOGITECH_VENDOR_ID\nfrom logitech_receiver.common import NamedInt\n\nfrom solaar import NAME\nfrom solaar.i18n import _\nfrom solaar.i18n import ngettext\n\nfrom . import action\nfrom . import config_panel\nfrom . import diversion_rules\nfrom . import icons\nfrom .about import about\nfrom .common import ui_async\n\ngi.require_version(\"Gdk\", \"3.0\")\nfrom gi.repository import Gdk  # NOQA: E402\nfrom gi.repository import GLib  # NOQA: E402\nfrom gi.repository import Gtk  # NOQA: E402\n\nlogger = logging.getLogger(__name__)\n\n_SMALL_BUTTON_ICON_SIZE = Gtk.IconSize.MENU\n_NORMAL_BUTTON_ICON_SIZE = Gtk.IconSize.BUTTON\n_TREE_ICON_SIZE = Gtk.IconSize.BUTTON\n_INFO_ICON_SIZE = Gtk.IconSize.LARGE_TOOLBAR\n_DEVICE_ICON_SIZE = Gtk.IconSize.DND\ntry:\n    gi.check_version(\"3.7.4\")\n    _CAN_SET_ROW_NONE = None\nexcept (ValueError, AttributeError):\n    _CAN_SET_ROW_NONE = \"\"\n\n\nclass Column(IntEnum):\n    \"\"\"Columns of tree model.\"\"\"\n\n    PATH = 0\n    NUMBER = 1\n    ACTIVE = 2\n    NAME = 3\n    ICON = 4\n    STATUS_TEXT = 5\n    STATUS_ICON = 6\n    DEVICE = 7\n\n\n_COLUMN_TYPES = (str, int, bool, str, str, str, str, TYPE_PYOBJECT)\n_TREE_SEPATATOR = (None, 0, False, None, None, None, None, None)\nassert len(_TREE_SEPATATOR) == len(_COLUMN_TYPES)\nassert len(_COLUMN_TYPES) == len(Column)\n\n\nclass GtkSignal(Enum):\n    CHANGED = \"changed\"\n    CLICKED = \"clicked\"\n    DELETE_EVENT = \"delete-event\"\n\n\ndef _new_button(label, icon_name=None, icon_size=_NORMAL_BUTTON_ICON_SIZE, tooltip=None, toggle=False, clicked=None):\n    b = Gtk.ToggleButton() if toggle else Gtk.Button()\n    c = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 5)\n    if icon_name:\n        c.pack_start(Gtk.Image.new_from_icon_name(icon_name, icon_size), True, True, 0)\n    if label:\n        c.pack_start(Gtk.Label(label=label), True, True, 0)\n    b.add(c)\n    if clicked is not None:\n        b.connect(GtkSignal.CLICKED.value, clicked)\n    if tooltip:\n        b.set_tooltip_text(tooltip)\n    if not label and icon_size < _NORMAL_BUTTON_ICON_SIZE:\n        b.set_relief(Gtk.ReliefStyle.NONE)\n        b.set_focus_on_click(False)\n    return b\n\n\ndef _create_receiver_panel():\n    p = Gtk.Box.new(Gtk.Orientation.VERTICAL, 4)\n\n    p._count = Gtk.Label()\n    p._count.set_margin_top(24)\n    p.pack_start(p._count, True, True, 0)\n\n    p._scanning = Gtk.Label(label=_(\"Scanning\") + \"...\")\n    p._spinner = Gtk.Spinner()\n\n    bp = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 8)\n    bp.pack_start(Gtk.Label(label=\" \"), True, True, 0)\n    bp.pack_start(p._scanning, False, False, 0)\n    bp.pack_end(p._spinner, False, False, 0)\n    p.pack_end(bp, False, False, 0)\n\n    return p\n\n\ndef _create_device_panel():\n    p = Gtk.Box.new(Gtk.Orientation.VERTICAL, 4)\n\n    def _status_line(label_text):\n        b = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 8)\n        b.set_size_request(10, 28)\n\n        b._label = Gtk.Label(label=label_text)\n        b._label.set_size_request(170, 10)\n        b.pack_start(b._label, False, False, 0)\n\n        b._icon = Gtk.Image()\n        b.pack_start(b._icon, False, False, 0)\n\n        b._text = Gtk.Label()\n        b.pack_start(b._text, False, False, 0)\n\n        return b\n\n    p._battery = _status_line(_(\"Battery\"))\n    p.pack_start(p._battery, False, False, 0)\n\n    p._secure = _status_line(_(\"Wireless Link\"))\n    p._secure._icon.set_from_icon_name(\"dialog-warning\", _INFO_ICON_SIZE)\n    p.pack_start(p._secure, False, False, 0)\n\n    p._lux = _status_line(_(\"Lighting\"))\n    p.pack_start(p._lux, False, False, 0)\n\n    p.pack_start(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL), False, False, 0)  # spacer\n\n    p._config = config_panel.create()\n    p.pack_end(p._config, True, True, 4)\n\n    return p\n\n\ndef _create_details_panel():\n    p = Gtk.Frame()\n    p.set_shadow_type(Gtk.ShadowType.NONE)\n    p.set_size_request(240, 0)\n    p.set_state_flags(Gtk.StateFlags.ACTIVE, True)\n\n    p._text = Gtk.Label()\n    p._text.set_margin_start(6)\n    p._text.set_margin_end(4)\n    p._text.set_selectable(True)\n    p.add(p._text)\n\n    return p\n\n\ndef _create_buttons_box():\n    bb = Gtk.HButtonBox()\n    bb.set_layout(Gtk.ButtonBoxStyle.END)\n\n    bb._details = _new_button(\n        None,\n        \"dialog-information\",\n        _SMALL_BUTTON_ICON_SIZE,\n        tooltip=_(\"Show Technical Details\"),\n        toggle=True,\n        clicked=_update_details,\n    )\n    bb.add(bb._details)\n    bb.set_child_secondary(bb._details, True)\n    bb.set_child_non_homogeneous(bb._details, True)\n\n    def _pair_new_device(trigger):\n        assert _find_selected_device_id() is not None\n        receiver = _find_selected_device()\n        assert receiver is not None\n        assert bool(receiver)\n        assert receiver.kind is None\n        action.pair(_window, receiver)\n\n    bb._pair = _new_button(_(\"Pair new device\"), \"list-add\", clicked=_pair_new_device)\n    bb.add(bb._pair)\n\n    def _unpair_current_device(trigger):\n        assert _find_selected_device_id() is not None\n        device = _find_selected_device()\n        assert device is not None\n        assert device.kind is not None\n        action.unpair(_window, device)\n\n    bb._unpair = _new_button(_(\"Unpair\"), \"edit-delete\", clicked=_unpair_current_device)\n    bb.add(bb._unpair)\n\n    return bb\n\n\ndef _create_empty_panel():\n    p = Gtk.Label()\n    p.set_markup(\"<small>\" + _(\"Select a device\") + \"</small>\")\n    p.set_sensitive(False)\n\n    return p\n\n\ndef _create_info_panel():\n    p = Gtk.Box.new(Gtk.Orientation.VERTICAL, 4)\n\n    p._title = Gtk.Label(label=\" \")\n    p._icon = Gtk.Image()\n\n    b1 = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 4)\n    b1.pack_start(p._title, True, True, 0)\n    b1.pack_start(p._icon, False, False, 0)\n    p.pack_start(b1, False, False, 0)\n\n    p.pack_start(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL), False, False, 0)  # spacer\n\n    p._receiver = _create_receiver_panel()\n    p.pack_start(p._receiver, True, True, 0)\n\n    p._device = _create_device_panel()\n    p.pack_start(p._device, True, True, 0)\n\n    p.pack_start(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL), False, False, 0)  # spacer\n\n    p._buttons = _create_buttons_box()\n    p.pack_end(p._buttons, False, False, 0)\n\n    return p\n\n\ndef _create_tree(model):\n    tree = Gtk.TreeView()\n    tree.set_size_request(330, 0)  # enough width for simple setups\n    tree.set_headers_visible(False)\n    tree.set_show_expanders(False)\n    tree.set_level_indentation(20)\n    tree.set_enable_tree_lines(True)\n    tree.set_reorderable(False)\n    tree.set_enable_search(False)\n    tree.set_model(model)\n\n    def _is_separator(model, item, _ignore=None):\n        return model.get_value(item, Column.PATH) is None\n\n    tree.set_row_separator_func(_is_separator, None)\n\n    icon_cell_renderer = Gtk.CellRendererPixbuf()\n    icon_cell_renderer.set_property(\"stock-size\", _TREE_ICON_SIZE)\n    icon_column = Gtk.TreeViewColumn(\"Icon\", icon_cell_renderer)\n    icon_column.add_attribute(icon_cell_renderer, \"sensitive\", Column.ACTIVE)\n    icon_column.add_attribute(icon_cell_renderer, \"icon-name\", Column.ICON)\n    tree.append_column(icon_column)\n\n    name_cell_renderer = Gtk.CellRendererText()\n    name_column = Gtk.TreeViewColumn(\"device name\", name_cell_renderer)\n    name_column.add_attribute(name_cell_renderer, \"sensitive\", Column.ACTIVE)\n    name_column.add_attribute(name_cell_renderer, \"text\", Column.NAME)\n    name_column.set_expand(True)\n    tree.append_column(name_column)\n    tree.set_expander_column(name_column)\n\n    status_cell_renderer = Gtk.CellRendererText()\n    status_cell_renderer.set_property(\"scale\", 0.85)\n    status_cell_renderer.set_property(\"xalign\", 1)\n    status_column = Gtk.TreeViewColumn(\"status text\", status_cell_renderer)\n    status_column.add_attribute(status_cell_renderer, \"sensitive\", Column.ACTIVE)\n    status_column.add_attribute(status_cell_renderer, \"text\", Column.STATUS_TEXT)\n    status_column.set_expand(True)\n    tree.append_column(status_column)\n\n    battery_cell_renderer = Gtk.CellRendererPixbuf()\n    battery_cell_renderer.set_property(\"stock-size\", _TREE_ICON_SIZE)\n    battery_column = Gtk.TreeViewColumn(\"status icon\", battery_cell_renderer)\n    battery_column.add_attribute(battery_cell_renderer, \"sensitive\", Column.ACTIVE)\n    battery_column.add_attribute(battery_cell_renderer, \"icon-name\", Column.STATUS_ICON)\n    tree.append_column(battery_column)\n\n    return tree\n\n\ndef _create_window_layout():\n    assert _tree is not None\n    assert _details is not None\n    assert _info is not None\n    assert _empty is not None\n\n    assert _tree.get_selection().get_mode() == Gtk.SelectionMode.SINGLE\n    _tree.get_selection().connect(GtkSignal.CHANGED.value, _device_selected)\n\n    tree_scroll = Gtk.ScrolledWindow()\n    tree_scroll.add(_tree)\n    tree_scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)\n    tree_scroll.set_shadow_type(Gtk.ShadowType.IN)\n\n    tree_panel = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)\n    tree_panel.set_homogeneous(False)\n    tree_panel.pack_start(tree_scroll, True, True, 0)\n    tree_panel.pack_start(_details, False, False, 0)\n\n    panel = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 16)\n    panel.pack_start(tree_panel, False, False, 0)\n    panel.pack_start(_info, True, True, 0)\n    panel.pack_start(_empty, True, True, 0)\n\n    bottom_buttons_box = Gtk.HButtonBox()\n    bottom_buttons_box.set_layout(Gtk.ButtonBoxStyle.START)\n    bottom_buttons_box.set_spacing(20)\n    quit_button = _new_button(_(\"Quit %s\") % NAME, \"application-exit\", _SMALL_BUTTON_ICON_SIZE, clicked=destroy)\n    bottom_buttons_box.add(quit_button)\n    about_button = _new_button(_(\"About %s\") % NAME, \"help-about\", _SMALL_BUTTON_ICON_SIZE, clicked=about.show)\n    bottom_buttons_box.add(about_button)\n    diversion_button = _new_button(\n        _(\"Rule Editor\"), \"\", _SMALL_BUTTON_ICON_SIZE, clicked=lambda *_trigger: diversion_rules.show_window(_model)\n    )\n    bottom_buttons_box.add(diversion_button)\n    bottom_buttons_box.set_child_secondary(diversion_button, True)\n\n    vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 8)\n    vbox.set_border_width(8)\n    vbox.pack_start(panel, True, True, 0)\n    vbox.pack_end(bottom_buttons_box, False, False, 0)\n    vbox.show_all()\n\n    _details.set_visible(False)\n    _info.set_visible(False)\n    return vbox\n\n\ndef _create(delete_action):\n    window = Gtk.Window()\n    window.set_title(NAME)\n    window.set_role(\"status-window\")\n    window.connect(GtkSignal.DELETE_EVENT.value, delete_action)\n\n    vbox = _create_window_layout()\n    window.add(vbox)\n\n    geometry = Gdk.Geometry()\n    geometry.min_width = 600\n    geometry.min_height = 320\n    window.set_geometry_hints(vbox, geometry, Gdk.WindowHints.MIN_SIZE)\n    window.set_position(Gtk.WindowPosition.CENTER)\n\n    style = window.get_style_context()\n    style.add_class(\"solaar\")\n\n    return window\n\n\ndef _find_selected_device():\n    selection = _tree.get_selection()\n    model, item = selection.get_selected()\n    return model.get_value(item, Column.DEVICE) if item else None\n\n\ndef _find_selected_device_id():\n    selection = _tree.get_selection()\n    model, item = selection.get_selected()\n    if item:\n        return _model.get_value(item, Column.PATH), _model.get_value(item, Column.NUMBER)\n\n\n# triggered by changing selection in the tree\ndef _device_selected(selection):\n    model, item = selection.get_selected()\n    device = model.get_value(item, Column.DEVICE) if item else None\n    if device:\n        _update_info_panel(device, full=True)\n    else:\n        # When removing a receiver, one of its children may get automatically selected\n        # before the tree had time to remove them as well.\n        # Rather than chase around for another device to select, just clear the selection.\n        _tree.get_selection().unselect_all()\n        _update_info_panel(None, full=True)\n\n\ndef _receiver_row(receiver_path, receiver=None):\n    assert receiver_path\n    r = _model.get_iter_first()\n    while r:\n        r = _model.iter_next(r)\n\n    item = _model.get_iter_first()\n    while item:\n        # first row matching the path must be the receiver one\n        if _model.get_value(item, Column.PATH) == receiver_path:\n            return item\n        item = _model.iter_next(item)\n\n    if not item and receiver:\n        icon_name = icons.device_icon_name(receiver.name)\n        status_text = None\n        status_icon = None\n        row_data = (receiver_path, 0, True, receiver.name, icon_name, status_text, status_icon, receiver)\n        assert len(row_data) == len(_TREE_SEPATATOR)\n        logger.debug(\"new receiver row %s\", row_data)\n        item = _model.append(None, row_data)\n        if _TREE_SEPATATOR:\n            _model.append(None, _TREE_SEPATATOR)\n\n    return item or None\n\n\ndef _device_row(receiver_path, device_number, device=None):\n    assert device_number is not None\n    if receiver_path is None:\n        return None\n\n    receiver_row = _receiver_row(receiver_path, None if device is None else device.receiver)\n    if device_number == 0xFF or device_number == 0x0:  # direct-connected device, receiver row is device row\n        if receiver_row:\n            return receiver_row\n        item = None\n        new_child_index = 0\n    else:\n        item = _model.iter_children(receiver_row)\n        new_child_index = 0\n        while item:\n            if _model.get_value(item, Column.PATH) != receiver_path:\n                logger.warning(\n                    \"path for device row %s different from path for receiver %s\",\n                    _model.get_value(item, Column.PATH),\n                    receiver_path,\n                )\n            item_number = _model.get_value(item, Column.NUMBER)\n            if item_number == device_number:\n                return item\n            if item_number > device_number:\n                item = None\n                break\n            new_child_index += 1\n            item = _model.iter_next(item)\n\n    if not item and device:\n        icon_name = icons.device_icon_name(device.name, device.kind)\n        status_text = None\n        status_icon = None\n        row_data = (\n            receiver_path,\n            device_number,\n            bool(device.online),\n            device.codename,\n            icon_name,\n            status_text,\n            status_icon,\n            device,\n        )\n        assert len(row_data) == len(_TREE_SEPATATOR)\n        logger.debug(\"new device row %s at index %d\", row_data, new_child_index)\n        item = _model.insert(receiver_row, new_child_index, row_data)\n\n    return item or None\n\n\ndef select(receiver_path, device_number=None):\n    assert _window\n    assert receiver_path is not None\n    if device_number is None:\n        item = _receiver_row(receiver_path)\n    else:\n        item = _device_row(receiver_path, device_number)\n    if item:\n        selection = _tree.get_selection()\n        selection.select_iter(item)\n    else:\n        logger.warning(\"select(%s, %s) failed to find an item\", receiver_path, device_number)\n\n\ndef _hide(w, _ignore=None):\n    assert w == _window\n    # some window managers move the window to 0,0 after hide()\n    # so try to remember the last position\n    position = _window.get_position()\n    _window.hide()\n    _window.move(*position)\n    return True\n\n\ndef popup(trigger=None, receiver_path=None, device_id=None):\n    if receiver_path:\n        select(receiver_path, device_id)\n    _window.present()\n    return True\n\n\ndef toggle(trigger=None):\n    if _window.get_visible():\n        _hide(_window)\n    else:\n        _window.present()\n\n\ndef _update_details(button):\n    assert button\n    visible = button.get_active()\n\n    if visible:\n        # _details._text.set_markup('<small>reading...</small>')\n\n        def _details_items(device, read_all=False):\n            # If read_all is False, only return stuff that is ~100% already\n            # cached, and involves no HID++ calls.\n\n            yield _(\"Path\"), device.path\n            if device.kind is None:\n                yield _(\"USB ID\"), f\"{LOGITECH_VENDOR_ID:04x}:\" + device.product_id\n\n                if read_all:\n                    yield _(\"Serial\"), device.serial\n                else:\n                    yield _(\"Serial\"), \"...\"\n\n            else:\n                # yield ('Codename', device.codename)\n                yield _(\"Index\"), device.number\n                if device.wpid:\n                    yield _(\"Wireless PID\"), device.wpid\n                if device.product_id:\n                    yield _(\"Product ID\"), f\"{LOGITECH_VENDOR_ID:04x}:\" + device.product_id\n                hid_version = device.protocol\n                yield _(\"Protocol\"), f\"HID++ {hid_version:1.1f}\" if hid_version else _(\"Unknown\")\n                if read_all and device.polling_rate:\n                    yield _(\"Polling rate\"), device.polling_rate\n\n                if read_all or not device.online:\n                    yield _(\"Serial\"), device.serial\n                else:\n                    yield _(\"Serial\"), \"...\"\n                if read_all and device.unitId and device.unitId != device.serial:\n                    yield _(\"Unit ID\"), device.unitId\n\n            if read_all:\n                if device.firmware:\n                    for fw in list(device.firmware):\n                        yield \"  \" + _(str(fw.kind)), (fw.name + \" \" + fw.version).strip()\n            elif device.kind is None or device.online:\n                yield f\"  {_('Firmware')}\", \"...\"\n\n            flag_bits = device.notification_flags\n            if flag_bits is not None:\n                flag_names = hidpp10_constants.flags_to_str(flag_bits, fallback=f\"({_('none')})\")\n                yield _(\"Notifications\"), flag_names\n\n        def _set_details(text):\n            _details._text.set_markup(text)\n\n        def _make_text(items):\n            text = \"\\n\".join(\"%-13s: %s\" % (name, value) for name, value in items)\n            return f\"<small><tt>{text}</tt></small>\"\n\n        def _displayable_items(items):\n            for name, value in items:\n                value = GLib.markup_escape_text(str(value).replace(\"\\x00\", \"\")).strip()\n                if value:\n                    yield name, value\n\n        def _read_slow(device):\n            items = _details_items(selected_device, True)\n            items = _displayable_items(items)\n            text = _make_text(items)\n            if device == _details._current_device:\n                GLib.idle_add(_set_details, text)\n\n        selected_device = _find_selected_device()\n        assert selected_device\n        _details._current_device = selected_device\n\n        read_all = not (selected_device.kind is None or selected_device.online)\n        items = _details_items(selected_device, read_all)\n        _set_details(_make_text(items))\n\n        if read_all:\n            _details._current_device = None\n        else:\n            ui_async(_read_slow, selected_device)\n\n    _details.set_visible(visible)\n\n\ndef _update_receiver_panel(receiver, panel, buttons, full=False):\n    assert receiver\n\n    devices_count = len(receiver)\n\n    paired_text = (\n        _(_(\"No device paired.\"))\n        if devices_count == 0\n        else ngettext(\"%(count)s paired device.\", \"%(count)s paired devices.\", devices_count) % {\"count\": devices_count}\n    )\n\n    if receiver.max_devices > 0:\n        paired_text += (\n            \"\\n\\n<small>%s</small>\"\n            % ngettext(\n                \"Up to %(max_count)s device can be paired to this receiver.\",\n                \"Up to %(max_count)s devices can be paired to this receiver.\",\n                receiver.max_devices,\n            )\n            % {\"max_count\": receiver.max_devices}\n        )\n    elif devices_count > 0:\n        paired_text += f\"\\n\\n<small>{_('Only one device can be paired to this receiver.')}</small>\"\n    pairings = receiver.remaining_pairings()\n    if pairings is not None and pairings >= 0:\n        paired_text += \"\\n<small>%s</small>\" % (\n            ngettext(\"This receiver has %d pairing remaining.\", \"This receiver has %d pairings remaining.\", pairings)\n            % pairings\n        )\n\n    panel._count.set_markup(paired_text)\n\n    is_pairing = receiver.pairing.lock_open\n    if is_pairing:\n        panel._scanning.set_visible(True)\n        if not panel._spinner.get_visible():\n            panel._spinner.start()\n        panel._spinner.set_visible(True)\n    else:\n        panel._scanning.set_visible(False)\n        if panel._spinner.get_visible():\n            panel._spinner.stop()\n        panel._spinner.set_visible(False)\n\n    panel.set_visible(True)\n\n    # b._insecure.set_visible(False)\n    buttons._unpair.set_visible(False)\n\n    if (\n        not is_pairing\n        and (receiver.remaining_pairings() is None or receiver.remaining_pairings() != 0)\n        and (receiver.re_pairs or devices_count < receiver.max_devices)\n    ):\n        buttons._pair.set_sensitive(True)\n    else:\n        buttons._pair.set_sensitive(False)\n\n    buttons._pair.set_visible(True)\n\n\ndef _update_device_panel(device, panel, buttons, full=False):\n    assert device\n    is_online = bool(device.online)\n    panel.set_sensitive(is_online)\n\n    if device.battery_info is None or device.battery_info.level is None:\n        device.read_battery()\n\n    battery_level = device.battery_info.level if device.battery_info is not None else None\n    battery_voltage = device.battery_info.voltage if device.battery_info is not None else None\n    if battery_level is None and battery_voltage is None:\n        panel._battery.set_visible(False)\n    else:\n        panel._battery.set_visible(True)\n        battery_next_level = device.battery_info.next_level\n        charging = device.battery_info.charging() if device.battery_info is not None else None\n        icon_name = icons.battery(battery_level, charging)\n        panel._battery._icon.set_from_icon_name(icon_name, _INFO_ICON_SIZE)\n        panel._battery._icon.set_sensitive(True)\n        panel._battery._text.set_sensitive(is_online)\n\n        if battery_voltage is not None:\n            panel._battery._label.set_text(_(\"Battery Voltage\"))\n            text = f\"{int(battery_voltage)}mV\"\n            tooltip_text = _(\"Voltage reported by battery\")\n        else:\n            panel._battery._label.set_text(_(\"Battery Level\"))\n            text = \"\"\n            tooltip_text = _(\"Approximate level reported by battery\")\n        if battery_voltage is not None and battery_level is not None:\n            text += \", \"\n        if battery_level is not None:\n            text += _(str(battery_level)) if isinstance(battery_level, NamedInt) else f\"{int(battery_level)}%\"\n        if battery_next_level is not None and not charging:\n            if isinstance(battery_next_level, NamedInt):\n                text += \"<small> (\" + _(\"next reported \") + _(str(battery_next_level)) + \")</small>\"\n            else:\n                text += \"<small> (\" + _(\"next reported \") + f\"{int(battery_next_level)}%\" + \")</small>\"\n            tooltip_text = tooltip_text + _(\" and next level to be reported.\")\n        if is_online:\n            if charging:\n                text += f\" <small>({_('charging')})</small>\"\n        else:\n            text += f\" <small>({_('last known')})</small>\"\n\n        panel._battery._text.set_markup(text)\n        panel._battery.set_tooltip_text(tooltip_text)\n\n    if device.link_encrypted is None:\n        panel._secure.set_visible(False)\n    elif is_online:\n        panel._secure.set_visible(True)\n        panel._secure._icon.set_visible(True)\n        if device.link_encrypted is True:\n            panel._secure._text.set_text(_(\"encrypted\"))\n            panel._secure._icon.set_from_icon_name(\"security-high\", _INFO_ICON_SIZE)\n            panel._secure.set_tooltip_text(_(\"The wireless link between this device and its receiver is encrypted.\"))\n        else:\n            panel._secure._text.set_text(_(\"not encrypted\"))\n            panel._secure._icon.set_from_icon_name(\"security-low\", _INFO_ICON_SIZE)\n            panel._secure.set_tooltip_text(\n                _(\n                    \"The wireless link between this device and its receiver is not encrypted.\\n\"\n                    \"This is a security issue for pointing devices, and a major security issue for text-input devices.\"\n                )\n            )\n    else:\n        panel._secure.set_visible(True)\n        panel._secure._icon.set_visible(False)\n        panel._secure._text.set_markup(f\"<small>{_('offline')}</small>\")\n        panel._secure.set_tooltip_text(\"\")\n\n    if is_online:\n        light_level = device.battery_info.light_level if device.battery_info is not None else None\n        if light_level is None:\n            panel._lux.set_visible(False)\n        else:\n            panel._lux._icon.set_from_icon_name(icons.lux(light_level), _INFO_ICON_SIZE)\n            panel._lux._text.set_text(_(\"%(light_level)d lux\") % {\"light_level\": light_level})\n            panel._lux.set_visible(True)\n    else:\n        panel._lux.set_visible(False)\n\n    buttons._pair.set_visible(False)\n    buttons._unpair.set_sensitive(device.receiver.may_unpair if device.receiver else False)\n    buttons._unpair.set_visible(True)\n\n    panel.set_visible(True)\n\n    if full:\n        config_panel.update(device, is_online)\n\n\ndef _update_info_panel(device, full=False):\n    if device is None:\n        # no selected device, show the 'empty' panel\n        _details.set_visible(False)\n        _info.set_visible(False)\n        _empty.set_visible(True)\n        return\n\n    # a receiver must be valid\n    # a device must be paired\n    assert device\n\n    _info._title.set_markup(f\"<b>{device.name}</b>\")\n    icon_name = icons.device_icon_name(device.name, device.kind)\n    _info._icon.set_from_icon_name(icon_name, _DEVICE_ICON_SIZE)\n\n    if device.kind is None:\n        _info._device.set_visible(False)\n        _info._icon.set_sensitive(True)\n        _info._title.set_sensitive(True)\n        _update_receiver_panel(device, _info._receiver, _info._buttons, full)\n    else:\n        _info._receiver.set_visible(False)\n        is_online = bool(device.online)\n        _info._icon.set_sensitive(is_online)\n        _info._title.set_sensitive(is_online)\n        _update_device_panel(device, _info._device, _info._buttons, full)\n\n    _empty.set_visible(False)\n    _info.set_visible(True)\n\n    if full:\n        _update_details(_info._buttons._details)\n\n\n# window layout:\n#  +--------------------------------+\n#  |  tree      | receiver  | empty |\n#  |            | or device |       |\n#  |------------| status    |       |\n#  | details    |           |       |\n#  |--------------------------------|\n#  | (about)                        |\n#  +--------------------------------|\n# either the status or empty panel is visible at any point\n# the details panel can be toggle on/off\n\n_model = None\n_tree = None\n_details = None\n_info = None\n_empty = None\n_window = None\n\n\ndef init(show_window, hide_on_close):\n    Gtk.Window.set_default_icon_name(NAME.lower())\n\n    global _model, _tree, _details, _info, _empty, _window\n    _model = Gtk.TreeStore(*_COLUMN_TYPES)\n    _tree = _create_tree(_model)\n    _details = _create_details_panel()\n    _info = _create_info_panel()\n    _empty = _create_empty_panel()\n    _window = _create(_hide if hide_on_close else destroy)\n    if show_window:\n        _window.present()\n\n\ndef destroy(_ignore1=None, _ignore2=None):\n    global _model, _tree, _details, _info, _empty, _window\n    w, _window = _window, None\n    w.destroy()\n    w = None\n    config_panel.destroy()\n\n    _empty = None\n    _info = None\n    _details = None\n    _tree = None\n    _model = None\n\n\ndef update(device, need_popup=False, refresh=False):\n    if _window is None:\n        return\n\n    assert device is not None\n\n    if need_popup:\n        popup()\n\n    selected_device_id = _find_selected_device_id()\n\n    if device.kind is None:  # receiver\n        # receiver\n        is_alive = bool(device)\n        item = _receiver_row(device.path, device if is_alive else None)\n\n        if is_alive and item:\n            was_pairing = bool(_model.get_value(item, Column.STATUS_ICON))\n            is_pairing = (not device.isDevice) and bool(device.pairing.lock_open)\n            _model.set_value(item, Column.STATUS_ICON, \"network-wireless\" if is_pairing else _CAN_SET_ROW_NONE)\n\n            if selected_device_id == (device.path, 0):\n                full_update = need_popup or was_pairing != is_pairing\n                _update_info_panel(device, full=full_update)\n\n        elif item:\n            if _TREE_SEPATATOR:\n                separator = _model.iter_next(item)\n                if separator:\n                    _model.remove(separator)\n            _model.remove(item)\n\n    else:\n        path = device.receiver.path if device.receiver is not None else device.path\n        assert device.number is not None and device.number >= 0, f\"invalid device number{str(device.number)}\"\n        item = _device_row(path, device.number, device if bool(device) else None)\n\n        if bool(device) and item:\n            update_device(device, item, selected_device_id, need_popup, full=refresh)\n        elif item:\n            _model.remove(item)\n            config_panel.clean(device)\n\n    # make sure all rows are visible\n    _tree.expand_all()\n\n\ndef update_device(device, item, selected_device_id, need_popup, full=False):\n    was_online = _model.get_value(item, Column.ACTIVE)\n    is_online = bool(device.online)\n    _model.set_value(item, Column.ACTIVE, is_online)\n\n    battery_level = device.battery_info.level if device.battery_info is not None else None\n    battery_voltage = device.battery_info.voltage if device.battery_info is not None else None\n    if battery_level is None:\n        _model.set_value(item, Column.STATUS_TEXT, _CAN_SET_ROW_NONE)\n        _model.set_value(item, Column.STATUS_ICON, _CAN_SET_ROW_NONE)\n    else:\n        if battery_voltage is not None and False:  # Use levels instead of voltage here\n            status_text = f\"{int(battery_voltage)}mV\"\n        elif isinstance(battery_level, NamedInt):\n            status_text = _(str(battery_level))\n        else:\n            status_text = f\"{int(battery_level)}%\"\n        _model.set_value(item, Column.STATUS_TEXT, status_text)\n\n        charging = device.battery_info.charging() if device.battery_info is not None else None\n        icon_name = icons.battery(battery_level, charging)\n        _model.set_value(item, Column.STATUS_ICON, icon_name)\n\n    _model.set_value(item, Column.NAME, device.codename)\n\n    if selected_device_id is None or need_popup:\n        select(device.receiver.path if device.receiver else device.path, device.number)\n    elif selected_device_id == (device.receiver.path if device.receiver else device.path, device.number):\n        full_update = full or was_online != is_online\n        _update_info_panel(device, full=full_update)\n\n\ndef find_device(serial):\n    assert serial, \"need serial number or unit ID to find a device\"\n    result = None\n\n    def check(_store, _treepath, row):\n        nonlocal result\n        device = _model.get_value(row, Column.DEVICE)\n        if device and device.kind and (device.unitId == serial or device.serial == serial):\n            result = device\n            return True\n\n    _model.foreach(check)\n    return result\n"
  },
  {
    "path": "lib/solaar/version",
    "content": "1.1.19\n"
  },
  {
    "path": "mkdocs.yml",
    "content": "site_name: Solaar Documentation\nsite_description: Linux Device Manager for Logitech Unifying Receivers and Devices.\nsite_author: pwr-Solaar\nrepo_url: https://github.com/pwr-Solaar/Solaar\nrepo_name: Solaar\ntheme:\n  name: readthedocs\ndocs_dir: docs\nnav:\n  - Solaar: index.md\n  - Usage: usage.md\n  - Capabilities: capabilities.md\n  - Issues: issues.md\n  - Rules: rules.md\n  - Installation: installation.md\n  - Uninstallation: uninstallation.md\n  - Translation: i18n.md\n  - Features: features.md\n  - Devices: devices.md\n  - Implementation: implementation.md\n  - Debian: debian.md\n\nplugins:\n  - search\n#  - mkdocstrings:\n#      handlers:\n#        python:\n#          setup_commands:\n#            - python -m pip install .\n  - mermaid2\nmarkdown_extensions:\n  - pymdownx.superfences\n"
  },
  {
    "path": "po/README",
    "content": "See docs/i18n.md for instructions about creating or updating a translation.\n"
  },
  {
    "path": "po/ca.po",
    "content": "# Catalan translations for Solaar package.\n# Copyright (C) 2021 THE Solaar's COPYRIGHT HOLDER.\n# This file is distributed under the same license as the Solaar package.\n# Marc Serra <hola@webolot.com>, 2021.\n#\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 0.9.3\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n        \"PO-Revision-Date: 2021-10-22 19:19+0200\\n\"\n        \"Last-Translator: \\n\"\n        \"Language-Team: none\\n\"\n        \"Language: ca\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"X-Generator: Poedit 2.3\\n\"\n        \"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid   \"Bolt Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid   \"Unifying Receiver\"\nmsgstr  \"Receptor Unifying\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid   \"Nano Receiver\"\nmsgstr  \"Receptor Nano\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"Receptor Lightspeed\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"Receptor EX100 27 Mhz\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"empty\"\nmsgstr  \"buida\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"critical\"\nmsgstr  \"crítica\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"low\"\nmsgstr  \"baixa\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"average\"\nmsgstr  \"mitja\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid   \"good\"\nmsgstr  \"bona\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"full\"\nmsgstr  \"plena\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"discharging\"\nmsgstr  \"descarregant\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"recharging\"\nmsgstr  \"recarregant\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid   \"charging\"\nmsgstr  \"carregant\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"not charging\"\nmsgstr  \"no carregant\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"almost full\"\nmsgstr  \"quasi plena\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"charged\"\nmsgstr  \"carregant\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"slow recharge\"\nmsgstr  \"recàrrega lenta\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"invalid battery\"\nmsgstr  \"bateria no vàlida\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"thermal error\"\nmsgstr  \"error tèrmic\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"error\"\nmsgstr  \"error\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid   \"standard\"\nmsgstr  \"estàndard\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"fast\"\nmsgstr  \"ràpid\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"slow\"\nmsgstr  \"lent\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid   \"device timeout\"\nmsgstr  \"temps exhaurit pel dispositiu\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid   \"device not supported\"\nmsgstr  \"dispositiu no suportat\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"too many devices\"\nmsgstr  \"masses dispositius\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"sequence timeout\"\nmsgstr  \"temps de seqüència exhaurit\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid   \"Firmware\"\nmsgstr  \"Firmware\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Bootloader\"\nmsgstr  \"Gestor d'arrencada\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Hardware\"\nmsgstr  \"Hardware\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Other\"\nmsgstr  \"Altres\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Left Button\"\nmsgstr  \"Botó Esquerra\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"Right Button\"\nmsgstr  \"Botó Dret\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Middle Button\"\nmsgstr  \"Botó Central\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Back Button\"\nmsgstr  \"Botó Endarrere\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Forward Button\"\nmsgstr  \"Botó Endavant\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"Botó Gestos Ratolí\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Smart Shift\"\nmsgstr  \"Canvi intel·ligent\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"DPI Switch\"\nmsgstr  \"Selector DPI\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Left Tilt\"\nmsgstr  \"Inclinació a l'Esquerra\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Right Tilt\"\nmsgstr  \"Inclinació a la Dreta\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Left Click\"\nmsgstr  \"Clic Esquerra\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Right Click\"\nmsgstr  \"Clic Dreta\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"Clic Central Ratolí\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"Mouse Back Button\"\nmsgstr  \"Clic Endarrere Ratolí\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"Clik Endavant Ratolí\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"Navegació amb el Botó de Gestos\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"Botó Scroll a l'esquerra\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"Botó Scroll a la dreta\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid   \"pressed\"\nmsgstr  \"pressionat\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid   \"released\"\nmsgstr  \"alliberat\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is closed\"\nmsgstr  \"el bloqueig de vinculació està tancat\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is open\"\nmsgstr  \"el bloqueig de vinculació està obert\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid   \"connected\"\nmsgstr  \"connectat\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid   \"disconnected\"\nmsgstr  \"desconnectat\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid   \"unpaired\"\nmsgstr  \"desvinculat\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid   \"powered on\"\nmsgstr  \"alimentat\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid   \"register\"\nmsgstr  \"registrar\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid   \"feature\"\nmsgstr  \"característica\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid   \"Swap Fx function\"\nmsgstr  \"Intercanviar funció Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"Al activar-se, les tecles F1..F12 activaran les seves funcions \"\n        \"especials,\\n\"\n        \"i s'ha de mantenir pressionada la tecla FN per activar la seva \"\n        \"funció estàndard.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"Al desactivar-se, les tecles F1..F12 activaran les seves funcions \"\n        \"estàndard,\\n\"\n        \"i s'ha de mantenir pressionada la tecla FN per activar la seva \"\n        \"funció especial.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid   \"Hand Detection\"\nmsgstr  \"Detecció de mans\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"Encendra la i·il·luminació quan les mans passin pel damunt el teclat.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"Suavitat Scroll Rodeta\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"Mode d'alta sensibilitat per l'scroll vertical amb la rodeta.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid   \"Side Scrolling\"\nmsgstr  \"Scroll Lateral\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"Al desactivar-se, pressionar la rodeta lateralment envia \"\n        \"esdeveniments de botons personalitzats\\n\"\n        \"en lloc dels esdeveniments estàndard d'scroll lateral.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"Sensibilitat del moviment del ratolí\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid   \"Backlight\"\nmsgstr  \"Retroiluminació\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid   \"Turn illumination on or off on keyboard.\"\nmsgstr  \"Encendre o apagar la il·luminació del teclat.\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"Rodeta d'Alta Resolució\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"Desviar Rodeta\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"Direcció Desplaçament Rodeta\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"Invertir direcció del desplaçament vertical amb la rodeta.\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"Resolució Rodeta Desplaçament\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"Sensibilitat (Velocitat del punter)\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"Multiplicador de velocitat pel ratolí (256 és un multiplicador \"\n        \"normal)\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"Desviament de la Rodeta del Polze\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"Direcció de la Rodeta del Polze\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"Invertir la direcció de desplaçament de la rodeta del polze.\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid   \"Onboard Profiles\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid   \"Enable onboard profiles, which often control report rate and \"\n        \"keyboard lighting\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid   \"Polling Rate (ms)\"\nmsgstr  \"Taxa de Sondeig (ms)\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid   \"Frequency of device polling, in milliseconds\"\nmsgstr  \"Freqüència de sondeig del dispositiu, en milisegons\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid   \"Divert crown events\"\nmsgstr  \"Desviar esdeveniments de la corona\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Fer que la corona enviï notificacions de CROWN HID ++ (que activen \"\n        \"les regles de Solaar, del contrari s'ignoren).\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid   \"Divert G Keys\"\nmsgstr  \"Desviar Tecles G\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid   \"Make G keys send GKEY HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Fer que les tecles G enviïn notificacions GKEY HID ++ (que activen \"\n        \"les regles de Solaar, del contrari, s'ignoren).\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid   \"May also make M keys and MR key send HID++ notifications\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Freespinning\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid   \"Key/Button Actions\"\nmsgstr  \"Accions de Tecla/Botó\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"Canviar l'acció per la tecla o botó.\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"Canviar accions importants (per exemple el botó esquerra del ratolí) \"\n        \"pot deixar el sistema inservible.\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"Desviament de Tecla/Botó\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Diverted\"\nmsgstr  \"Desviat\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid   \"Mouse Gestures\"\nmsgstr  \"Gestos de Ratolí\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Regular\"\nmsgstr  \"Normal\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid   \"Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"Sensibilitat (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid   \"Off\"\nmsgstr  \"Off\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid   \"Disable keys\"\nmsgstr  \"Desactivar tecles\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"Desactivar tecles específiques del teclat.\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"Desactiva la tecla %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid   \"Set OS\"\nmsgstr  \"Especificar S.O.\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"Canviar tecles per coincidir amb el S.O.\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid   \"Change Host\"\nmsgstr  \"Canviar Host\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"Canviar connexió a un host diferent\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Performs a left click.\"\nmsgstr  \"Realitza un clic esquerra.\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Single tap\"\nmsgstr  \"Un toc\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Performs a right click.\"\nmsgstr  \"Realitza un clic dret.\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"Un toc amb dos dits\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"Un toc amb tres dits\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Double tap\"\nmsgstr  \"Doble toc\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Performs a double click.\"\nmsgstr  \"Realitza un clic doble.\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"Doble toc amb dos dits\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"Doble toc amb tres dits\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"Arrossega elements arrossegant el dit després de tocar dues vegades.\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Tap and drag\"\nmsgstr  \"Tocar i arrossegar\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"Arrossega elements arrossegant els dits després de tocar dues \"\n        \"vegades.\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"Tocar i arrossegar amb dos dits\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"Tocar i arrossegar amb tres dits\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"Desactiva els gestos de toc i marge (equivalent a pressionar \"\n        \"FN+LeftClick).\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"Elimina els gestos de toc i marge\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid   \"Scroll with one finger\"\nmsgstr  \"Desplaça amb un dit\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scrolls.\"\nmsgstr  \"Desplaçament.\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"Desplaça amb dos dits\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"Desplaça horitzontalment amb dos dits\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"Desplaça horitzontalment.\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"Desplaçar verticalment amb dos dits\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"Desplaça verticalment.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"Invertir la direcció de desplaçament.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Natural scrolling\"\nmsgstr  \"Desplaçament natural\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"Activa la rodeta del polze.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Thumbwheel\"\nmsgstr  \"Rodeta del polze\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"Lliscar des del marge superior\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"Lliscar des del marge esquerra\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"Lliscar des del marge dret\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"Lliscar des del marge inferior\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"Lliscar dos dits des del marge esquerra\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"Lliscar dos dits des del marge dret\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"Lliscar dos dits des del marge inferior\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"Lliscar dos dits des del marge superior\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"Pessigar per allunyar; Expandir per acostar.\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"Zoom amb dos dits.\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"Pessigar per allunyar.\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"Expandir per acostar.\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"Zoom amb tres dits.\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"Zoom amb dos dits\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid   \"Pixel zone\"\nmsgstr  \"Zona de píxels\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid   \"Ratio zone\"\nmsgstr  \"Zona de relació\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Scale factor\"\nmsgstr  \"Factor d'escalat\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"Estableix la velocitat del cursor.\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left\"\nmsgstr  \"Esquerra\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"Coordenada més a la esquerra.\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width\"\nmsgstr  \"Amplada\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width.\"\nmsgstr  \"Amplada.\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height\"\nmsgstr  \"Alçada\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height.\"\nmsgstr  \"Alçada.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Cursor speed.\"\nmsgstr  \"Velocitat del cursor.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Scale\"\nmsgstr  \"Escala\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid   \"Gestures\"\nmsgstr  \"Gestos\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"Modificar el comportament del ratolí/panell tàctil.\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid   \"Gestures Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid   \"Gesture params\"\nmsgstr  \"Paràmetres de gestos\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"Canviar paràmetres numèrics de un ratolí/panell tàctil.\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid   \"M-Key LEDs\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid   \"MR-Key LED\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Sidetone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid   \"Set sidetone level.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid   \"Equalizer\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid   \"Hz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid   \"Power Management\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid   \"No paired devices.\"\nmsgstr  \"Cap dispositiu connectat.\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"%(count)s dispositiu vinculat.\"\nmsgstr[1]       \"%(count)s dispositius vinculats.\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid   \"Battery: %(level)s\"\nmsgstr  \"Bateria: %(level)s\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid   \"Battery: %(percent)d%%\"\nmsgstr  \"Bateria: %(percent)d%%\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid   \"Lighting: %(level)s lux\"\nmsgstr  \"Il·luminació: %(level)s lux\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"Bateria: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"Bateria: %(percent)d%% (%(status)s)\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid   \"Permissions error\"\nmsgstr  \"Error de permisos\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"Error al connectar al dispositiu\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"S'ha trobat un receptor o dispositiu Logitech a %s, però s'ha \"\n        \"produït un error al connectar-se.\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid   \"Unpairing failed\"\nmsgstr  \"Ha fallat la desvinculació\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"Error al desvincular %{device} de %{receiver}.\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"El receptor ha tornat un error, sense detalls addicionals.\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"Gestiona receptors Logitech,\\n\"\n        \"teclats, ratolins i tauletes.\"\n\n#: lib/solaar/ui/about.py:44\nmsgid   \"Additional Programming\"\nmsgstr  \"Programació addicional\"\n\n#: lib/solaar/ui/about.py:45\nmsgid   \"GUI design\"\nmsgstr  \"Disseny de la interfície gràfica\"\n\n#: lib/solaar/ui/about.py:47\nmsgid   \"Testing\"\nmsgstr  \"Provant\"\n\n#: lib/solaar/ui/about.py:54\nmsgid   \"Logitech documentation\"\nmsgstr  \"Documentació de Logitech\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid   \"Unpair\"\nmsgstr  \"Desvincular\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid   \"Cancel\"\nmsgstr  \"Cancel·lar\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Incomplete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"%d valor\"\nmsgstr[1]       \"%d valors\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid   \"Changes allowed\"\nmsgstr  \"Canvis permesos\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid   \"No changes allowed\"\nmsgstr  \"Canvis no permesos\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid   \"Ignore this setting\"\nmsgstr  \"Ignorar aquesta opció\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid   \"Working\"\nmsgstr  \"Funcionant\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"Ha fallat l'operació de lectura/escriptura.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"Built-in rules\"\nmsgstr  \"Regles integrades\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"User-defined rules\"\nmsgstr  \"Regles definides per l'usuari\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid   \"Rule\"\nmsgstr  \"Regla\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid   \"Sub-rule\"\nmsgstr  \"Sub-regla\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid   \"[empty]\"\nmsgstr  \"[buit]\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"Editor de Regles Solaar\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Make changes permanent?\"\nmsgstr  \"¿Fer els canvis permanents?\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid   \"Yes\"\nmsgstr  \"Sí\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid   \"No\"\nmsgstr  \"No\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"Si escull No, els canvis es perdran quan es tanqui Solaar.\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid   \"Save changes\"\nmsgstr  \"Guardar canvis\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid   \"Discard changes\"\nmsgstr  \"Descartar canvis\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid   \"Insert here\"\nmsgstr  \"Inserir aquí\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid   \"Insert above\"\nmsgstr  \"Inserir a dalt\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid   \"Insert below\"\nmsgstr  \"Inserir a baix\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid   \"Insert new rule here\"\nmsgstr  \"Inserir nova regla aquí\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid   \"Insert new rule above\"\nmsgstr  \"Inserir nova regla a dalt\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Insert new rule below\"\nmsgstr  \"Inserir nova regla a baix\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid   \"Paste here\"\nmsgstr  \"Enganxar aquí\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid   \"Paste above\"\nmsgstr  \"Enganxar a dalt\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid   \"Paste below\"\nmsgstr  \"Enganxar a baix\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid   \"Paste rule here\"\nmsgstr  \"Enganxar regla aquí\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid   \"Paste rule above\"\nmsgstr  \"Enganxar regla a dalt\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Paste rule below\"\nmsgstr  \"Enganxar regla a baix\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid   \"Paste rule\"\nmsgstr  \"Enganxar regla\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid   \"Flatten\"\nmsgstr  \"Aplanar\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Insert\"\nmsgstr  \"Insertar\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Or\"\nmsgstr  \"O\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid   \"And\"\nmsgstr  \"I\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid   \"Condition\"\nmsgstr  \"Condició\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid   \"Feature\"\nmsgstr  \"Característica\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid   \"Report\"\nmsgstr  \"Informar\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid   \"Process\"\nmsgstr  \"Procés\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid   \"Mouse process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid   \"Modifiers\"\nmsgstr  \"Modificadors\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid   \"Key\"\nmsgstr  \"Tecla\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid   \"KeyIsDown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid   \"Active\"\nmsgstr  \"Actiu\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid   \"Device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid   \"Setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid   \"Test\"\nmsgstr  \"Test\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid   \"Test bytes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid   \"Mouse Gesture\"\nmsgstr  \"Gest de Ratolí\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid   \"Action\"\nmsgstr  \"Acció\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid   \"Key press\"\nmsgstr  \"Pulsació de tecla\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid   \"Mouse scroll\"\nmsgstr  \"Desplaçament rodeta del ratolí\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid   \"Mouse click\"\nmsgstr  \"Clic del ratolí\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Set\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid   \"Execute\"\nmsgstr  \"Executar\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Later\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Insert new rule\"\nmsgstr  \"Afegir nova regla\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid   \"Delete\"\nmsgstr  \"Esborrar\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid   \"Negate\"\nmsgstr  \"Negar\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid   \"Wrap with\"\nmsgstr  \"Embolicar amb\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid   \"Cut\"\nmsgstr  \"Tallar\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid   \"Paste\"\nmsgstr  \"Enganxar\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid   \"Copy\"\nmsgstr  \"Copiar\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"Aquest editor encara no és compatible amb el component de regla \"\n        \"seleccionat.\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid   \"Number of seconds to delay.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid   \"Not\"\nmsgstr  \"No\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid   \"MouseProcess\"\nmsgstr  \"ProcésRatolí\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid   \"Key down\"\nmsgstr  \"Tecla avall\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid   \"Key up\"\nmsgstr  \"Tecla amunt\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid   \"Parameter\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid   \"begin (inclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid   \"end (exclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid   \"range\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid   \"minimum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid   \"maximum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid   \"mask\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid   \"type\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid   \"Add movement\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid   \"Add key\"\nmsgstr  \"Afegir tecla\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid   \"Click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid   \"Depress\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid   \"Release\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid   \"Button\"\nmsgstr  \"Botó\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid   \"Count and Action\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid   \"Add argument\"\nmsgstr  \"Afegir argument\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"Toggle\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"True\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid   \"False\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid   \"Unsupported setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid   \"Originating device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid   \"Name of host computer.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid   \"Value\"\nmsgstr  \"Valor\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid   \"Item\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid   \"Change setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid   \"Setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid   \"offline\"\nmsgstr  \"desconectat\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"%(receiver_name)s: vincular nou dispositiu\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"left\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"right\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid   \"Pairing failed\"\nmsgstr  \"Ha falla la vinculació\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"Asseguri's que el seu dispositiu estigui dins l'abast del receptor i \"\n        \"que la bateria tingui suficient càrrega.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"S'ha detectat un nou dispositiu, però no és compatible amb aquest \"\n        \"receptor.\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"Més dispositius emparellats de els que admet el receptor.\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"No hi ha més detalls disponibles sobre aquest error.\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid   \"Found a new device:\"\nmsgstr  \"S'ha trobat un nou dispositiu:\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"La connexió sense fils no és xifrada\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid   \"You may have to first turn the device off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid   \"Turn on the device you want to pair.\"\nmsgstr  \"Engegui el dispositiu que vol vincular.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"Si el dispositiu ja està encès, apagui'l i torni'l a encendre.\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\\n\"\n        \"\\n\"\n        \"Aquest receptor té %d aparellament restant.\"\nmsgstr[1]       \"\\n\"\n        \"\\n\"\n        \"Aquest receptor té %d aparellaments restants.\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\\n\"\n        \"Si cancel·la en aquest punt no es farà servir un aparellament.\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid   \"No supported device found\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"Sobre %s\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"Sortir %s\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid   \"no receiver\"\nmsgstr  \"sense receptor\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid   \"no status\"\nmsgstr  \"sense estat\"\n\n#: lib/solaar/ui/window.py:96\nmsgid   \"Scanning\"\nmsgstr  \"Explorant\"\n\n#: lib/solaar/ui/window.py:129\nmsgid   \"Battery\"\nmsgstr  \"Bateria\"\n\n#: lib/solaar/ui/window.py:132\nmsgid   \"Wireless Link\"\nmsgstr  \"Enllaç sense fils\"\n\n#: lib/solaar/ui/window.py:136\nmsgid   \"Lighting\"\nmsgstr  \"Il·luminació\"\n\n#: lib/solaar/ui/window.py:170\nmsgid   \"Show Technical Details\"\nmsgstr  \"Mostrar detalls tècnics\"\n\n#: lib/solaar/ui/window.py:186\nmsgid   \"Pair new device\"\nmsgstr  \"Vincular nou dispositiu\"\n\n#: lib/solaar/ui/window.py:205\nmsgid   \"Select a device\"\nmsgstr  \"Seleccionar un dispositiu\"\n\n#: lib/solaar/ui/window.py:322\nmsgid   \"Rule Editor\"\nmsgstr  \"Editor de Regles\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Path\"\nmsgstr  \"Ruta\"\n\n#: lib/solaar/ui/window.py:536\nmsgid   \"USB ID\"\nmsgstr  \"ID USB\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid   \"Serial\"\nmsgstr  \"Serial\"\n\n#: lib/solaar/ui/window.py:545\nmsgid   \"Index\"\nmsgstr  \"Índex\"\n\n#: lib/solaar/ui/window.py:547\nmsgid   \"Wireless PID\"\nmsgstr  \"PID sense fils\"\n\n#: lib/solaar/ui/window.py:549\nmsgid   \"Product ID\"\nmsgstr  \"ID del producte\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Protocol\"\nmsgstr  \"Protocol\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Unknown\"\nmsgstr  \"Desconegut\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid   \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr  \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#: lib/solaar/ui/window.py:554\nmsgid   \"Polling rate\"\nmsgstr  \"Taxa de sondeig\"\n\n#: lib/solaar/ui/window.py:565\nmsgid   \"Unit ID\"\nmsgstr  \"ID Unitat\"\n\n#: lib/solaar/ui/window.py:576\nmsgid   \"none\"\nmsgstr  \"cap\"\n\n#: lib/solaar/ui/window.py:577\nmsgid   \"Notifications\"\nmsgstr  \"Notificacions\"\n\n#: lib/solaar/ui/window.py:621\nmsgid   \"No device paired.\"\nmsgstr  \"No hi ha dispositius vinculats.\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"Es pot vincular fins a %(max_count)s dispositiu a aquest \"\n        \"receptor.\"\nmsgstr[1]       \"Es pot vincular fins a %(max_count)s dispositius a aquest \"\n        \"receptor.\"\n\n#: lib/solaar/ui/window.py:634\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"Només es pot vincular un dispositiu a aquest receptor.\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"Aquest receptor té %d aparellament restant.\"\nmsgstr[1]       \"Aquest receptor té %d aparellaments restants.\"\n\n#: lib/solaar/ui/window.py:692\nmsgid   \"Battery Voltage\"\nmsgstr  \"Voltatge de la bateria\"\n\n#: lib/solaar/ui/window.py:694\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"Voltatge informat per la bateria\"\n\n#: lib/solaar/ui/window.py:696\nmsgid   \"Battery Level\"\nmsgstr  \"Nivell de Bateria\"\n\n#: lib/solaar/ui/window.py:698\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"Nivell aproximat informat per la bateria\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid   \"next reported \"\nmsgstr  \"següent informe \"\n\n#: lib/solaar/ui/window.py:708\nmsgid   \" and next level to be reported.\"\nmsgstr  \" i següent nivell que serà informat.\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"last known\"\nmsgstr  \"últim conegut\"\n\n#: lib/solaar/ui/window.py:724\nmsgid   \"encrypted\"\nmsgstr  \"xifrat\"\n\n#: lib/solaar/ui/window.py:726\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"La connexió sense fils entre el dispositiu i el seu receptor està \"\n        \"xifrada.\"\n\n#: lib/solaar/ui/window.py:728\nmsgid   \"not encrypted\"\nmsgstr  \"no xifrat\"\n\n#: lib/solaar/ui/window.py:732\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"%(light_level)d lux\"\n\n#~ msgid        \"\\n\"\n#~      \"\\n\"\n#~      \"This receiver has %d pairing(s) remaining.\"\n#~ msgstr       \"\\n\"\n#~      \"\\n\"\n#~      \"Aquest receptor té %d aparellament(s) disponibles.\"\n\n#~ msgid        \"%(battery_level)s\"\n#~ msgstr       \"%(battery_level)s\"\n\n#~ msgid        \"%(battery_percent)d%%\"\n#~ msgstr       \"%(battery_percent)d%%\"\n\n#~ msgid        \"Add action\"\n#~ msgstr       \"Afegir acció\"\n\n#~ msgid        \"Adjust the DPI by sliding the mouse horizontally while \"\n#~      \"holding the button down.\"\n#~ msgstr       \"Ajustar els DPI lliscant el ratolí horitzontalment mentre es \"\n#~      \"manté el botó pressionat.\"\n\n#~ msgid        \"Automatically switch the mouse wheel between ratchet and \"\n#~      \"freespin mode.\\n\"\n#~      \"The mouse wheel is always free at 0, and always locked at 50\"\n#~ msgstr       \"Canvia automàticament el mode de la rodeta del ratolí entre \"\n#~      \"bloquejat i gir lliure.\\n\"\n#~      \"La rodeta del ratolí sempre està lliure a 0 i sempre bloquejat a 50\"\n\n#~ msgid        \"Automatically switch the mouse wheel between ratchet and \"\n#~      \"freespin mode.\\n\"\n#~      \"The mouse wheel is always free at 0, and always ratcheted at 50\"\n#~ msgstr       \"Canviar automàticament la rodeta del ratolí entre el mode de \"\n#~      \"trinquet i el mode de gir lliure.\\n\"\n#~      \"La rodeta del ratolí sempre està lliure a 0 i sempre amb trinquet a \"\n#~      \"50\"\n\n#~ msgid        \"Battery information unknown.\"\n#~ msgstr       \"Informació de la bateria desconeguda.\"\n\n#~ msgid        \"Count\"\n#~ msgstr       \"Conta\"\n\n#~ msgid        \"DPI Sliding Adjustment\"\n#~ msgstr       \"Ajustar DPI lliscant\"\n\n#~ msgid        \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr       \"Desactiva eficaçment el desplaçament amb el polze en Linux.\"\n\n#~ msgid        \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr       \"Desactiva eficaçment l'scroll de la rodeta amb Linux.\"\n\n#, python-format\n#~ msgid        \"Found a Logitech Receiver (%s), but did not have permission \"\n#~      \"to open it.\"\n#~ msgstr       \"S'ha trobat receptor Logitech (%s), però no té permisos per \"\n#~      \"obrir-lo.\"\n\n#~ msgid        \"HID++ Scrolling\"\n#~ msgstr       \"Desplaçament HID++\"\n\n#~ msgid        \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr       \"Mode HID++ per desplaçament horitzontal amb la rodeta del \"\n#~      \"polze.\"\n\n#~ msgid        \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr       \"Mode HID++ pel desplaçament vertical amb la rodeta.\"\n\n#~ msgid        \"High Resolution Scrolling\"\n#~ msgstr       \"Desplaçament d'alta resolució\"\n\n#~ msgid        \"High Resolution Wheel Invert\"\n#~ msgstr       \"Invertir rodeta a l'alta resolució \"\n\n#~ msgid        \"High-sensitivity wheel invert mode for vertical scroll.\"\n#~ msgstr       \"Mode invers d'alta resolució a la rodeta per desplaçament \"\n#~      \"vertical.\"\n\n#~ msgid        \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr       \"Si el dispositiu ja està encès, apagui'l i torni'l a \"\n#~      \"encendre.\"\n\n#~ msgid        \"If you've just installed Solaar, try removing the receiver \"\n#~      \"and plugging it back in.\"\n#~ msgstr       \"Si acaba d'instal·lar Solaar, intenta treure el receptor i \"\n#~      \"connectar-lo de nou.\"\n\n#~ msgid        \"Make the key or button send HID++ notifications (which \"\n#~      \"trigger Solaar rules but are otherwise ignored).\"\n#~ msgstr       \"Fer que la tecla o el botó enviï notificacions HID ++ (que \"\n#~      \"activen les regles de Solaar, del contrari s'ignoren).\"\n\n#~ msgid        \"No Logitech receiver found\"\n#~ msgstr       \"No s'ha trobat cap receptor Logitech\"\n\n#~ msgid        \"Scroll Wheel Rachet\"\n#~ msgstr       \"Trinquet Rodeta Desplaçament\"\n\n#~ msgid        \"Send a gesture by sliding the mouse while holding the button \"\n#~      \"down.\"\n#~ msgstr       \"Enviar un gest lliscant el ratolí mentre manté pressionat el \"\n#~      \"botó.\"\n\n#~ msgid        \"Shows status of devices connected\\n\"\n#~      \"through wireless Logitech receivers.\"\n#~ msgstr       \"Mostrar l'estat de dispositius connectats\\n\"\n#~      \"mitjançant receptors sense fils Logitech.\"\n\n#~ msgid        \"Smooth Scrolling\"\n#~ msgstr       \"Desplaçament suau\"\n\n#~ msgid        \"The receiver only supports %d paired device(s).\"\n#~ msgstr       \"El receptor només soporta %d dispositiu(s) aparellats(s).\"\n\n#~ msgid        \"The receiver was unplugged.\"\n#~ msgstr       \"El receptor s'ha desconnectat.\"\n\n#~ msgid        \"The wireless link between this device and its receiver is \"\n#~      \"not encrypted.\\n\"\n#~      \"\\n\"\n#~      \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~      \"security issue.\\n\"\n#~      \"\\n\"\n#~      \"It is, however, a major security issue for text-input devices \"\n#~      \"(keyboards, numpads),\\n\"\n#~      \"because typed text can be sniffed inconspicuously by 3rd parties \"\n#~      \"within range.\"\n#~ msgstr       \"La conexió inalámbrica entre el dispositiu i el receptor no \"\n#~      \"està cifrada.\\n\"\n#~      \"\\n\"\n#~      \"Per dispositius apuntadors (ratolins, trackballs, trackpads), aquest \"\n#~      \"és un problema menor de seguretat.\\n\"\n#~      \"\\n\"\n#~      \"Tot i això, per dispositius d'entrada de text (teclats, teclats \"\n#~      \"numèrics) sí que és un problema greu,\\n\"\n#~      \"doncs el text introduït pot ser capturat de forma inadvertida per \"\n#~      \"tercers que estiguin aprop.\"\n\n#~ msgid        \"This receiver has %d pairing(s) remaining.\"\n#~ msgstr       \"Este receptor té %d aparellament(s) disponibles.\"\n\n#~ msgid        \"Top-most coordinate.\"\n#~ msgstr       \"Coordenada superior.\"\n\n#~ msgid        \"Try removing the device and plugging it back in or turning \"\n#~      \"it off and then on.\"\n#~ msgstr       \"Intenti treure el dispositiu i tornar a endollar-lo o apagar-\"\n#~      \"lo i encendre'l.\"\n\n#~ msgid        \"USB id\"\n#~ msgstr       \"id USB\"\n\n#~ msgid        \"Wheel Resolution\"\n#~ msgstr       \"Resolució de la rodeta\"\n\n#~ msgid        \"height\"\n#~ msgstr       \"alçada\"\n\n#~ msgid        \"top\"\n#~ msgstr       \"superior\"\n\n#~ msgid        \"unknown\"\n#~ msgstr       \"desconegut\"\n\n#~ msgid        \"width\"\n#~ msgstr       \"amplada\"\n"
  },
  {
    "path": "po/cs.po",
    "content": "# Czech translations for solaar package.\n# Copyright (C) 2020 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n#\n# Automatically generated, 2020.\n# Marián Kyral <mkyral@email.cz>, 2020.\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 1.0.4\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n        \"PO-Revision-Date: 2020-12-30 17:48+0100\\n\"\n        \"Last-Translator: Marián Kyral <mkyral@email.cz>\\n\"\n        \"Language-Team: Czech <kde-i18n-doc@kde.org>\\n\"\n        \"Language: cs\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : \"\n        \"2;\\n\"\n        \"X-Generator: Lokalize 20.12.0\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid   \"Bolt Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid   \"Unifying Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid   \"Nano Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"empty\"\nmsgstr  \"prázdná\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"critical\"\nmsgstr  \"kritická\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"low\"\nmsgstr  \"nízká\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"average\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid   \"good\"\nmsgstr  \"dobrá\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"full\"\nmsgstr  \"plně nabito\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"discharging\"\nmsgstr  \"vybíjení\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"recharging\"\nmsgstr  \"nabíjení\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid   \"charging\"\nmsgstr  \"nabíjení\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"not charging\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"almost full\"\nmsgstr  \"téměř nabito\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"charged\"\nmsgstr  \"nabito\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"slow recharge\"\nmsgstr  \"pomalé nabíjení\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"invalid battery\"\nmsgstr  \"vadná baterie\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"thermal error\"\nmsgstr  \"teplotní chyba\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"error\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid   \"standard\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"fast\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid   \"device timeout\"\nmsgstr  \"vypršel časový limit zařízení\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid   \"device not supported\"\nmsgstr  \"nepodporované zařízení\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"too many devices\"\nmsgstr  \"příliš mnoho zařízení\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"sequence timeout\"\nmsgstr  \"vypršel časový limit sekvence\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid   \"Firmware\"\nmsgstr  \"Firmware\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Bootloader\"\nmsgstr  \"Bootloader\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Hardware\"\nmsgstr  \"Hardware\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Other\"\nmsgstr  \"Další\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Smart Shift\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"DPI Switch\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Left Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Right Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Left Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Right Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"Mouse Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid   \"pressed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid   \"released\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is closed\"\nmsgstr  \"zámek připojení byl uzavřen\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is open\"\nmsgstr  \"zámek připojení byl otevřen\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid   \"connected\"\nmsgstr  \"připojeno\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid   \"disconnected\"\nmsgstr  \"odpojeno\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid   \"unpaired\"\nmsgstr  \"nepřipojeno\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid   \"powered on\"\nmsgstr  \"zapnuto\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid   \"register\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid   \"feature\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid   \"Swap Fx function\"\nmsgstr  \"Přepnout Fx funkci\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"Pokud je nastaveno, budou klávesy F1..F12 spouštět jejich speciální \"\n        \"funkce\\n\"\n        \"a musíte držet Fn abyste aktivovali jejich standardní funkce.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"Pokud není nastaveno, budou klávesy F1..F12 spouštět jejich \"\n        \"standardní funkce\\n\"\n        \"a musíte držet Fn abyste aktivovali jejich speciální funkce.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid   \"Hand Detection\"\nmsgstr  \"Detekce rukou\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"Zapne podsvícení pokud se ruce objeví nad klávesnicí.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"Plynulý posuv kolečkem\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"Vysoce citlivý režim svislého posuvu kolečkem.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid   \"Side Scrolling\"\nmsgstr  \"Boční posuv\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"Pokud je zakázáno, boční stlačení kolečka pošle vlastní události \"\n        \"tlačítek\\n\"\n        \"místo standardních událostí bočního posuvu.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"Citlivost kurzoru myši\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid   \"Backlight\"\nmsgstr  \"Podsvícení\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid   \"Turn illumination on or off on keyboard.\"\nmsgstr  \"Vypne/zapne podsvícení klávesnice.\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"Vysoké rozlišení posuvného kolečka\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"Směr kolečka\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"Mění směr svislého otáčení kolečka.\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"Rozlišení posuvného kolečka\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"Citlivost (rychlost kurzoru)\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"Rychlostní násobitel myši (256 je běžný násobitel).\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"Směr posuvného kolečka\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"Mění směr otáčení kolečka.\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid   \"Onboard Profiles\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid   \"Enable onboard profiles, which often control report rate and \"\n        \"keyboard lighting\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid   \"Polling Rate (ms)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid   \"Frequency of device polling, in milliseconds\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid   \"Divert crown events\"\nmsgstr  \"Odklonění událostí korunky\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Korunka bude zasílat CROWN HID++ oznámení (která spustí Solaar \"\n        \"pravidla, ale jinak budou ignorována).\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid   \"Divert G Keys\"\nmsgstr  \"Odklonit G klávesy\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid   \"Make G keys send GKEY HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"G klávesy budou zasílat GKEY HID++ oznámení (která spustí Solaar \"\n        \"pravidla, ale jinak budou ignorována).\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid   \"May also make M keys and MR key send HID++ notifications\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Freespinning\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid   \"Key/Button Actions\"\nmsgstr  \"Akce klávesy/tlačítka\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"Změní akci klávesy nebo tlačítka.\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"Změna důležité akce (například pro levé tlačítko myši) může vést k \"\n        \"nepoužitelnému systému.\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"Odklonění klávesy/tlačítka\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Diverted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid   \"Mouse Gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Regular\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid   \"Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"Citlivost (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid   \"Off\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid   \"Disable keys\"\nmsgstr  \"Zakázat klávesy\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"Zakáže specifické klávesy.\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"Zakáže %s klávesu.\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid   \"Set OS\"\nmsgstr  \"Nastavit OS\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"Změní klávesy dle operačního systému.\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid   \"Change Host\"\nmsgstr  \"Změnit hostitele\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"Přepnout spojení na jiného hostitele\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Performs a left click.\"\nmsgstr  \"Provede levý klik.\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Single tap\"\nmsgstr  \"Jednoduché kliknutí\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Performs a right click.\"\nmsgstr  \"Provede pravý klik.\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"Jedno klepnutí dvěma prsty\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"Jedno klepnutí třemi prsty\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Double tap\"\nmsgstr  \"\\t\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Performs a double click.\"\nmsgstr  \"Provede dvouklik.\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"Dvojité klepnutí dvěma prsty\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"Dvojité klepnutí třemi prsty\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"Táhnutí položek tažením prstu po dvojitém poklepání.\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Tap and drag\"\nmsgstr  \"Táhni a pusť\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"Táhnutí položek tažením prstů po dvojitém poklepání.\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"Klepnutí a táhnutí dvěma prsty\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"Klepnutí a táhnutí třemi prsty\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"Potlačí gesta klepnutí a hrany (ekvivalent stisknutí Fn + levý klik).\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"Potlačit gesta klepnutí a hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid   \"Scroll with one finger\"\nmsgstr  \"Posuv jedním prstem.\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scrolls.\"\nmsgstr  \"Posuvy.\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"Posuv dvěma prsty\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"Vodorovný posuv dvěma prsty\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"Vodorovný posuv.\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"Svislý posuv dvěma prsty\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"Svislý posuv.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"Mění směr otáčení.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Natural scrolling\"\nmsgstr  \"Přirozený posuv\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"Povolí kolečko.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Thumbwheel\"\nmsgstr  \"Kolečko\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"Táhnutí z horní hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"Táhnutí z levé hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"Táhnutí z pravé hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"Táhnutí ze spodní hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"Táhnutí dvěma prsty z levé hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"Táhnutí dvěma prsty z pravé hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"Táhnutí dvěma prsty ze spodní hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"Táhnutí dvěma prsty z horní hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"Sevření pro přiblížení; rozevření pro oddálení.\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"Přiblížení dvěma prsty.\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"Sevřít pro přiblížení.\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"Rozevřít pro oddálení.\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"Přiblížení třemi prsty.\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"Přiblížení dvěma prsty\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid   \"Pixel zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid   \"Ratio zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Scale factor\"\nmsgstr  \"Faktor škálování\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left\"\nmsgstr  \"Vlevo\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"Souřadnice nejvíce vlevo.\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width\"\nmsgstr  \"Šířka\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width.\"\nmsgstr  \"Šířka.\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height\"\nmsgstr  \"Výška\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height.\"\nmsgstr  \"Výška.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Cursor speed.\"\nmsgstr  \"Rychlost kurzoru.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Scale\"\nmsgstr  \"Měřítko\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid   \"Gestures\"\nmsgstr  \"Gesta\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"Ladí chování myši/touchpadu.\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid   \"Gestures Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid   \"Gesture params\"\nmsgstr  \"Parametry gesta\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"Změňte číselné parametry myši/touchpadu.\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid   \"M-Key LEDs\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid   \"MR-Key LED\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Sidetone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid   \"Set sidetone level.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid   \"Equalizer\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid   \"Hz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid   \"Power Management\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid   \"No paired devices.\"\nmsgstr  \"Nepřipojené zařízení.\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"%(count)s připojené zařízení.\"\nmsgstr[1]       \"%(count)s připojené zařízení.\"\nmsgstr[2]       \"%(count)s připojených zařízení.\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid   \"Battery: %(level)s\"\nmsgstr  \"Baterie: %(level)s\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid   \"Battery: %(percent)d%%\"\nmsgstr  \"Baterie: %(percent)d%%\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid   \"Lighting: %(level)s lux\"\nmsgstr  \"Osvětlení: %(level)s lux\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"Baterie: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"Baterie: %(percent)d%% (%(status)s)\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid   \"Permissions error\"\nmsgstr  \"Chyba oprávnění\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid   \"Unpairing failed\"\nmsgstr  \"Odpojení selhalo\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"Selhalo odpojení %{device} od %{receiver}.\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"Přijímač vrátil chybu bez dalších detailů.\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:44\nmsgid   \"Additional Programming\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:45\nmsgid   \"GUI design\"\nmsgstr  \"Vzhled aplikace\"\n\n#: lib/solaar/ui/about.py:47\nmsgid   \"Testing\"\nmsgstr  \"Testování\"\n\n#: lib/solaar/ui/about.py:54\nmsgid   \"Logitech documentation\"\nmsgstr  \"Dokumentace Logitechu\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid   \"Unpair\"\nmsgstr  \"Odpojit\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid   \"Cancel\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Incomplete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"%d hodnota\"\nmsgstr[1]       \"%d hodnoty\"\nmsgstr[2]       \"%d hodnot\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid   \"Changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid   \"No changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid   \"Ignore this setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid   \"Working\"\nmsgstr  \"Pracuji\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"Operace čtení/zápisu selhala.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"Built-in rules\"\nmsgstr  \"Zabudovaná pravidla\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"User-defined rules\"\nmsgstr  \"Uživatelem definované pravidla\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid   \"Rule\"\nmsgstr  \"Pravidlo\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid   \"Sub-rule\"\nmsgstr  \"Podpravidlo\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid   \"[empty]\"\nmsgstr  \"[prázdné]\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"Editor pravidel Solaar\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Make changes permanent?\"\nmsgstr  \"Nastavit změnu jako trvalou?\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid   \"Yes\"\nmsgstr  \"Ano\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid   \"No\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"Pokud vyberete Ne, budou změny po ukončení aplikace ztraceny.\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid   \"Save changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid   \"Discard changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid   \"Insert here\"\nmsgstr  \"Vložit tady\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid   \"Insert above\"\nmsgstr  \"Vložit nad\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid   \"Insert below\"\nmsgstr  \"Vložit pod\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid   \"Insert new rule here\"\nmsgstr  \"Vložit nové pravidlo tady\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid   \"Insert new rule above\"\nmsgstr  \"Vložit nové pravidlo nad\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Insert new rule below\"\nmsgstr  \"Vložit nové pravidlo pod\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid   \"Paste here\"\nmsgstr  \"Vložit tady\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid   \"Paste above\"\nmsgstr  \"Vložit nad\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid   \"Paste below\"\nmsgstr  \"Vložit pod\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid   \"Paste rule here\"\nmsgstr  \"Vložit pravidlo tady\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid   \"Paste rule above\"\nmsgstr  \"Vložit pravidlo nad\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Paste rule below\"\nmsgstr  \"Vložit pravidlo pod\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid   \"Paste rule\"\nmsgstr  \"Vložit pravidlo\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid   \"Flatten\"\nmsgstr  \"Srovnání\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Insert\"\nmsgstr  \"Vložit\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Or\"\nmsgstr  \"Nebo\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid   \"And\"\nmsgstr  \"A\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid   \"Condition\"\nmsgstr  \"podmínka\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid   \"Feature\"\nmsgstr  \"Vlastnost\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid   \"Report\"\nmsgstr  \"Report\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid   \"Process\"\nmsgstr  \"Proces\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid   \"Mouse process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid   \"Modifiers\"\nmsgstr  \"Modifikátory\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid   \"Key\"\nmsgstr  \"Klávesa\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid   \"KeyIsDown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid   \"Active\"\nmsgstr  \"Aktivní\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid   \"Device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid   \"Setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid   \"Test\"\nmsgstr  \"Test\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid   \"Test bytes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid   \"Mouse Gesture\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid   \"Action\"\nmsgstr  \"Akce\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid   \"Key press\"\nmsgstr  \"Stisknutí klávesy\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid   \"Mouse scroll\"\nmsgstr  \"Otočení kolečkem\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid   \"Mouse click\"\nmsgstr  \"Kliknutí myši\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Set\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid   \"Execute\"\nmsgstr  \"Vykonat\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Later\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Insert new rule\"\nmsgstr  \"Vložit nové pravidlo\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid   \"Delete\"\nmsgstr  \"Smazat\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid   \"Negate\"\nmsgstr  \"Negovat\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid   \"Wrap with\"\nmsgstr  \"Obalit s\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid   \"Cut\"\nmsgstr  \"Vyjmout\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid   \"Paste\"\nmsgstr  \"Vložit\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid   \"Copy\"\nmsgstr  \"Kopírovat\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"Vybraná komponenta pravidla není editorem zatím podporována.\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid   \"Number of seconds to delay.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid   \"Not\"\nmsgstr  \"Opak\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid   \"MouseProcess\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid   \"Key down\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid   \"Key up\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid   \"Parameter\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid   \"begin (inclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid   \"end (exclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid   \"range\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid   \"minimum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid   \"maximum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid   \"mask\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid   \"type\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid   \"Add movement\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid   \"Add key\"\nmsgstr  \"Přidat klávesu\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid   \"Click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid   \"Depress\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid   \"Release\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid   \"Button\"\nmsgstr  \"Tlačítko\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid   \"Count and Action\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid   \"Add argument\"\nmsgstr  \"Přidat argument\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"Toggle\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"True\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid   \"False\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid   \"Unsupported setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid   \"Originating device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid   \"Name of host computer.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid   \"Value\"\nmsgstr  \"Hodnota\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid   \"Item\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid   \"Change setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid   \"Setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid   \"offline\"\nmsgstr  \"vypnuto\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"%(receiver_name)s: nově připojení zařízení\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"left\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"right\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid   \"Pairing failed\"\nmsgstr  \"Připojení selhalo.\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"Ujistěte se, že je zařízení v dosahu je dostatečně nabito.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"Nové zařízení bylo detekováno, ale není kompatibilní s tímto \"\n        \"přijímačem.\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"Více připojených zařízení než přijímač dokáže zvládnout.\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"Další detaily o chybě nejsou dostupné.\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid   \"Found a new device:\"\nmsgstr  \"Nalezeno nové zařízení:\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"Bezdrátové spojení není šifrováno\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid   \"You may have to first turn the device off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid   \"Turn on the device you want to pair.\"\nmsgstr  \"Zapněte zařízení které chcete připojit.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\\n\"\n        \"\\n\"\n        \"K přijímači lze připojit ještě %d zařízení.\"\nmsgstr[1]       \"\\n\"\n        \"\\n\"\n        \"K přijímači lze připojit ještě %d zařízení.\"\nmsgstr[2]       \"\\n\"\n        \"\\n\"\n        \"K přijímači lze připojit ještě %d zařízení.\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\\n\"\n        \"Zrušení v tomto okamžiku nevyužije připojení.\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid   \"No supported device found\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"O aplikaci %s\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"Ukončit %s\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid   \"no receiver\"\nmsgstr  \"bez přijímače\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid   \"no status\"\nmsgstr  \"bez statusu\"\n\n#: lib/solaar/ui/window.py:96\nmsgid   \"Scanning\"\nmsgstr  \"Skenování\"\n\n#: lib/solaar/ui/window.py:129\nmsgid   \"Battery\"\nmsgstr  \"Baterie\"\n\n#: lib/solaar/ui/window.py:132\nmsgid   \"Wireless Link\"\nmsgstr  \"Bezdrátové propojení\"\n\n#: lib/solaar/ui/window.py:136\nmsgid   \"Lighting\"\nmsgstr  \"Osvětlení\"\n\n#: lib/solaar/ui/window.py:170\nmsgid   \"Show Technical Details\"\nmsgstr  \"Ukázat technické detaily\"\n\n#: lib/solaar/ui/window.py:186\nmsgid   \"Pair new device\"\nmsgstr  \"Připojit nové zařízení\"\n\n#: lib/solaar/ui/window.py:205\nmsgid   \"Select a device\"\nmsgstr  \"Vyberte zařízení\"\n\n#: lib/solaar/ui/window.py:322\nmsgid   \"Rule Editor\"\nmsgstr  \"Editor pravidel\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Path\"\nmsgstr  \"Cesta\"\n\n#: lib/solaar/ui/window.py:536\nmsgid   \"USB ID\"\nmsgstr  \"USB ID\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid   \"Serial\"\nmsgstr  \"Sériové číslo\"\n\n#: lib/solaar/ui/window.py:545\nmsgid   \"Index\"\nmsgstr  \"Index\"\n\n#: lib/solaar/ui/window.py:547\nmsgid   \"Wireless PID\"\nmsgstr  \"Bezdrát. PID\"\n\n#: lib/solaar/ui/window.py:549\nmsgid   \"Product ID\"\nmsgstr  \"ID výrobku\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Protocol\"\nmsgstr  \"Protokol\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Unknown\"\nmsgstr  \"Neznámý\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid   \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr  \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#: lib/solaar/ui/window.py:554\nmsgid   \"Polling rate\"\nmsgstr  \"Četn. dotazů\"\n\n#: lib/solaar/ui/window.py:565\nmsgid   \"Unit ID\"\nmsgstr  \"Číslo jednotky\"\n\n#: lib/solaar/ui/window.py:576\nmsgid   \"none\"\nmsgstr  \"žádný\"\n\n#: lib/solaar/ui/window.py:577\nmsgid   \"Notifications\"\nmsgstr  \"Oznámení\"\n\n#: lib/solaar/ui/window.py:621\nmsgid   \"No device paired.\"\nmsgstr  \"Žádné připojené zařízení.\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"K přijímači může být připojeno %(max_count)s zařízení.\"\nmsgstr[1]       \"K přijímači můžou být připojena až %(max_count)s zařízení.\"\nmsgstr[2]       \"K přijímači může být připojeno až %(max_count)s zařízení.\"\n\n#: lib/solaar/ui/window.py:634\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"K tomuto přijímači je možné připojit jen jedno zařízení.\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"K přijímači je možné připojit ještě %d zařízení.\"\nmsgstr[1]       \"K přijímači je možné připojit ještě %d zařízení.\"\nmsgstr[2]       \"K přijímači je možné připojit ještě %d zařízení.\"\n\n#: lib/solaar/ui/window.py:692\nmsgid   \"Battery Voltage\"\nmsgstr  \"Napětí baterie\"\n\n#: lib/solaar/ui/window.py:694\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"Napětí hlášené baterií\"\n\n#: lib/solaar/ui/window.py:696\nmsgid   \"Battery Level\"\nmsgstr  \"Úroveň baterie\"\n\n#: lib/solaar/ui/window.py:698\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"Přibližná úroveň hlášená baterií\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid   \"next reported \"\nmsgstr  \"další hlášené \"\n\n#: lib/solaar/ui/window.py:708\nmsgid   \" and next level to be reported.\"\nmsgstr  \" a další úroveň pro hlášení.\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"last known\"\nmsgstr  \"poslední známý\"\n\n#: lib/solaar/ui/window.py:724\nmsgid   \"encrypted\"\nmsgstr  \"šifrováno\"\n\n#: lib/solaar/ui/window.py:726\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"Bezdrátové spojení mezi zařízením a přijímačem je šifrováno.\"\n\n#: lib/solaar/ui/window.py:728\nmsgid   \"not encrypted\"\nmsgstr  \"nešifrováno\"\n\n#: lib/solaar/ui/window.py:732\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"%(light_level)d lux\"\n\n#~ msgid        \"Adjust the DPI by sliding the mouse horizontally while \"\n#~      \"holding the DPI button.\"\n#~ msgstr       \"Přizpůsobení DPI vodorovného posunu myši při současném \"\n#~      \"držením stisku DPI tlačítka.\"\n\n#~ msgid        \"Automatically switch the mouse wheel between ratchet and \"\n#~      \"freespin mode.\\n\"\n#~      \"The mouse wheel is always free at 0, and always ratcheted at 50\"\n#~ msgstr       \"Automatické přepíná režim kolečka myši mezi krokováním a \"\n#~      \"volným otáčením.\\n\"\n#~      \"Kolečko je při hodnotě 0 vždy volné a při hodnotě 50 vždy krokuje.\"\n\n#~ msgid        \"Battery information unknown.\"\n#~ msgstr       \"Informace o baterii nejsou známy.\"\n\n#~ msgid        \"Click to allow changes.\"\n#~ msgstr       \"Klikněte pro povolení změn.\"\n\n#~ msgid        \"Click to prevent changes.\"\n#~ msgstr       \"Klikněte pro zakázání změn.\"\n\n#~ msgid        \"Count\"\n#~ msgstr       \"Počet\"\n\n#~ msgid        \"DPI Sliding Adjustment\"\n#~ msgstr       \"Úprava DPI klouzání\"\n\n#~ msgid        \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr       \"Efektivně vypne rolování palcem v Linuxu.\"\n\n#~ msgid        \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr       \"Efektivně vypne posuv kolečkem v Linuxu.\"\n\n#~ msgid        \"For more information see the Solaar installation directions\\n\"\n#~      \"at https://pwr-solaar.github.io/Solaar/installation\"\n#~ msgstr       \"Další instalační informace pro Solaar naleznete na \\n\"\n#~      \"https://pwr-solaar.github.io/Solaar/installation\"\n\n#, python-format\n#~ msgid        \"Found a Logitech Receiver (%s), but did not have permission \"\n#~      \"to open it.\"\n#~ msgstr       \"Nalezen přijímač Logitech (%s), ale chybí práva pro jeho \"\n#~      \"otevření.\"\n\n#~ msgid        \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr       \"HID++ režim pro vodorovný posun pomocí kolečka.\"\n\n#~ msgid        \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr       \"HID++ režim pro svislý posuv kolečkem.\"\n\n#~ msgid        \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr       \"Pokud je zařízení zapnuto, vypněte jej a znovu zapněte\"\n\n#~ msgid        \"If you've just installed Solaar, try removing the receiver \"\n#~      \"and plugging it back in.\"\n#~ msgstr       \"Pokud jste Solaar právě nainstalovali, zkuste přijímač \"\n#~      \"odpojit a znova připojit.\"\n\n#~ msgid        \"Make the key or button send HID++ notifications (which \"\n#~      \"trigger Solaar rules but are otherwise ignored).\"\n#~ msgstr       \"Klávesa nebo tlačítko budou zasílat HID++ oznámení (která \"\n#~      \"spustí Solaar pravidla, ale jinak budou ignorována).\"\n\n#~ msgid        \"No Logitech receiver found\"\n#~ msgstr       \"Logitech přijímač nebyl nalezen\"\n\n#~ msgid        \"Scroll Wheel HID++ Scrolling\"\n#~ msgstr       \"HID++ posuv kolečka\"\n\n#~ msgid        \"Scroll Wheel Rachet\"\n#~ msgstr       \"Krokování kolečka\"\n\n#~ msgid        \"Shows status of devices connected\\n\"\n#~      \"through wireless Logitech receivers.\"\n#~ msgstr       \"Zobrazí stav zařízení připojených\\n\"\n#~      \"přes bezdrátový přijímač Logitech.\"\n\n#~ msgid        \"Solaar depends on a udev file that is not present\"\n#~ msgstr       \"Solaar závisí na udev souboru, který chybí\"\n\n#~ msgid        \"The wireless link between this device and its receiver is \"\n#~      \"not encrypted.\\n\"\n#~      \"\\n\"\n#~      \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~      \"security issue.\\n\"\n#~      \"\\n\"\n#~      \"It is, however, a major security issue for text-input devices \"\n#~      \"(keyboards, numpads),\\n\"\n#~      \"because typed text can be sniffed inconspicuously by 3rd parties \"\n#~      \"within range.\"\n#~ msgstr       \"Bezdrátové spojení mezi zařízením a přijímačem není \"\n#~      \"šifrováno.\\n\"\n#~      \"\\n\"\n#~      \"U ukazovacích zařízení (myši, trackbally, trackpady) je to jen \"\n#~      \"drobný bezpečnostní problém.\\n\"\n#~      \"\\n\"\n#~      \"Ovšem pro textové vstupní zařízení (klávesnice, numerické \"\n#~      \"klávesnice) se jedná\\n\"\n#~      \"o významný bezpečnostní problém, protože psaný text může být\\n\"\n#~      \"nepozorovaně odposlechnut třetí stranou, pokud je v dosahu.\"\n\n#~ msgid        \"Thumb Wheel HID++ Scrolling\"\n#~ msgstr       \"HID++ posun kolečkem\"\n\n#~ msgid        \"Top-most coordinate.\"\n#~ msgstr       \"Nejvyšší souřadnice.\"\n\n#~ msgid        \"height\"\n#~ msgstr       \"výška\"\n\n#~ msgid        \"top\"\n#~ msgstr       \"nahoře\"\n\n#~ msgid        \"unknown\"\n#~ msgstr       \"neznámý\"\n\n#~ msgid        \"width\"\n#~ msgstr       \"šířka\"\n"
  },
  {
    "path": "po/da.po",
    "content": "# Danish translations for solaar package.\n# Copyright (C) 2020 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2020.\n#\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 1.0.3\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n        \"PO-Revision-Date: 2020-08-03 02:47+0200\\n\"\n        \"Last-Translator: John Erling Blad <jeblad@gmail.com>\\n\"\n        \"Language-Team: none\\n\"\n        \"Language: da\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n        \"X-Generator: Poedit 2.3\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid   \"Bolt Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid   \"Unifying Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid   \"Nano Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"empty\"\nmsgstr  \"tom\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"critical\"\nmsgstr  \"kritisk\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"low\"\nmsgstr  \"lav\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"average\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid   \"good\"\nmsgstr  \"god\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"full\"\nmsgstr  \"fuld\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"discharging\"\nmsgstr  \"afladning\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"recharging\"\nmsgstr  \"genopladning\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid   \"charging\"\nmsgstr  \"opladning\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"not charging\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"almost full\"\nmsgstr  \"næsten fuld\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"charged\"\nmsgstr  \"opladt\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"slow recharge\"\nmsgstr  \"langsom opladning\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"invalid battery\"\nmsgstr  \"batterifejl\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"thermal error\"\nmsgstr  \"termisk fejl\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"error\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid   \"standard\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"fast\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid   \"device timeout\"\nmsgstr  \"enheden svarede ikke\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid   \"device not supported\"\nmsgstr  \"enhed understøttes ikke\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"too many devices\"\nmsgstr  \"for mange enheder\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"sequence timeout\"\nmsgstr  \"sekvens timeout\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid   \"Firmware\"\nmsgstr  \"Firmware\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Bootloader\"\nmsgstr  \"Opstartsindlæser\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Hardware\"\nmsgstr  \"Hardware\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Other\"\nmsgstr  \"Andet\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Smart Shift\"\nmsgstr  \"Smart skift\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"DPI Switch\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Left Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Right Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Left Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Right Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"Mouse Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid   \"pressed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid   \"released\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is closed\"\nmsgstr  \"parlåsen er lukket\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is open\"\nmsgstr  \"parlåsen er åben\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid   \"connected\"\nmsgstr  \"tilsluttet\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid   \"disconnected\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid   \"unpaired\"\nmsgstr  \"uparret\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid   \"powered on\"\nmsgstr  \"tændt\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid   \"register\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid   \"feature\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid   \"Swap Fx function\"\nmsgstr  \"Byt Fx-funktion\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"Hvis aktiveret, vil F1–F12-tastene aktivere sin spesialfunksjon,\\n\"\n        \"og du må holde FN-tasten nede for at aktivere jeres standardfunktion.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"Hvis deaktiveret, vil F1–F12-tastene aktivere sin standardfunktion,\\n\"\n        \"og du må holde FN-tasten nede for at aktivere deres spesialfunktion.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid   \"Hand Detection\"\nmsgstr  \"Hånddetektion\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"Tænd belysning når hænderne er over tastaturet.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"Højfølsom tilstand til lodret rulling med hjulet.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid   \"Side Scrolling\"\nmsgstr  \"Siderulling\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"Når deaktiveret, sender et tryk på hjulet sidelæns brugerdefinerede \"\n        \"knaphændelser\\n\"\n        \"i stedet for standard siderullehændelser.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid   \"Backlight\"\nmsgstr  \"Bagbelysning\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid   \"Turn illumination on or off on keyboard.\"\nmsgstr  \"Tænd eller sluk for belysning på tastaturet.\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"Følsomhed (pegerhastighed)\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"Hastighedsmultiplikator for mus (256 er normal multiplikator).\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid   \"Onboard Profiles\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid   \"Enable onboard profiles, which often control report rate and \"\n        \"keyboard lighting\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid   \"Polling Rate (ms)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid   \"Frequency of device polling, in milliseconds\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid   \"Divert crown events\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid   \"Divert G Keys\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid   \"Make G keys send GKEY HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid   \"May also make M keys and MR key send HID++ notifications\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Freespinning\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid   \"Key/Button Actions\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"Skift handlingen for tasten eller knappen.\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"Ændring af vigtige handlinger (for eksempel venstre museknap) kan \"\n        \"resultere i et ubrugeligt system.\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Diverted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid   \"Mouse Gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Regular\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid   \"Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"Følsomhed (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid   \"Off\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid   \"Disable keys\"\nmsgstr  \"Deaktiver taster\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"Deaktiver specifikke tastaturtaster.\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid   \"Set OS\"\nmsgstr  \"Indstil OS\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"Skift taster for at matche OS.\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid   \"Change Host\"\nmsgstr  \"Indstil vært\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"Skift forbindelse til en anden vært\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Performs a left click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Single tap\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Performs a right click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Double tap\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Performs a double click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Tap and drag\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid   \"Scroll with one finger\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scrolls.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Natural scrolling\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Thumbwheel\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid   \"Pixel zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid   \"Ratio zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Scale factor\"\nmsgstr  \"Skaleringsfaktor\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width\"\nmsgstr  \"Bredde\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height\"\nmsgstr  \"Højde\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Cursor speed.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Scale\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid   \"Gestures\"\nmsgstr  \"Gestusser\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid   \"Gestures Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid   \"Gesture params\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid   \"M-Key LEDs\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid   \"MR-Key LED\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Sidetone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid   \"Set sidetone level.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid   \"Equalizer\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid   \"Hz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid   \"Power Management\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid   \"No paired devices.\"\nmsgstr  \"Ingen forbundne enheder.\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"%(count)s parret enhed.\"\nmsgstr[1]       \"%(count)s parrede enheder.\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid   \"Battery: %(level)s\"\nmsgstr  \"Batteri: %(level)s\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid   \"Battery: %(percent)d%%\"\nmsgstr  \"Batteri: %(percent)d%%\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid   \"Lighting: %(level)s lux\"\nmsgstr  \"Belysning: %(level)s lux\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"Batteri: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"Batteri: %(percent)d%% (%(status)s)\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid   \"Permissions error\"\nmsgstr  \"Tilladelsesfejl\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid   \"Unpairing failed\"\nmsgstr  \"Frakobling mislykkedes\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"Mislykkedes med at bryde paret %{device} og %{receiver}.\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"Modtageren returnerede en fejl uden yderligere detaljer.\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:44\nmsgid   \"Additional Programming\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:45\nmsgid   \"GUI design\"\nmsgstr  \"GUI-design\"\n\n#: lib/solaar/ui/about.py:47\nmsgid   \"Testing\"\nmsgstr  \"Testing\"\n\n#: lib/solaar/ui/about.py:54\nmsgid   \"Logitech documentation\"\nmsgstr  \"Logitech-dokumentation\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid   \"Unpair\"\nmsgstr  \"Fjern parring\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid   \"Cancel\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Incomplete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid   \"Changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid   \"No changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid   \"Ignore this setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid   \"Working\"\nmsgstr  \"Succes\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"Læse-/skriveoperationen mislykkedes.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"Built-in rules\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"User-defined rules\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid   \"Rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid   \"Sub-rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid   \"[empty]\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Make changes permanent?\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid   \"Yes\"\nmsgstr  \"Ja\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid   \"No\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid   \"Save changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid   \"Discard changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid   \"Insert here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid   \"Insert above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid   \"Insert below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid   \"Insert new rule here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid   \"Insert new rule above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Insert new rule below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid   \"Paste here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid   \"Paste above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid   \"Paste below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid   \"Paste rule here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid   \"Paste rule above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Paste rule below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid   \"Paste rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid   \"Flatten\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Insert\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Or\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid   \"And\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid   \"Condition\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid   \"Feature\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid   \"Report\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid   \"Process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid   \"Mouse process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid   \"Modifiers\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid   \"Key\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid   \"KeyIsDown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid   \"Active\"\nmsgstr  \"Aktiv\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid   \"Device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid   \"Setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid   \"Test\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid   \"Test bytes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid   \"Mouse Gesture\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid   \"Action\"\nmsgstr  \"Handling\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid   \"Key press\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid   \"Mouse scroll\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid   \"Mouse click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Set\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid   \"Execute\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Later\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Insert new rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid   \"Delete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid   \"Negate\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid   \"Wrap with\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid   \"Cut\"\nmsgstr  \"Klip\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid   \"Paste\"\nmsgstr  \"Indsæt\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid   \"Copy\"\nmsgstr  \"Kopiér\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid   \"Number of seconds to delay.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid   \"Not\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid   \"MouseProcess\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid   \"Key down\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid   \"Key up\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid   \"Parameter\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid   \"begin (inclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid   \"end (exclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid   \"range\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid   \"minimum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid   \"maximum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid   \"mask\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid   \"type\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid   \"Add movement\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid   \"Add key\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid   \"Click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid   \"Depress\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid   \"Release\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid   \"Button\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid   \"Count and Action\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid   \"Add argument\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"Toggle\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"True\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid   \"False\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid   \"Unsupported setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid   \"Originating device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid   \"Name of host computer.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid   \"Value\"\nmsgstr  \"Værdi\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid   \"Item\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid   \"Change setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid   \"Setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid   \"offline\"\nmsgstr  \"afslået\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"%(receiver_name)s: parre ny enhed\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"left\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"right\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid   \"Pairing failed\"\nmsgstr  \"Parring mislykkedes\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"Sørg for, at din enhed er inden for rækkevidde og har en anstændig \"\n        \"batteriopladning.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"Der blev fundet en ny enhed, men den er ikke kompatibel med denne \"\n        \"modtager.\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"Flere parrede enheder end modtageren kan understøtte.\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"Ingen yderligere oplysninger er tilgængelige om fejlen.\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid   \"Found a new device:\"\nmsgstr  \"Fandt en ny enhed:\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"Den trådløse tilslutningen er ukryptert\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid   \"You may have to first turn the device off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid   \"Turn on the device you want to pair.\"\nmsgstr  \"Tænd for den enhed, du vil parre.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\\n\"\n        \"\\n\"\n        \"Denne modtager har %d parring tilbage.\"\nmsgstr[1]       \"\\n\"\n        \"\\n\"\n        \"Denne modtager har %d parringer tilbage.\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\\n\"\n        \"Annullering på dette tidspunkt bruger ikke en parring.\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid   \"No supported device found\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"Om %s\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"Afslut %s\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid   \"no receiver\"\nmsgstr  \"ingen modtager\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid   \"no status\"\nmsgstr  \"ingen status\"\n\n#: lib/solaar/ui/window.py:96\nmsgid   \"Scanning\"\nmsgstr  \"Søger\"\n\n#: lib/solaar/ui/window.py:129\nmsgid   \"Battery\"\nmsgstr  \"Batteri\"\n\n#: lib/solaar/ui/window.py:132\nmsgid   \"Wireless Link\"\nmsgstr  \"Trådløs tilslutning\"\n\n#: lib/solaar/ui/window.py:136\nmsgid   \"Lighting\"\nmsgstr  \"Belysning\"\n\n#: lib/solaar/ui/window.py:170\nmsgid   \"Show Technical Details\"\nmsgstr  \"Vis tekniske detaljer\"\n\n#: lib/solaar/ui/window.py:186\nmsgid   \"Pair new device\"\nmsgstr  \"Parre ny enhed\"\n\n#: lib/solaar/ui/window.py:205\nmsgid   \"Select a device\"\nmsgstr  \"Vælg en enhed\"\n\n#: lib/solaar/ui/window.py:322\nmsgid   \"Rule Editor\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Path\"\nmsgstr  \"Sti\"\n\n#: lib/solaar/ui/window.py:536\nmsgid   \"USB ID\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid   \"Serial\"\nmsgstr  \"Seriel\"\n\n#: lib/solaar/ui/window.py:545\nmsgid   \"Index\"\nmsgstr  \"Indeks\"\n\n#: lib/solaar/ui/window.py:547\nmsgid   \"Wireless PID\"\nmsgstr  \"Trådløs-PID\"\n\n#: lib/solaar/ui/window.py:549\nmsgid   \"Product ID\"\nmsgstr  \"Produkt-id\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Protocol\"\nmsgstr  \"Protokol\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Unknown\"\nmsgstr  \"Ukendt\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid   \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr  \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#: lib/solaar/ui/window.py:554\nmsgid   \"Polling rate\"\nmsgstr  \"Spørgerate\"\n\n#: lib/solaar/ui/window.py:565\nmsgid   \"Unit ID\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:576\nmsgid   \"none\"\nmsgstr  \"ingen\"\n\n#: lib/solaar/ui/window.py:577\nmsgid   \"Notifications\"\nmsgstr  \"Varsler\"\n\n#: lib/solaar/ui/window.py:621\nmsgid   \"No device paired.\"\nmsgstr  \"Ingen enhed parret.\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"Op til %(max_count)s enhed kan parres med denne modtager.\"\nmsgstr[1]       \"Op til %(max_count)s enheder kan parres med denne modtager.\"\n\n#: lib/solaar/ui/window.py:634\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"Kun en enhed kan parres med denne modtager.\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"Denne modtager har %d parring tilbage.\"\nmsgstr[1]       \"Denne modtager har %d parringer tilbage.\"\n\n#: lib/solaar/ui/window.py:692\nmsgid   \"Battery Voltage\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:694\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:696\nmsgid   \"Battery Level\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:698\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid   \"next reported \"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:708\nmsgid   \" and next level to be reported.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"last known\"\nmsgstr  \"sidst kendt\"\n\n#: lib/solaar/ui/window.py:724\nmsgid   \"encrypted\"\nmsgstr  \"kryptert\"\n\n#: lib/solaar/ui/window.py:726\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"Den trådløse forbindelse mellem denne enhed og dens modtager er \"\n        \"krypteret.\"\n\n#: lib/solaar/ui/window.py:728\nmsgid   \"not encrypted\"\nmsgstr  \"ukrypteret\"\n\n#: lib/solaar/ui/window.py:732\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"%(light_level)d lux\"\n\n#~ msgid        \"\\n\"\n#~      \"\\n\"\n#~      \"This receiver has %d pairing(s) remaining.\"\n#~ msgstr       \"\\n\"\n#~      \"\\n\"\n#~      \"Denne modtager har %d parring(er) tilbage.\"\n\n#~ msgid        \"Actions\"\n#~ msgstr       \"Handlinger\"\n\n#~ msgid        \"Automatically switch the mouse wheel between ratchet and \"\n#~      \"freespin mode.\\n\"\n#~      \"The mouse wheel is always free at 0, and always locked at 50\"\n#~ msgstr       \"Skift automatisk musehjulet mellem skralde og freespin-\"\n#~      \"tilstand.\\n\"\n#~      \"Musehjulet er altid frit ved 0, og altid låst ved 50\"\n\n#~ msgid        \"Count\"\n#~ msgstr       \"Antal\"\n\n#~ msgid        \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr       \"Slår i praksis af tommelrulling i Linux.\"\n\n#~ msgid        \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr       \"Slår i praksis af hjulrulling i Linux.\"\n\n#~ msgid        \"For more information see the Solaar installation directions\\n\"\n#~      \"at https://pwr-solaar.github.io/Solaar/installation\"\n#~ msgstr       \"Yderligere oplysninger finder du i Installationsvejledningen \"\n#~      \"til Solaar\\n\"\n#~      \"på https://pwr-solaar.github.io/Solaar/installation\"\n\n#, python-format\n#~ msgid        \"Found a Logitech Receiver (%s), but did not have permission \"\n#~      \"to open it.\"\n#~ msgstr       \"Fundet en Logitech-modtager (%s), men havde ikke tilladelse \"\n#~      \"til at åbne den.\"\n\n#~ msgid        \"HID++ Scrolling\"\n#~ msgstr       \"HID++ rulling\"\n\n#~ msgid        \"HID++ Thumb Scrolling\"\n#~ msgstr       \"HID++ tommelrulling\"\n\n#~ msgid        \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr       \"HID ++ -tilstand til vandret rulling med tommelhjulet.\"\n\n#~ msgid        \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr       \"HID++ tilstand til lodret rulling med hjulet.\"\n\n#~ msgid        \"High Resolution Scrolling\"\n#~ msgstr       \"Høyfølsom rulling\"\n\n#~ msgid        \"High Resolution Wheel Invert\"\n#~ msgstr       \"Inverter høyfølsom rulling\"\n\n#~ msgid        \"High-sensitivity wheel invert direction for vertical scroll.\"\n#~ msgstr       \"Inverter retning til høyfølsom lodret rulling med hjulet.\"\n\n#~ msgid        \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr       \"Hvis enheden allerede er tændt, slå den fra og til igen.\"\n\n#~ msgid        \"If you've just installed Solaar, try removing the receiver \"\n#~      \"and plugging it back in.\"\n#~ msgstr       \"Hvis du lige har installeret Solaar, kan du prøve at fjerne \"\n#~      \"modtageren og tilslutte den igen.\"\n\n#~ msgid        \"Invert thumb scroll direction.\"\n#~ msgstr       \"Inverter retning på tommelrulling.\"\n\n#~ msgid        \"No Logitech receiver found\"\n#~ msgstr       \"Der blev ikke fundet nogen Logitech-modtager\"\n\n#~ msgid        \"Shows status of devices connected\\n\"\n#~      \"through wireless Logitech receivers.\"\n#~ msgstr       \"Viser status for enheder, der er tilsluttet\\n\"\n#~      \"via trådløse Logitech-modtagere.\"\n\n#~ msgid        \"Smooth Scrolling\"\n#~ msgstr       \"Glat rulling\"\n\n#~ msgid        \"Solaar depends on a udev file that is not present\"\n#~ msgstr       \"Solaar er afhængig af en udev-fil, der ikke er til stede\"\n\n#~ msgid        \"The receiver only supports %d paired device(s).\"\n#~ msgstr       \"Modtageren understøtter kun %d parrede enhed(er).\"\n\n#~ msgid        \"The receiver was unplugged.\"\n#~ msgstr       \"Mottakeren fjernedes.\"\n\n#~ msgid        \"The wireless link between this device and its receiver is \"\n#~      \"not encrypted.\\n\"\n#~      \"\\n\"\n#~      \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~      \"security issue.\\n\"\n#~      \"\\n\"\n#~      \"It is, however, a major security issue for text-input devices \"\n#~      \"(keyboards, numpads),\\n\"\n#~      \"because typed text can be sniffed inconspicuously by 3rd parties \"\n#~      \"within range.\"\n#~ msgstr       \"Den trådløse forbindelse mellem denne enhed og dens modtager \"\n#~      \"er ikke krypteret.\\n\"\n#~      \"\\n\"\n#~      \"For pegeenheder (mus, trackballs, pegefelter) er dette et mindre \"\n#~      \"sikkerhedsproblem.\\n\"\n#~      \"\\n\"\n#~      \"Det er imidlertid et vigtigt sikkerhedsproblem for tekstinputenheder \"\n#~      \"(tastaturer, numpads),\\n\"\n#~      \"fordi maskinskrevet tekst kan sniffes upåfaldende af 3rd parter \"\n#~      \"inden for rækkevidde.\"\n\n#~ msgid        \"This receiver has %d pairing(s) remaining.\"\n#~ msgstr       \"Denne modtager har %d parring(er) tilbage.\"\n\n#~ msgid        \"Thumb Scroll Invert\"\n#~ msgstr       \"Inverter tommelrulling\"\n\n#~ msgid        \"USB id\"\n#~ msgstr       \"USB-id\"\n\n#~ msgid        \"Unexpected device number (%s) in notification %s.\"\n#~ msgstr       \"Uventet enhedsnummer (%s) i varsel %s.\"\n\n#~ msgid        \"Wheel Resolution\"\n#~ msgstr       \"Hjulopløsning\"\n\n#~ msgid        \"height\"\n#~ msgstr       \"højde\"\n\n#~ msgid        \"next \"\n#~ msgstr       \"næste \"\n\n#~ msgid        \"unknown\"\n#~ msgstr       \"ukendt\"\n\n#~ msgid        \"width\"\n#~ msgstr       \"bredde\"\n"
  },
  {
    "path": "po/de.po",
    "content": "# German translations for solaar package.\n# Copyright (C) 2014 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2014.\n#\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 1.0.1\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n        \"PO-Revision-Date: 2023-07-07 11:06+0200\\n\"\n        \"Last-Translator: Daniel Frost <one@frostinfo.de>\\n\"\n        \"Language-Team: none\\n\"\n        \"Language: de\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=2; plural=n != 1;\\n\"\n        \"X-Launchpad-Export-Date: 2021-04-17 16:52+0000\\n\"\n        \"X-Generator: Poedit 3.3.2\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid   \"Bolt Receiver\"\nmsgstr  \"Bolt Empfänger\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid   \"Unifying Receiver\"\nmsgstr  \"Unifying Empfänger\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid   \"Nano Receiver\"\nmsgstr  \"Nano Empfänger\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"Lightspeed Empfänger\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"EX100 Empfänger 27 Mhz\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"empty\"\nmsgstr  \"entladen\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"critical\"\nmsgstr  \"kritisch\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"low\"\nmsgstr  \"niedrig\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"average\"\nmsgstr  \"mittel\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid   \"good\"\nmsgstr  \"gut\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"full\"\nmsgstr  \"voll\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"discharging\"\nmsgstr  \"entlädt\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"recharging\"\nmsgstr  \"lädt wieder auf\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid   \"charging\"\nmsgstr  \"lädt\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"not charging\"\nmsgstr  \"lädt nicht\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"almost full\"\nmsgstr  \"nahezu voll\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"charged\"\nmsgstr  \"geladen\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"slow recharge\"\nmsgstr  \"langsames Aufladen\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"invalid battery\"\nmsgstr  \"unzulässiger/defekter Akku\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"thermal error\"\nmsgstr  \"thermischer Fehler\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"error\"\nmsgstr  \"Fehler\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid   \"standard\"\nmsgstr  \"standard\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"fast\"\nmsgstr  \"schnell\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"slow\"\nmsgstr  \"langsam\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid   \"device timeout\"\nmsgstr  \"Geräte Zeitüberschreitung\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid   \"device not supported\"\nmsgstr  \"nicht unterstütztes Gerät\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"too many devices\"\nmsgstr  \"zu viele Geräte\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"sequence timeout\"\nmsgstr  \"Zeitüberschreitung im Ablauf\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid   \"Firmware\"\nmsgstr  \"Firmware\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Bootloader\"\nmsgstr  \"Bootloader\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Hardware\"\nmsgstr  \"Hardware\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Other\"\nmsgstr  \"Andere\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Left Button\"\nmsgstr  \"Linke Taste\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"Right Button\"\nmsgstr  \"Rechte Taste\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Middle Button\"\nmsgstr  \"Mittlere Taste\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Back Button\"\nmsgstr  \"Zurück Taste\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Forward Button\"\nmsgstr  \"Vorwärts Taste\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"Gestentaste\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Smart Shift\"\nmsgstr  \"Smart Shift\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"DPI Switch\"\nmsgstr  \"DPI Schalter\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Left Tilt\"\nmsgstr  \"Links kippen\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Right Tilt\"\nmsgstr  \"Rechts kippen\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Left Click\"\nmsgstr  \"Linksklick\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Right Click\"\nmsgstr  \"Rechtsklick\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"Maus mittlere Taste\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"Mouse Back Button\"\nmsgstr  \"Maus \\\"Zurück\\\" Taste\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"Maus \\\"Vorwärts\\\"\\n\"\n        \" Taste\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"Gestentaste-Navigation\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"Maus \\\"Links scrollen\\\" Taste\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"Maus \\\"Rechts scrollen\\\" Taste\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid   \"pressed\"\nmsgstr  \"gedrückt\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid   \"released\"\nmsgstr  \"losgelassen\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is closed\"\nmsgstr  \"Koppelsperre ist inaktiv\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is open\"\nmsgstr  \"Koppelsperre ist aktiv\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is closed\"\nmsgstr  \"Entdeckungssperre ist inaktiv\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is open\"\nmsgstr  \"Entdeckungssperre ist aktiv\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid   \"connected\"\nmsgstr  \"verbunden\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid   \"disconnected\"\nmsgstr  \"nicht verbunden\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid   \"unpaired\"\nmsgstr  \"nicht gekoppelt\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid   \"powered on\"\nmsgstr  \"eingeschaltet\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid   \"register\"\nmsgstr  \"registrieren\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid   \"feature\"\nmsgstr  \"Feature\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid   \"Swap Fx function\"\nmsgstr  \"Fn-Tastenbelegung umkehren\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"Wenn aktiviert, dann behalten die Tasten F1-F12 ihre \"\n        \"Sonderbelegung.\\n\"\n        \"Die jeweilige Standardbelegung kann über die FN-Taste aktiviert \"\n        \"werden.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"Wenn nicht aktiviert, dann behalten die Tasten F1-F12 ihre \"\n        \"Standardbelegung.\\n\"\n        \"Die jeweilige Sonderbelegung kann über die FN-Taste aktiviert werden.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid   \"Hand Detection\"\nmsgstr  \"Handerkennung\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"Schaltet die Beleuchtung ein, wenn sich die Hand über der Tastatur \"\n        \"befindet.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"Weiches Mausrad-Scrollen\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"Hohe Empfindlichkeit für vertikales Scrollen mit dem Mausrad.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid   \"Side Scrolling\"\nmsgstr  \"Seitliches Scrollen\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"Wenn ausgeschaltet, werden durch seitliches Kippen des Mausrads \"\n        \"benutzer-\\n\"\n        \"definierte Maustastenereignisse gesendet, anstatt der vorgegebenen \"\n        \"Seitlich-Scrollen-\\n\"\n        \"Ereignisse.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"Empfindlichkeit (DPI - ältere Mäuse)\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"Mauszeigerempfindlichkeit\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid   \"Backlight\"\nmsgstr  \"Hintergrundbeleuchtung\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"Die Beleuchtungszeit für die Tastatur einstellen.\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid   \"Turn illumination on or off on keyboard.\"\nmsgstr  \"Schaltet die Tastaturbeleuchtung an oder aus.\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"Hohe Auflösung für Mausrad-Scrollen\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"Aktivieren zum Ignorieren, falls Scrollen ungewöhnlich langsam oder \"\n        \"schnell ist\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"Mausrad Umleitung\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"Lasse das Mausrad LOWRES_WHEEL HID++ Nachrichten senden (diese lösen \"\n        \"Solaar Regeln aus, werden sonst aber ignoriert).\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"Mausrad-Scroll-Richtung\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"Kehrt die vertikale Scroll-Richtung des Mausrads um.\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"Auflösung für Mausrad-Scrollen\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"Lasse das Mausrad HIRES_WHEEL HID++ Nachrichten senden (diese lösen \"\n        \"Solaar Regeln aus, werden sonst aber ignoriert).\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"Empfindlichkeit (Zeigergeschwindigkeit)\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"Geschwindigkeits-Multiplikator für die Maus (256 ist der normale \"\n        \"Multiplikator).\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"Daumenrad Umleitung\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"Lasse das Daumenrad THUMB_WHEEL HID++ Nachrichten senden (diese \"\n        \"lösen Solaar Regeln aus, werden sonst aber ignoriert).\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"Daumenrad-Scroll-Richtung\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"Kehrt die Scroll-Richtung des Daumenrads um.\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid   \"Onboard Profiles\"\nmsgstr  \"Onboard-Profile\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid   \"Enable onboard profiles, which often control report rate and \"\n        \"keyboard lighting\"\nmsgstr  \"Schaltet Onboard-Profile an, welche oft die Wiederholrate und die \"\n        \"Tastenbeleuchtung steuern\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid   \"Polling Rate (ms)\"\nmsgstr  \"Abtastrate (ms)\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid   \"Frequency of device polling, in milliseconds\"\nmsgstr  \"Frequenz der Geräteabtastung, in Millisekunden\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"Onboard-Profile müssen eventuell deaktivert sein damit dies \"\n        \"funktioniert.\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid   \"Divert crown events\"\nmsgstr  \"Drehregler-Ereignisse umleiten\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Das Senden von CROWN-HID++-Mitteilungen beim Bedienen des \"\n        \"Drehreglers erzwingen (diese lösen Solaar Regeln aus, werden sonst \"\n        \"aber ignoriert).\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"Crown weiches scrollen\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"Aktiviere Crown weiches scrollen\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid   \"Divert G Keys\"\nmsgstr  \"G-Tasten umleiten\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid   \"Make G keys send GKEY HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Das Senden von GKEY-HID++-Mitteilungen beim Drücken der G-Tasten \"\n        \"erzwingen (diese lösen Solaar Regeln aus, werden sonst aber \"\n        \"ignoriert).\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid   \"May also make M keys and MR key send HID++ notifications\"\nmsgstr  \"Die M und MR Tasten senden ggf. auch HID++ Benachrichtigungen\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"Mausrad-Rastfunktion\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"Schaltet beim Mausrad um zwischen geschwindigkeitskontrolliert mit \"\n        \"einrasten und immer freilaufend.\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Freespinning\"\nmsgstr  \"Freilaufen\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Ratcheted\"\nmsgstr  \"Einrastend\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"Mausrad-Rastgeschwindigkeit\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"Mausrad automatisch zwischen einrastendem und freilaufendem Modus \"\n        \"umschalten.\\n\"\n        \"Das Mausrad läuft bei 0 stets frei und verhält sich bei 50 stets \"\n        \"einrastend.\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid   \"Key/Button Actions\"\nmsgstr  \"Tasten-/Maustastenaktionen\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"Die Aktion für die Taste oder die Maustaste ändern.\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"Durch Umleitung überschrieben.\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"Das Ändern wichtiger Aktionen (wie z.B. für die linke Maustaste) \"\n        \"kann zu einem unbenutzbaren System führen.\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"Taste/Maustaste umleiten\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"Die Taste/Maustaste sendet HID++-Mitteilungen (umgeleitet) oder \"\n        \"initiiert Mausgesten oder Gleiten DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Diverted\"\nmsgstr  \"Umgeleitet\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid   \"Mouse Gestures\"\nmsgstr  \"Mausgesten\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Regular\"\nmsgstr  \"Normal\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid   \"Sliding DPI\"\nmsgstr  \"Gleiten DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"Empfindlichkeit (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"Umschaltung Empfindlichkeit\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"Tauscht die aktuelle Empfindlichkeit und die abgespeicherte \"\n        \"Empfindlichkeit wenn die Taste gedrückt wird.\\n\"\n        \"Falls keine gespeicherte Empfindlichkeit vorhanden ist, wird die \"\n        \"aktuelle Empfindlichkeit abgespeichert\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid   \"Off\"\nmsgstr  \"Aus\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid   \"Disable keys\"\nmsgstr  \"Tasten abschalten\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"Bestimmte Tastatur-Tasten abschalten.\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"Deaktiviert die %s-Taste.\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid   \"Set OS\"\nmsgstr  \"Betriebssystem auswählen\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"Ändert Tasten so, dass Sie zum BS passen.\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid   \"Change Host\"\nmsgstr  \"Anderen Empfänger wählen\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"Verbindung zu einem anderen Empfänger umschalten\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Performs a left click.\"\nmsgstr  \"Führt einen Linksklick aus.\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Single tap\"\nmsgstr  \"Einfaches Tippen\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Performs a right click.\"\nmsgstr  \"Führt einen Rechtsklick aus.\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"Einfaches Tippen mit zwei Fingern\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"Einfaches Tippen mit drei Fingern\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Double tap\"\nmsgstr  \"Doppeltes Tippen\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Performs a double click.\"\nmsgstr  \"Führt einen Doppelklick aus.\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"Doppeltes Tippen mit zwei Fingern\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"Doppeltes Tippen mit drei Fingern\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"Zieht Objekte durch Ziehen des Fingers nach doppeltem Tippen.\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Tap and drag\"\nmsgstr  \"Tippen-und-Ziehen\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"Zieht Objekte durch Ziehen der Finger nach doppeltem Tippen.\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"Tippen und mit zwei Fingern ziehen\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"Tippen und mit drei Fingern ziehen\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"Schaltet Tipp- und Bildschirmrand-Gesten ab (entspricht dem Drücken \"\n        \"von Fn+Linksklick).\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"Tipp- und Bildschirmrand-Gesten abschalten\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid   \"Scroll with one finger\"\nmsgstr  \"Mit einem Finger scrollen\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scrolls.\"\nmsgstr  \"Scrollt.\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"Mit zwei Fingern scrollen\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"Horizontales Scrollen mit zwei Fingern\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"Scrollt horizontal.\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"Vertikales Scrollen mit zwei Fingern\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"Scrollt vertikal.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"Kehrt die Scroll-Richtung um.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Natural scrolling\"\nmsgstr  \"Natürlicher Bildlauf\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"Aktiviert das Daumenrad.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Thumbwheel\"\nmsgstr  \"Daumenrad\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"Vom oberen Bildschirmrand wischen\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"Vom linken Bildschirmrand wischen\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"Vom rechten Bildschirmrand wischen\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"Vom unteren Bildschirmrand wischen\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"Mit zwei Fingern vom linken Bildschirmrand wischen\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"Mit zwei Fingern vom rechten Bildschirmrand wischen\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"Mit zwei Fingern vom unteren Bildschirmrand wischen\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"Mit zwei Fingern vom oberen Bildschirmrand wischen\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"Kneifgeste zum Verkleinern; Spreizgeste zum Vergrößern.\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"Vergrößerung mit zwei Fingern ändern.\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"Kneifgeste zum Verkleinern.\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"Spreizgeste zum Vergrößern.\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"Vergrößerung mit drei Fingern ändern.\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"Vergrößerung mit zwei Fingern\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid   \"Pixel zone\"\nmsgstr  \"Pixel Zone\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid   \"Ratio zone\"\nmsgstr  \"Verhältnis Zone\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Scale factor\"\nmsgstr  \"Skalierungsfaktor\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"Stellt die Cursorgeschwindigkeit ein.\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left\"\nmsgstr  \"Links\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"Äußerste linke Koordinate.\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom\"\nmsgstr  \"Ende\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"Ende Koordinate.\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width\"\nmsgstr  \"Breite\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width.\"\nmsgstr  \"Breite.\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height\"\nmsgstr  \"Höhe\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height.\"\nmsgstr  \"Höhe.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Cursor speed.\"\nmsgstr  \"Zeigergeschwindigkeit.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Scale\"\nmsgstr  \"Skalierung\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid   \"Gestures\"\nmsgstr  \"Gesten\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"Das Maus-/Tastfeldverhalten einstellen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid   \"Gestures Diversion\"\nmsgstr  \"Gesten Umleitung\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"Maus/Tastfeldgesten umleiten.\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid   \"Gesture params\"\nmsgstr  \"Gestenparameter\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"Numerische Parameter einer Maus/eines Tastfelds ändern.\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid   \"M-Key LEDs\"\nmsgstr  \"M-Taste LED's\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"Steuert die M-Tasten LED's.\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"G Tasten müssen evtl. umgeleitet sein um zu funktionieren.\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"Beleuchtet die %s Tasten.\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid   \"MR-Key LED\"\nmsgstr  \"MR-Taste LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"Steuert die MR-Taste LED.\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"Dauerhafte Tasten-/Maustastenzuordnung\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"Ändert die Zuordung für die Taste/Maustaste dauerhaft.\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"Änderungen an wichtigen Tasten oder Maustasten (wie an der linken \"\n        \"Maustaste) können zu einem unbenutzbaren System führen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Sidetone\"\nmsgstr  \"Nebenton\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid   \"Set sidetone level.\"\nmsgstr  \"Setze Nebentonlautstärke.\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid   \"Equalizer\"\nmsgstr  \"Equalizer\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"Setze Equalizerlautstärke.\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid   \"Hz\"\nmsgstr  \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid   \"Power Management\"\nmsgstr  \"Energieverwaltung\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"Ausschalten in Minuten (0 für nie)\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid   \"No paired devices.\"\nmsgstr  \"Keine gekoppelten Geräte.\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"%(count)s gekoppeltes Gerät.\"\nmsgstr[1]       \"%(count)s gekoppelte Geräte.\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid   \"Battery: %(level)s\"\nmsgstr  \"Akku: %(level)s\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid   \"Battery: %(percent)d%%\"\nmsgstr  \"Akku: %(percent)d%%\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid   \"Lighting: %(level)s lux\"\nmsgstr  \"Beleuchtung: %(level)s lux\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"Akku: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"Akku: %(percent)d%% (%(status)s)\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid   \"Permissions error\"\nmsgstr  \"Zugriffsfehler\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"Es wurde ein Logitech Empfänger oder Gerät (%s) gefunden, aber es \"\n        \"fehlen die Berechtigungen dieses zu öffnen.\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"Falls du Solaar gerade erst installiert hast, versuche den Empfänger \"\n        \"oder das Geräte zu trennen und dann erneut zu verbinden.\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"Kann nicht mit dem Gerät verbinden Fehler\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"Ein Logitech Empfänger oder Gerät wurde auf %s gefunden, aber beim \"\n        \"Verbinden ist ein Fehler aufgetreten.\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"Versuche die Verbindung zu dem Geräte zu trennen und neu zu \"\n        \"verbinden oder dieses aus- und wieder einzuschalten.\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid   \"Unpairing failed\"\nmsgstr  \"Entkopplung fehlgeschlagen\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"Kopplung zwischen Gerät %{device} und Empfänger %{receiver} konnte \"\n        \"nicht gelöst werden.\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"Der Empfänger gab einen Fehler zurück, ohne weitere Details.\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"Ein anderer Solaar-Prozess läuft bereits deshalb nur dessen Fenster \"\n        \"in den Vordergrund holen\"\n\n#: lib/solaar/ui/about.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"Verwaltet Logitech Empfänger, Tastaturen, Mäuse und Grafiktablets.\"\n\n#: lib/solaar/ui/about.py:44\nmsgid   \"Additional Programming\"\nmsgstr  \"Zusätzliche Programmierung\"\n\n#: lib/solaar/ui/about.py:45\nmsgid   \"GUI design\"\nmsgstr  \"GUI Design\"\n\n#: lib/solaar/ui/about.py:47\nmsgid   \"Testing\"\nmsgstr  \"Tester\"\n\n#: lib/solaar/ui/about.py:54\nmsgid   \"Logitech documentation\"\nmsgstr  \"Logitech-Dokumentation\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid   \"Unpair\"\nmsgstr  \"Entkoppeln\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid   \"Cancel\"\nmsgstr  \"Abbrechen\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"Abgeschlossen - ENTER zu ändern\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Incomplete\"\nmsgstr  \"Unvollständig\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"%d Wert\"\nmsgstr[1]       \"%d Werte\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid   \"Changes allowed\"\nmsgstr  \"Änderungen erlaubt\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid   \"No changes allowed\"\nmsgstr  \"Änderungen nicht erlaubt\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid   \"Ignore this setting\"\nmsgstr  \"Diese Einstellung ignorieren\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid   \"Working\"\nmsgstr  \"Beschäftigt\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"Lese-/Schreiboperation fehlgeschlagen.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"Built-in rules\"\nmsgstr  \"Integrierte Regeln\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"User-defined rules\"\nmsgstr  \"Benutzerdefinierte Regeln\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid   \"Rule\"\nmsgstr  \"Regel\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid   \"Sub-rule\"\nmsgstr  \"Unterregel\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid   \"[empty]\"\nmsgstr  \"[leer]\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"Solaar-Regelbearbeitung\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Make changes permanent?\"\nmsgstr  \"Änderungen dauerhaft anwenden?\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid   \"Yes\"\nmsgstr  \"Ja\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid   \"No\"\nmsgstr  \"Nein\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"Wenn Sie »Nein« wählen, gehen alle Änderungen beim Schließen von \"\n        \"Solaar verloren.\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid   \"Save changes\"\nmsgstr  \"Änderungen speichern\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid   \"Discard changes\"\nmsgstr  \"Änderungen verwerfen\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid   \"Insert here\"\nmsgstr  \"Hier hinzufügen\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid   \"Insert above\"\nmsgstr  \"Darüber hinzufügen\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid   \"Insert below\"\nmsgstr  \"Darunter hinzufügen\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid   \"Insert new rule here\"\nmsgstr  \"Neue Regel hier hinzufügen\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid   \"Insert new rule above\"\nmsgstr  \"Neue Regel darüber hinzufügen\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Insert new rule below\"\nmsgstr  \"Neue Regel darunter hinzufügen\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid   \"Paste here\"\nmsgstr  \"Hier einfügen\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid   \"Paste above\"\nmsgstr  \"Darüber einfügen\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid   \"Paste below\"\nmsgstr  \"Darunter einfügen\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid   \"Paste rule here\"\nmsgstr  \"Regel hier einfügen\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid   \"Paste rule above\"\nmsgstr  \"Regel darüber einfügen\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Paste rule below\"\nmsgstr  \"Regel darunter einfügen\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid   \"Paste rule\"\nmsgstr  \"Regel einfügen\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid   \"Flatten\"\nmsgstr  \"Einrückung aufheben\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Insert\"\nmsgstr  \"Hinzufügen\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Or\"\nmsgstr  \"Oder\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid   \"And\"\nmsgstr  \"Und\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid   \"Condition\"\nmsgstr  \"Bedingung\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid   \"Feature\"\nmsgstr  \"Funktion\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid   \"Report\"\nmsgstr  \"Rückgabewert\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid   \"Process\"\nmsgstr  \"Prozessname (Anwendung)\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid   \"Mouse process\"\nmsgstr  \"Maus Prozess\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid   \"Modifiers\"\nmsgstr  \"Zusatztasten\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid   \"Key\"\nmsgstr  \"Taste\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid   \"KeyIsDown\"\nmsgstr  \"TasteIstGedrückt\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid   \"Active\"\nmsgstr  \"Aktiv\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid   \"Device\"\nmsgstr  \"Gerät\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid   \"Setting\"\nmsgstr  \"Einstellung\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid   \"Test\"\nmsgstr  \"Prüfwert/Ereignis\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid   \"Test bytes\"\nmsgstr  \"Prüfwert Bytes\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid   \"Mouse Gesture\"\nmsgstr  \"Mausgeste\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid   \"Action\"\nmsgstr  \"Aktion\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid   \"Key press\"\nmsgstr  \"Tastendruck\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid   \"Mouse scroll\"\nmsgstr  \"Mausrad-Scrollen\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid   \"Mouse click\"\nmsgstr  \"Mausklick\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Set\"\nmsgstr  \"Aktivieren\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid   \"Execute\"\nmsgstr  \"Ausführen\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Later\"\nmsgstr  \"Später\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Insert new rule\"\nmsgstr  \"Neue Regel hinzufügen\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid   \"Delete\"\nmsgstr  \"Löschen\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid   \"Negate\"\nmsgstr  \"Negieren\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid   \"Wrap with\"\nmsgstr  \"Einrücken unter\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid   \"Cut\"\nmsgstr  \"Ausschneiden\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid   \"Paste\"\nmsgstr  \"Einfügen\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid   \"Copy\"\nmsgstr  \"Kopieren\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"Diese Regelbearbeitung unterstützt die ausgewählte Regelkomponente \"\n        \"noch nicht.\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid   \"Number of seconds to delay.\"\nmsgstr  \"Angabe der Sekunden für die Verzögerung.\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid   \"Not\"\nmsgstr  \"Nicht\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"Aktiver X11 Prozess. Nur zur Verwendung mit X11.\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"X11 Mausprozess. Nur zur Verwendung mit X11.\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid   \"MouseProcess\"\nmsgstr  \"Mausprozess\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"Funktionsname der Benachrichtigung, die die Regelverarbeitung \"\n        \"auslöst.\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"Aktive Keyboardanpassung. Unter Wayland nicht immer verfügbar.\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"Umgeleitete Taste oder Maustaste ist gedrückt oder losgelassen.\\n\"\n        \"Verwende die Tasten-/Maustastenumleitungs- und G \"\n        \"Tastenumleitungseinstellungen um Tasten sowie Maustasten umzuleiten.\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid   \"Key down\"\nmsgstr  \"Taste gedrückt\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid   \"Key up\"\nmsgstr  \"Taste losgelassen\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"Umgeleitete Taste oder Maustaste ist unten. Verwende die Tasten-/\"\n        \"Maustastenumleitungs- und G Tastenumleitungseinstellungen um Tasten \"\n        \"sowie Maustasten umzuleiten.\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid   \"Parameter\"\nmsgstr  \"Parameter\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid   \"begin (inclusive)\"\nmsgstr  \"Anfang (inklusive)\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid   \"end (exclusive)\"\nmsgstr  \"Ende (exklusive)\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid   \"range\"\nmsgstr  \"Bereich\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid   \"minimum\"\nmsgstr  \"Minimum\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid   \"maximum\"\nmsgstr  \"Maximum\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"Bytes %(0)d bis %(1)d, beginnend von %(2)d bis %(3)d\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid   \"mask\"\nmsgstr  \"Maske\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"Bytes %(0)d bis %(1)d, Maske %(2)d\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid   \"type\"\nmsgstr  \"Typ\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"Mausgeste mit optionaler initiierender Maustaste gefolgt von keiner \"\n        \"oder mehreren Bewegungen.\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid   \"Add movement\"\nmsgstr  \"Bewegung hinzufügen\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"Simuliert einen kombinierten Mausklick oder Tastendruck bzw. \"\n        \"loslassen einer Taste.\\n\"\n        \"Benötigt unter Wayland Schreibzugriff auf /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid   \"Add key\"\nmsgstr  \"Weitere Taste hinzufügen\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid   \"Click\"\nmsgstr  \"Linksklick\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid   \"Depress\"\nmsgstr  \"Abgesenkt\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid   \"Release\"\nmsgstr  \"Loslassen\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"Simuliert eine Mausradbewegung. Benötigt unter Wayland \"\n        \"Schreibzugriff auf /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"Simuliert einen Mausklick. Benötigt unter Wayland Schreibzugriff \"\n        \"auf /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid   \"Button\"\nmsgstr  \"Maustaste\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid   \"Count and Action\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"Einen Befehl mit Parametern ausführen.\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid   \"Add argument\"\nmsgstr  \"Argument hinzufügen\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"Toggle\"\nmsgstr  \"Umschalten\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"True\"\nmsgstr  \"Wahr\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid   \"False\"\nmsgstr  \"Falsch\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid   \"Unsupported setting\"\nmsgstr  \"Nicht unterstützte Einstellung\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid   \"Originating device\"\nmsgstr  \"Quellgerät\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"Das Gerät ist aktiv und die Einstellungen können geändert werden.\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid   \"Name of host computer.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid   \"Value\"\nmsgstr  \"Wert\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid   \"Item\"\nmsgstr  \"Item\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid   \"Change setting on device\"\nmsgstr  \"Einstellung auf dem Gerät ändern\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid   \"Setting on device\"\nmsgstr  \"Einstellung auf dem Gerät\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid   \"offline\"\nmsgstr  \"offline\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"%(receiver_name)s: neues Gerät koppeln\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"Gib das Passwort ein auf %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"Gib %(passcode)s ein und drücke die ENTER Taste.\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"left\"\nmsgstr  \"links\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"right\"\nmsgstr  \"rechts\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"Drücke %(code)s\\n\"\n        \"und drücke dann die links und rechts Tasten gleichzeitig.\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid   \"Pairing failed\"\nmsgstr  \"Kopplung fehlgeschlagen\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"Überprüfen Sie, ob sich das Gerät in Reichweite befindet und der \"\n        \"Akku ausreichend geladen bzw. die Batterie voll genug ist.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"Es wurde ein neues Gerät festgestellt, aber es ist nicht mit diesem \"\n        \"Empfänger kompatibel.\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"Es sind mehr Geräte gekoppelt als der Empfänger unterstützt.\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"Es gibt keine näheren Informationen zu diesem Fehler.\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid   \"Found a new device:\"\nmsgstr  \"Neues Gerät gefunden:\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"Die drahtlose Verbindung ist nicht verschlüsselt\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"Unifying Empfänger sind nur mit Unifying Geräten kompatibel.\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"Bolt Empfänger sind nur mit Bolt Geräten kompatibel.\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"Andere Empfänger sind nur mit wenigen Geräten kompatibel.\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"Das Gerät darf nicht mit mit anderen, eingeschalteten Empfängern in \"\n        \"der Nähe gekoppelt sein.\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"Drücke die Kopplungstaste bis das Kopplungslicht schnell blinkt.\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid   \"You may have to first turn the device off and on again.\"\nmsgstr  \"Eventuell muss das Gerät dazu aus- und wieder eingeschaltet werden.\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid   \"Turn on the device you want to pair.\"\nmsgstr  \"Schalten Sie das zu koppelnde Gerät ein.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"Falls das Gerät eingeschaltet ist, schalte es aus und wieder ein.\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\\n\"\n        \"\\n\"\n        \"Dieser Empfänger kann an %d weiteres Gerät gekoppelt werden.\"\nmsgstr[1]       \"\\n\"\n        \"\\n\"\n        \"Dieser Empfänger kann an %d weitere Geräte gekoppelt werden.\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\\n\"\n        \"Ein Abbruch zu diesem Zeitpunkt wird keine Kopplung aufbrauchen.\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid   \"No supported device found\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"Info zu %s\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"%s beenden\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid   \"no receiver\"\nmsgstr  \"kein Empfänger\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid   \"no status\"\nmsgstr  \"kein Status\"\n\n#: lib/solaar/ui/window.py:96\nmsgid   \"Scanning\"\nmsgstr  \"Scanne\"\n\n#: lib/solaar/ui/window.py:129\nmsgid   \"Battery\"\nmsgstr  \"Akku\"\n\n#: lib/solaar/ui/window.py:132\nmsgid   \"Wireless Link\"\nmsgstr  \"Drahtlose Verbindung\"\n\n#: lib/solaar/ui/window.py:136\nmsgid   \"Lighting\"\nmsgstr  \"Beleuchtung\"\n\n#: lib/solaar/ui/window.py:170\nmsgid   \"Show Technical Details\"\nmsgstr  \"Technische Details anzeigen\"\n\n#: lib/solaar/ui/window.py:186\nmsgid   \"Pair new device\"\nmsgstr  \"Neues Gerät koppeln\"\n\n#: lib/solaar/ui/window.py:205\nmsgid   \"Select a device\"\nmsgstr  \"Gerät auswählen\"\n\n#: lib/solaar/ui/window.py:322\nmsgid   \"Rule Editor\"\nmsgstr  \"Regeln bearbeiten\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Path\"\nmsgstr  \"Pfad\"\n\n#: lib/solaar/ui/window.py:536\nmsgid   \"USB ID\"\nmsgstr  \"USB-ID\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid   \"Serial\"\nmsgstr  \"Seriennummer\"\n\n#: lib/solaar/ui/window.py:545\nmsgid   \"Index\"\nmsgstr  \"Index\"\n\n#: lib/solaar/ui/window.py:547\nmsgid   \"Wireless PID\"\nmsgstr  \"Wireless PID\"\n\n#: lib/solaar/ui/window.py:549\nmsgid   \"Product ID\"\nmsgstr  \"Produkt-ID\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Protocol\"\nmsgstr  \"Protokoll\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Unknown\"\nmsgstr  \"Unbekannt\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid   \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr  \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#: lib/solaar/ui/window.py:554\nmsgid   \"Polling rate\"\nmsgstr  \"Abfragerate\"\n\n#: lib/solaar/ui/window.py:565\nmsgid   \"Unit ID\"\nmsgstr  \"Geräte ID\"\n\n#: lib/solaar/ui/window.py:576\nmsgid   \"none\"\nmsgstr  \"keine\"\n\n#: lib/solaar/ui/window.py:577\nmsgid   \"Notifications\"\nmsgstr  \"Mitteilungen\"\n\n#: lib/solaar/ui/window.py:621\nmsgid   \"No device paired.\"\nmsgstr  \"Kein Gerät gekoppelt.\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"Nur %(max_count)s Gerät kann an diesen Empfänger gekoppelt \"\n        \"werden.\"\nmsgstr[1]       \"Bis zu %(max_count)s Geräte können an diesen Empfänger \"\n        \"gekoppelt werden.\"\n\n#: lib/solaar/ui/window.py:634\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"An diesen Empfänger kann nur ein Gerät gekoppelt werden.\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"Dieser Empfänger kann an %d weiteres Gerät gekoppelt werden.\"\nmsgstr[1]       \"Dieser Empfänger kann an %d weitere Geräte gekoppelt werden.\"\n\n#: lib/solaar/ui/window.py:692\nmsgid   \"Battery Voltage\"\nmsgstr  \"Akkuspannung\"\n\n#: lib/solaar/ui/window.py:694\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"Spannung, die vom Akku gemeldet wird\"\n\n#: lib/solaar/ui/window.py:696\nmsgid   \"Battery Level\"\nmsgstr  \"Akkuladung\"\n\n#: lib/solaar/ui/window.py:698\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"Ungefährer Ladezustand des Akkus, den das Gerät meldet\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid   \"next reported \"\nmsgstr  \"nächste Meldung bei \"\n\n#: lib/solaar/ui/window.py:708\nmsgid   \" and next level to be reported.\"\nmsgstr  \" und der nächste, der vom Gerät mitgeteilt werden wird.\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"last known\"\nmsgstr  \"letzte bekannte\"\n\n#: lib/solaar/ui/window.py:724\nmsgid   \"encrypted\"\nmsgstr  \"verschlüsselt\"\n\n#: lib/solaar/ui/window.py:726\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"Die drahtlose Verbindung zwischen diesem Gerät und dem Empfänger ist \"\n        \"verschlüsselt.\"\n\n#: lib/solaar/ui/window.py:728\nmsgid   \"not encrypted\"\nmsgstr  \"nicht verschlüsselt\"\n\n#: lib/solaar/ui/window.py:732\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"Die drahtlose Verbindung zwischen diesem Gerät und dem Empfänger ist \"\n        \"nicht verschlüsselt.\\n\"\n        \"Dies ist ein Sicherheitsproblem für Zeigegeräte, aber ein großes \"\n        \"Sicherheitsrisiko für Texteingabegeräte.\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"%(light_level)d Lux\"\n\n#~ msgid        \"About\"\n#~ msgstr       \"Über\"\n\n#~ msgid        \"Add action\"\n#~ msgstr       \"Aktion hinzufügen\"\n\n#~ msgid        \"Adjust the DPI by sliding the mouse horizontally while \"\n#~      \"holding the DPI button.\"\n#~ msgstr       \"Die Empfindlichkeit (in DPI) durch seitliches Bewegen der \"\n#~      \"Maus ändern, während der DPI-Knopf gehalten wird.\"\n\n#~ msgid        \"Adjust the DPI by sliding the mouse horizontally while \"\n#~      \"holding the button down.\"\n#~ msgstr       \"Passe die DPI an durch horizontale Mausbewegung bei \"\n#~      \"gleichzeitig gedrückter Taste.\"\n\n#~ msgid        \"Battery information unknown.\"\n#~ msgstr       \"Akkuzustand unbekannt.\"\n\n#~ msgid        \"Click to allow changes.\"\n#~ msgstr       \"Anklicken, um Änderungen zuzulassen.\"\n\n#~ msgid        \"Click to prevent changes.\"\n#~ msgstr       \"Anklicken, um Änderungen zu verhindern.\"\n\n#~ msgid        \"Count\"\n#~ msgstr       \"Klickanzahl\"\n\n#~ msgid        \"DPI Sliding Adjustment\"\n#~ msgstr       \"DPI-Anpassung durch seitliches Bewegen\"\n\n#~ msgid        \"Device originated the current notification.\"\n#~ msgstr       \"Die aktuelle Be­nach­rich­ti­gung entspringt dem Gerät.\"\n\n#~ msgid        \"Diverted key or button depressed or released.\\n\"\n#~      \"Use the Key/Button Diversion setting to divert keys and buttons.\"\n#~ msgstr       \"Umgeleitete Taste oder Maustaste gedrückt bzw. losgelassen.\\n\"\n#~      \"Verwende die Einstellungen für Tasten-/Maustastenumleitung um Tasten \"\n#~      \"oder Maustasten umzuleiten.\"\n\n#~ msgid        \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr       \"Schaltet das Scrollen mit dem Daumen unter Linux faktisch \"\n#~      \"aus.\"\n\n#~ msgid        \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr       \"Schaltet das Scrollen mit dem Mausrad unter Linux faktisch \"\n#~      \"aus.\"\n\n#~ msgid        \"For more information see the Solaar installation directions\\n\"\n#~      \"at https://pwr-solaar.github.io/Solaar/installation\"\n#~ msgstr       \"Weitere Informationen erhalten Sie in den Solaar-\"\n#~      \"Installationshinweisen\\n\"\n#~      \"unter https://pwr-solaar.github.io/Solaar/installation\"\n\n#, python-format\n#~ msgid        \"Found a Logitech Receiver (%s), but did not have permission \"\n#~      \"to open it.\"\n#~ msgstr       \"Ein Logitech-Empfänger (%s) wurde gefunden, wegen fehlender \"\n#~      \"Berechtigung kann aber nicht darauf zugegriffen werden.\"\n\n#~ msgid        \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr       \"HID++-Modus für horizontales Scrollen mit dem Daumenrad.\"\n\n#~ msgid        \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr       \"HID++ Modus für vertikales Mausrad-Scrollen.\"\n\n#~ msgid        \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr       \"Wenn das Gerät bereits eingeschaltet ist, schalte es aus und \"\n#~      \"wieder ein.\"\n\n#~ msgid        \"If you've just installed Solaar, try removing the receiver \"\n#~      \"and plugging it back in.\"\n#~ msgstr       \"Wenn Sie Solaar gerade neu installiert haben, versuchen Sie \"\n#~      \"den Empfänger aus- und wieder einzustecken.\"\n\n#~ msgid        \"No Logitech device found\"\n#~ msgstr       \"Kein Logitechgerät gefunden\"\n\n#~ msgid        \"No Logitech receiver found\"\n#~ msgstr       \"Kein Logitech-Empfänger gefunden\"\n\n#~ msgid        \"Quit\"\n#~ msgstr       \"Beenden\"\n\n#~ msgid        \"Scroll Wheel HID++ Scrolling\"\n#~ msgstr       \"Mausrad-HID++-Scrollen\"\n\n#~ msgid        \"Send a gesture by sliding the mouse while holding the button \"\n#~      \"down.\"\n#~ msgstr       \"Erstelle eine Geste durch Mausbewegung bei gleichzeitig \"\n#~      \"gedrückter Taste.\"\n\n#~ msgid        \"Set to ignore if unusual device behaviour is experienced\"\n#~ msgstr       \"Aktivieren zum Ignorieren, falls das Gerät sich ungewöhnlich \"\n#~      \"verhält\"\n\n#~ msgid        \"Shows status of devices connected\\n\"\n#~      \"through wireless Logitech receivers.\"\n#~ msgstr       \"Zeigt den Status von Geräten an, die über\\n\"\n#~      \"Logitech-Empfänger drahtlos verbunden sind.\"\n\n#~ msgid        \"Solaar depends on a udev file that is not present\"\n#~ msgstr       \"Solaar benötigt eine udev-Datei, die nicht gefunden wurde\"\n\n#~ msgid        \"Thumb Wheel HID++ Scrolling\"\n#~ msgstr       \"Daumenrad-HID++-Scrollen\"\n\n#~ msgid        \"Top-most coordinate.\"\n#~ msgstr       \"Äußerste obere Koordinate.\"\n\n#~ msgid        \"Try removing the device and plugging it back in or turning \"\n#~      \"it off and then on.\"\n#~ msgstr       \"Versuche das Gerät herauszuziehen und neu einzustecken bzw. \"\n#~      \"es aus und wieder an zuschalten.\"\n\n#~ msgid        \"height\"\n#~ msgstr       \"Höhe\"\n\n#~ msgid        \"top\"\n#~ msgstr       \"oben\"\n\n#~ msgid        \"unknown\"\n#~ msgstr       \"unbekannt\"\n\n#~ msgid        \"width\"\n#~ msgstr       \"Breite\"\n"
  },
  {
    "path": "po/el.po",
    "content": "# Greek translations for solaar package.\n# Copyright (C) 2014 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2014.\n# Giannis Tsagatakis <jtsagata@gmail.com>\n# Vangelis Skarmoutsos <skarmoutsosv@gmail.com>, 2017\n# Athanasios Nektarios Karachalios Stagkas <nasos.karachalios.stagkas@proton.me> 2023-2024\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 0.9.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-03-14 13:23+0700\\n\"\n\"PO-Revision-Date: 2024-04-01 03:51+0300\\n\"\n\"Last-Translator: Vangelis Skarmoutsos <skarmoutsosv@gmail.com>\\n\"\n\"Language-Team: none\\n\"\n\"Language: el\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.4.2\\n\"\n\n#: lib/logitech_receiver/base_usb.py:45\nmsgid \"Bolt Receiver\"\nmsgstr \"Δέκτης Bolt\"\n\n#: lib/logitech_receiver/base_usb.py:58\nmsgid \"Unifying Receiver\"\nmsgstr \"Δέκτης Unifying\"\n\n#: lib/logitech_receiver/base_usb.py:70 lib/logitech_receiver/base_usb.py:83\n#: lib/logitech_receiver/base_usb.py:97 lib/logitech_receiver/base_usb.py:111\n#: lib/logitech_receiver/base_usb.py:125\nmsgid \"Nano Receiver\"\nmsgstr \"Δέκτης Nano\"\n\n#: lib/logitech_receiver/base_usb.py:138\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Δέκτης Lightspeed\"\n\n#: lib/logitech_receiver/base_usb.py:149\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"Δέκτης EX100 27 Mhz\"\n\n#: lib/logitech_receiver/common.py:604\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"Μπαταρία: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:606\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"Μπαταρία: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:926\n#: lib/logitech_receiver/settings_templates.py:291\nmsgid \"Disabled\"\nmsgstr \"Απενεργοποιημένο\"\n\n#: lib/logitech_receiver/hidpp20.py:927\nmsgid \"Static\"\nmsgstr \"Στατικό\"\n\n#: lib/logitech_receiver/hidpp20.py:928\nmsgid \"Pulse\"\nmsgstr \"Παλμός\"\n\n#: lib/logitech_receiver/hidpp20.py:929\nmsgid \"Cycle\"\nmsgstr \"Κύκλος\"\n\n#: lib/logitech_receiver/hidpp20.py:930\nmsgid \"Boot\"\nmsgstr \"Εκκίνηση\"\n\n#: lib/logitech_receiver/hidpp20.py:931\nmsgid \"Demo\"\nmsgstr \"Ντέμο\"\n\n#: lib/logitech_receiver/hidpp20.py:932\nmsgid \"Breathe\"\nmsgstr \"Αναπνοή\"\n\n#: lib/logitech_receiver/hidpp20.py:933\nmsgid \"Ripple\"\nmsgstr \"Κυματισμός\"\n\n#: lib/logitech_receiver/hidpp20.py:994\nmsgid \"Unknown Location\"\nmsgstr \"Άγνωστη τοποθεσία\"\n\n#: lib/logitech_receiver/hidpp20.py:995\nmsgid \"Primary\"\nmsgstr \"Πρωτεύον\"\n\n#: lib/logitech_receiver/hidpp20.py:996\nmsgid \"Logo\"\nmsgstr \"Λογότυπο\"\n\n#: lib/logitech_receiver/hidpp20.py:997\nmsgid \"Left Side\"\nmsgstr \"Αριστερή Πλεύση\"\n\n#: lib/logitech_receiver/hidpp20.py:998\nmsgid \"Right Side\"\nmsgstr \"Δεξιά Πλεύση\"\n\n#: lib/logitech_receiver/hidpp20.py:999\nmsgid \"Combined\"\nmsgstr \"Συνδυασμένο\"\n\n#: lib/logitech_receiver/hidpp20.py:1000\nmsgid \"Primary 1\"\nmsgstr \"Πρωτεύον 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1001\nmsgid \"Primary 2\"\nmsgstr \"Πρωτεύον 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1002\nmsgid \"Primary 3\"\nmsgstr \"Πρωτεύον 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1003\nmsgid \"Primary 4\"\nmsgstr \"Πρωτεύον 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1004\nmsgid \"Primary 5\"\nmsgstr \"Πρωτεύον 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1005\nmsgid \"Primary 6\"\nmsgstr \"Πρωτεύον 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"άδεια\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"κρίσιμη\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"χαμηλή\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"μέση τιμή\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"καλή\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"γεμάτη\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"εκφορτίζεται\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"επαναφορτίζεται\"\n\n#: lib/logitech_receiver/i18n.py:37\nmsgid \"charging\"\nmsgstr \"φορτίζεται\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"χωρίς φόρτιση\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"σχεδόν γεμάτη\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"φορτισμένο\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"αργή επαναφόρτιση\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"invalid battery\"\nmsgstr \"μη έγκυρη μπαταρία\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"θερμικό σφάλμα\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"σφάλμα\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"πρότυπο\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"γρήγορο\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"αργό\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"ορίου χρόνου συσκευής\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"η συσκευή δεν υποστηρίζεται\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"πάρα πολλές συσκευές\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"ορίου χρόνου ακολουθίας\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid \"Firmware\"\nmsgstr \"Firmware\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"Bootloader\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"Υλισμικό\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"Άλλο\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"Αριστερό κουμπί\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"Δεξί κουμπί\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"Κεντρικό κουμπί\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"Πίσω κουμπί\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"Εμπρός Κουμπί\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"Κουμπί χειρονομιών ποντικιού\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"Έξυπνος Διακόπτης\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"Διακόπτης DPI\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"Αριστερή κλίση\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"Δεξιά κλίση\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"Αριστερό κλικ\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"Δεξί κλικ\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"Μεσαίο κουμπί ποντικιού\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"Πίσω κουμπί ποντικιού\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"Εμπρός κουμπί ποντικιού\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"Πλοήγηση με κουμπιά χειρονομιών\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"Κύλιση ποντικιού Αριστερό κουμπί\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"Κύλιση ποντικιού Δεξί κουμπί\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"πατημένο\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"αφημένο\"\n\n#: lib/logitech_receiver/notifications.py:63\n#: lib/logitech_receiver/notifications.py:115\nmsgid \"pairing lock is closed\"\nmsgstr \"η δικλείδα σύζευξης είναι κλειστή\"\n\n#: lib/logitech_receiver/notifications.py:63\n#: lib/logitech_receiver/notifications.py:115\nmsgid \"pairing lock is open\"\nmsgstr \"η δικλείδα σύζευξης είναι ανοιχτή\"\n\n#: lib/logitech_receiver/notifications.py:80\nmsgid \"discovery lock is closed\"\nmsgstr \"η δικλείδα ανακάλυψης είναι κλειστή\"\n\n#: lib/logitech_receiver/notifications.py:80\nmsgid \"discovery lock is open\"\nmsgstr \"η δικλείδα ανακάλυψης είναι ανοιχτή\"\n\n#: lib/logitech_receiver/notifications.py:207\nmsgid \"connected\"\nmsgstr \"συνδεμένη\"\n\n#: lib/logitech_receiver/notifications.py:207\nmsgid \"disconnected\"\nmsgstr \"αποσυνδεδεμένη\"\n\n#: lib/logitech_receiver/notifications.py:233\nmsgid \"unpaired\"\nmsgstr \"διαχωρισμένη\"\n\n#: lib/logitech_receiver/notifications.py:280\nmsgid \"powered on\"\nmsgstr \"ανοιχτή\"\n\n#: lib/logitech_receiver/receiver.py:345\nmsgid \"No paired devices.\"\nmsgstr \"Δεν έχω συνταιριασμένες συσκευές.\"\n\n#: lib/logitech_receiver/receiver.py:347 lib/solaar/ui/window.py:630\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s συζευγμένη συσκευή.\"\nmsgstr[1] \"%(count)s συζευγμένες συσκευές.\"\n\n#: lib/logitech_receiver/settings.py:617\nmsgid \"register\"\nmsgstr \"καταχώρηση\"\n\n#: lib/logitech_receiver/settings.py:631 lib/logitech_receiver/settings.py:658\nmsgid \"feature\"\nmsgstr \"χαρακτηριστικό\"\n\n#: lib/logitech_receiver/settings_templates.py:144\nmsgid \"Swap Fx function\"\nmsgstr \"Αντιστροφή λειτουργιών Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:147\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"Όταν είναι ορισμένο, τα πλήκτρα F1..F12 θα ενεργοποιήσουν τις ειδικές τους \"\n\"λειτουργίες,\\n\"\n\"και πρέπει να κρατήσετε το πλήκτρο FN για να ενεργοποιήσετε την τυπική \"\n\"λειτουργία τους.\"\n\n#: lib/logitech_receiver/settings_templates.py:152\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"Όταν δεν είναι ορισμένο, τα πλήκτρα F1..F12 θα ενεργοποιήσουν την τυπική \"\n\"λειτουργία τους,\\n\"\n\"και πρέπει να κρατήσετε το πλήκτρο FN για να ενεργοποιήσετε την ειδική \"\n\"λειτουργία τους.\"\n\n#: lib/logitech_receiver/settings_templates.py:160\nmsgid \"Hand Detection\"\nmsgstr \"Ανίχνευση χεριού\"\n\n#: lib/logitech_receiver/settings_templates.py:161\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"Άνοιγμα φωτισμού όταν τα χέρια βρεθούν πάνω από το πληκτρολόγιο.\"\n\n#: lib/logitech_receiver/settings_templates.py:168\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"Ομαλή κύλιση του τροχού κύλισης\"\n\n#: lib/logitech_receiver/settings_templates.py:169\n#: lib/logitech_receiver/settings_templates.py:402\n#: lib/logitech_receiver/settings_templates.py:431\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"Κατάσταση υψηλής ευαισθησίας για κατακόρυφη ολίσθηση με τον τροχό.\"\n\n#: lib/logitech_receiver/settings_templates.py:176\nmsgid \"Side Scrolling\"\nmsgstr \"Πλάγια κύλιση\"\n\n#: lib/logitech_receiver/settings_templates.py:178\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"Όταν είναι απενεργοποιημένο, πιέζοντας τον τροχό στο πλάι στέλνει \"\n\"προσαρμοσμένα γεγονότα κουμπιού\\n\"\n\"αντί των τυπικών γεγονότων πλάγιας ολίσθησης.\"\n\n#: lib/logitech_receiver/settings_templates.py:188\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"Ευαισθησία (DPI - παλαιά ποντίκια)\"\n\n#: lib/logitech_receiver/settings_templates.py:189\n#: lib/logitech_receiver/settings_templates.py:958\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"Ευαισθησία κίνησης ποντικιού\"\n\n#: lib/logitech_receiver/settings_templates.py:249\n#: lib/logitech_receiver/settings_templates.py:261\n#: lib/logitech_receiver/settings_templates.py:388\nmsgid \"Backlight\"\nmsgstr \"Οπίσθιος φωτισμός\"\n\n#: lib/logitech_receiver/settings_templates.py:250\n#: lib/logitech_receiver/settings_templates.py:389\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"Ρύθμιση χρόνου φωτισμού για το πληκτρολόγιο.\"\n\n#: lib/logitech_receiver/settings_templates.py:262\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"\"\n\"Επίπεδο φωτισμού στο πληκτρολόγιο.  Οι αλλαγές που πραγματοποιούνται \"\n\"εφαρμόζονται μόνο στη χειροκίνητη λειτουργία.\"\n\n#: lib/logitech_receiver/settings_templates.py:293\nmsgid \"Automatic\"\nmsgstr \"Αυτόματο\"\n\n#: lib/logitech_receiver/settings_templates.py:295\nmsgid \"Manual\"\nmsgstr \"Χειροκίνητο\"\n\n#: lib/logitech_receiver/settings_templates.py:297\nmsgid \"Enabled\"\nmsgstr \"Ενεργοποιημένο\"\n\n#: lib/logitech_receiver/settings_templates.py:303\nmsgid \"Backlight Level\"\nmsgstr \"Επίπεδο οπίσθιου φωτισμού\"\n\n#: lib/logitech_receiver/settings_templates.py:304\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"\"\n\"Επίπεδο φωτισμού στο πληκτρολόγιο όταν βρίσκεται σε χειροκίνητη λειτουργία.\"\n\n#: lib/logitech_receiver/settings_templates.py:361\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"Καθυστέρηση οπίσθιου φωτισμού Χέρια Εκτός\"\n\n#: lib/logitech_receiver/settings_templates.py:362\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"\"\n\"Καθυστέρηση σε δευτερόλεπτα μέχρι να σβήσει ο οπίσθιος φωτισμός με τα χέρια \"\n\"μακριά από το πληκτρολόγιο.\"\n\n#: lib/logitech_receiver/settings_templates.py:370\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"Καθυστέρηση οπίσθιου φωτισμού Χέρια Eντός\"\n\n#: lib/logitech_receiver/settings_templates.py:371\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"\"\n\"Καθυστέρηση σε δευτερόλεπτα μέχρι να σβήσει ο οπίσθιος φωτισμός με τα χέρια \"\n\"κοντά στο πληκτρολόγιο.\"\n\n#: lib/logitech_receiver/settings_templates.py:379\nmsgid \"Backlight Delay Powered\"\nmsgstr \"Καθυστέρηση οπίσθιου φωτισμού Με τροφοδοσία\"\n\n#: lib/logitech_receiver/settings_templates.py:380\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"\"\n\"Καθυστέρηση σε δευτερόλεπτα μέχρι να σβήσει ο οπίσθιος φωτισμός με εξωτερική \"\n\"τροφοδοσία.\"\n\n#: lib/logitech_receiver/settings_templates.py:400\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"Τροχός κύλισης υψηλής ανάλυσης\"\n\n#: lib/logitech_receiver/settings_templates.py:404\n#: lib/logitech_receiver/settings_templates.py:433\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"Ρύθμιση για να αγνοείται εάν η κύλιση είναι ασυνήθιστα γρήγορη ή αργή\"\n\n#: lib/logitech_receiver/settings_templates.py:411\n#: lib/logitech_receiver/settings_templates.py:442\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"Εκτροπή τροχού κύλισης\"\n\n#: lib/logitech_receiver/settings_templates.py:413\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Κάντε τον τροχό κύλισης να στέλνει ειδοποιήσεις LOWRES_WHEEL HID++ (οι \"\n\"οποίες ενεργοποιούν τους κανόνες Solaar αλλά αγνοούνται κατά τα άλλα).\"\n\n#: lib/logitech_receiver/settings_templates.py:420\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"Κατεύθυνση τροχού κύλισης\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"Αντιστροφή κατεύθυνσης για κάθετη κύλιση με τον τροχό.\"\n\n#: lib/logitech_receiver/settings_templates.py:429\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"Ανάλυση τροχού κύλισης\"\n\n#: lib/logitech_receiver/settings_templates.py:444\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Κάντε τον τροχό κύλισης να στέλνει ειδοποιήσεις HIRES_WHEEL HID++ (οι οποίες \"\n\"ενεργοποιούν τους κανόνες Solaar αλλά αγνοούνται διαφορετικά).\"\n\n#: lib/logitech_receiver/settings_templates.py:453\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"Ευαισθησία (ταχύτητα δείκτη)\"\n\n#: lib/logitech_receiver/settings_templates.py:454\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"\"\n\"Πολλαπλασιαστής ταχύτητας για το ποντίκι (256 είναι ο κανονικός \"\n\"πολλαπλασιαστής).\"\n\n#: lib/logitech_receiver/settings_templates.py:464\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"Εκτροπή τροχού αντίχειρα\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Κάντε τον τροχό αντίχειρα να στέλνει ειδοποιήσεις THUMB_WHEEL HID++ (οι \"\n\"οποίες ενεργοποιούν τους κανόνες του Solaar αλλά αγνοούνται διαφορετικά).\"\n\n#: lib/logitech_receiver/settings_templates.py:475\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"Κατεύθυνση τροχού αντίχειρα\"\n\n#: lib/logitech_receiver/settings_templates.py:476\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"Αντιστροφή της κατεύθυνσης κύλισης του τροχού αντίχειρα.\"\n\n#: lib/logitech_receiver/settings_templates.py:496\nmsgid \"Onboard Profiles\"\nmsgstr \"Ενσωματωμένα Προφίλ\"\n\n#: lib/logitech_receiver/settings_templates.py:497\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"\"\n\"Ενεργοποιήστε ένα ενσωματωμένο προφίλ, το οποίο ελέγχει το ρυθμό αναφοράς, \"\n\"την ευαισθησία και τις ενέργειες των κουμπιών\"\n\n#: lib/logitech_receiver/settings_templates.py:541\n#: lib/logitech_receiver/settings_templates.py:581\nmsgid \"Report Rate\"\nmsgstr \"Ρυθμός αναφοράς\"\n\n#: lib/logitech_receiver/settings_templates.py:543\n#: lib/logitech_receiver/settings_templates.py:583\nmsgid \"Frequency of device movement reports\"\nmsgstr \"Συχνότητα των αναφορών κίνησης της συσκευής\"\n\n#: lib/logitech_receiver/settings_templates.py:543\n#: lib/logitech_receiver/settings_templates.py:583\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1326\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"\"\n\"Ενδέχεται να χρειαστεί να θέσετε τα Προφίλ Ενσωματωμένου σε Απενεργοποίηση \"\n\"για να είναι αποτελεσματικά.\"\n\n#: lib/logitech_receiver/settings_templates.py:623\nmsgid \"Divert crown events\"\nmsgstr \"Εκτροπή εκδηλώσεων crown\"\n\n#: lib/logitech_receiver/settings_templates.py:624\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Κάντε το crown να στέλνει ειδοποιήσεις CROWN HID++ (οι οποίες ενεργοποιούν \"\n\"τους κανόνες Solaar αλλά αγνοούνται κατά τα άλλα).\"\n\n#: lib/logitech_receiver/settings_templates.py:632\nmsgid \"Crown smooth scroll\"\nmsgstr \"Ομαλή κύλιση Crown\"\n\n#: lib/logitech_receiver/settings_templates.py:633\nmsgid \"Set crown smooth scroll\"\nmsgstr \"Ρύθμιση ομαλής κύλισης Crown\"\n\n#: lib/logitech_receiver/settings_templates.py:641\nmsgid \"Divert G and M Keys\"\nmsgstr \"Εκτροπή πλήκτρων G και M\"\n\n#: lib/logitech_receiver/settings_templates.py:642\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Κάντε τα πλήκτρα G και M να στέλνουν ειδοποιήσεις HID++ (οι οποίες \"\n\"ενεργοποιούν τους κανόνες Solaar αλλά αγνοούνται κατά τα άλλα).\"\n\n#: lib/logitech_receiver/settings_templates.py:656\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"Τροχός κύλισης Αγκιστρωμένος\"\n\n#: lib/logitech_receiver/settings_templates.py:657\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"\"\n\"Αλλάξτε τον τροχό του ποντικιού μεταξύ ρυθμιζόμενης ταχύτητας Αγκιστρωμένου \"\n\"και πάντα ελεύθερης περιστροφής.\"\n\n#: lib/logitech_receiver/settings_templates.py:659\nmsgid \"Freespinning\"\nmsgstr \"Ελεύθερη περιστροφή\"\n\n#: lib/logitech_receiver/settings_templates.py:659\nmsgid \"Ratcheted\"\nmsgstr \"Αγκιστρωμένη\"\n\n#: lib/logitech_receiver/settings_templates.py:666\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"Ταχύτητα Αγκιστρωμένου Τροχού Κύλισης\"\n\n#: lib/logitech_receiver/settings_templates.py:668\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"Χρησιμοποιήστε την ταχύτητα του τροχού του ποντικιού για να εναλλάσσεστε \"\n\"ανάμεσα σε Αγκιστρωμένου και ελεύθερη περιστροφή.\\n\"\n\"Ο τροχός του ποντικιού είναι πάντα ρυθμισμένος στο 50.\"\n\n#: lib/logitech_receiver/settings_templates.py:717\nmsgid \"Key/Button Actions\"\nmsgstr \"Ενέργειες πλήκτρων/κουμπιών\"\n\n#: lib/logitech_receiver/settings_templates.py:719\nmsgid \"Change the action for the key or button.\"\nmsgstr \"Αλλαγή της ενέργειας για το πλήκτρο ή το κουμπί.\"\n\n#: lib/logitech_receiver/settings_templates.py:721\nmsgid \"Overridden by diversion.\"\nmsgstr \"Παρακάμπτεται από εκτροπή.\"\n\n#: lib/logitech_receiver/settings_templates.py:723\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"\"\n\"Η αλλαγή σημαντικών ενεργειών (όπως για το αριστερό κουμπί του ποντικιού) \"\n\"μπορεί να οδηγήσει σε ένα σύστημα που δεν μπορεί να χρησιμοποιηθεί.\"\n\n#: lib/logitech_receiver/settings_templates.py:886\nmsgid \"Key/Button Diversion\"\nmsgstr \"Εκτροπή πλήκτρων/κουμπιών\"\n\n#: lib/logitech_receiver/settings_templates.py:887\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse \"\n\"Gestures or Sliding DPI\"\nmsgstr \"\"\n\"Κάντε το πλήκτρο ή το κουμπί να στέλνει ειδοποιήσεις HID++ (εκτροπή) ή να \"\n\"ξεκινάει χειρονομίες ποντικιού ή συρόμενο DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:890\n#: lib/logitech_receiver/settings_templates.py:891\n#: lib/logitech_receiver/settings_templates.py:892\nmsgid \"Diverted\"\nmsgstr \"Εκτρεπόμενο\"\n\n#: lib/logitech_receiver/settings_templates.py:890\n#: lib/logitech_receiver/settings_templates.py:891\nmsgid \"Mouse Gestures\"\nmsgstr \"Χειρονομίες ποντικιού\"\n\n#: lib/logitech_receiver/settings_templates.py:890\n#: lib/logitech_receiver/settings_templates.py:891\n#: lib/logitech_receiver/settings_templates.py:892\nmsgid \"Regular\"\nmsgstr \"Κανονικό\"\n\n#: lib/logitech_receiver/settings_templates.py:890\nmsgid \"Sliding DPI\"\nmsgstr \"Ολίσθαινόμενο DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:957\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"Ευαισθησία (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:997\nmsgid \"Sensitivity Switching\"\nmsgstr \"Εναλλαγή ευαισθησίας\"\n\n#: lib/logitech_receiver/settings_templates.py:999\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key \"\n\"or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\"Εναλλαγή της τρέχουσας ευαισθησίας και της ευαισθησίας που έχει \"\n\"απομνημονευθεί όταν πατηθεί το πλήκτρο ή το κουμπί.\\n\"\n\"Εάν δεν υπάρχει απομνημονευμένη ευαισθησία, απλά θυμηθείτε την τρέχουσα \"\n\"ευαισθησία\"\n\n#: lib/logitech_receiver/settings_templates.py:1003\nmsgid \"Off\"\nmsgstr \"Απενεργοποίηση\"\n\n#: lib/logitech_receiver/settings_templates.py:1034\nmsgid \"Disable keys\"\nmsgstr \"Απενεργοποίηση πλήκτρων\"\n\n#: lib/logitech_receiver/settings_templates.py:1035\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"Απενεργοποίηση συγκεκριμένων πλήκτρων πληκτρολογίου.\"\n\n#: lib/logitech_receiver/settings_templates.py:1038\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"Απενεργοποίηση του πλήκτρου %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1051\n#: lib/logitech_receiver/settings_templates.py:1108\nmsgid \"Set OS\"\nmsgstr \"Ορισμός λειτουργικού συστήματος\"\n\n#: lib/logitech_receiver/settings_templates.py:1052\n#: lib/logitech_receiver/settings_templates.py:1109\nmsgid \"Change keys to match OS.\"\nmsgstr \"Αλλάξτε τα πλήκτρα για να ταιριάζουν με το λειτουργικό σύστημα.\"\n\n#: lib/logitech_receiver/settings_templates.py:1121\nmsgid \"Change Host\"\nmsgstr \"Αλλαγή κεντρικού υπολογιστή\"\n\n#: lib/logitech_receiver/settings_templates.py:1122\nmsgid \"Switch connection to a different host\"\nmsgstr \"Αλλαγή σύνδεσης σε διαφορετικό κεντρικό υπολογιστή\"\n\n#: lib/logitech_receiver/settings_templates.py:1146\nmsgid \"Performs a left click.\"\nmsgstr \"Πραγματοποιεί αριστερό κλικ.\"\n\n#: lib/logitech_receiver/settings_templates.py:1146\nmsgid \"Single tap\"\nmsgstr \"Απλό πάτημα\"\n\n#: lib/logitech_receiver/settings_templates.py:1147\nmsgid \"Performs a right click.\"\nmsgstr \"Πραγματοποιεί δεξί κλικ.\"\n\n#: lib/logitech_receiver/settings_templates.py:1147\nmsgid \"Single tap with two fingers\"\nmsgstr \"Απλό πάτημα με δύο δάχτυλα\"\n\n#: lib/logitech_receiver/settings_templates.py:1148\nmsgid \"Single tap with three fingers\"\nmsgstr \"Απλό πάτημα με τρία δάχτυλα\"\n\n#: lib/logitech_receiver/settings_templates.py:1152\nmsgid \"Double tap\"\nmsgstr \"Διπλό πάτημα\"\n\n#: lib/logitech_receiver/settings_templates.py:1152\nmsgid \"Performs a double click.\"\nmsgstr \"Πραγματοποιεί διπλό κλικ.\"\n\n#: lib/logitech_receiver/settings_templates.py:1153\nmsgid \"Double tap with two fingers\"\nmsgstr \"Διπλό πάτημα με δύο δάχτυλα\"\n\n#: lib/logitech_receiver/settings_templates.py:1154\nmsgid \"Double tap with three fingers\"\nmsgstr \"Διπλό πάτημα με τρία δάχτυλα\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"Σύρετε αντικείμενα σύροντας το δάχτυλο μετά από διπλό πάτημα.\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid \"Tap and drag\"\nmsgstr \"Πάτημα και σύρσιμο\"\n\n#: lib/logitech_receiver/settings_templates.py:1159\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"Πάτημα και σύρσιμο με δύο δάχτυλα\"\n\n#: lib/logitech_receiver/settings_templates.py:1160\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"Σύρετε αντικείμενα σύροντας τα δάχτυλα μετά από διπλό πάτημα.\"\n\n#: lib/logitech_receiver/settings_templates.py:1162\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"Πάτημα και σύρσιμο με τρία δάχτυλα\"\n\n#: lib/logitech_receiver/settings_templates.py:1165\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"Καταστολή χειρονομιών tap και edge\"\n\n#: lib/logitech_receiver/settings_templates.py:1166\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"\"\n\"Απενεργοποιεί τις χειρονομίες tap και edge (ισοδύναμο με το πάτημα των \"\n\"πλήκτρων Fn+LeftClick).\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid \"Scroll with one finger\"\nmsgstr \"Κύλιση με ένα δάχτυλο\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\n#: lib/logitech_receiver/settings_templates.py:1169\n#: lib/logitech_receiver/settings_templates.py:1172\nmsgid \"Scrolls.\"\nmsgstr \"Κύλιση.\"\n\n#: lib/logitech_receiver/settings_templates.py:1169\n#: lib/logitech_receiver/settings_templates.py:1172\nmsgid \"Scroll with two fingers\"\nmsgstr \"Κύλιση με δύο δάχτυλα\"\n\n#: lib/logitech_receiver/settings_templates.py:1170\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"Οριζόντια κύλιση με δύο δάχτυλα\"\n\n#: lib/logitech_receiver/settings_templates.py:1170\nmsgid \"Scrolls horizontally.\"\nmsgstr \"Κύλιση οριζόντια.\"\n\n#: lib/logitech_receiver/settings_templates.py:1171\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"Κατακόρυφη κύλιση με δύο δάχτυλα\"\n\n#: lib/logitech_receiver/settings_templates.py:1171\nmsgid \"Scrolls vertically.\"\nmsgstr \"Κατακόρυφη Κύλιση.\"\n\n#: lib/logitech_receiver/settings_templates.py:1173\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"Αναστροφή της κατεύθυνσης κύλισης.\"\n\n#: lib/logitech_receiver/settings_templates.py:1173\nmsgid \"Natural scrolling\"\nmsgstr \"Φυσική κύλιση\"\n\n#: lib/logitech_receiver/settings_templates.py:1174\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"Ενεργοποίηση του τροχού αντίχειρα.\"\n\n#: lib/logitech_receiver/settings_templates.py:1174\nmsgid \"Thumbwheel\"\nmsgstr \"Τροχός Αντίχειρα\"\n\n#: lib/logitech_receiver/settings_templates.py:1185\n#: lib/logitech_receiver/settings_templates.py:1189\nmsgid \"Swipe from the top edge\"\nmsgstr \"Σύρσιμο από την επάνω άκρη\"\n\n#: lib/logitech_receiver/settings_templates.py:1186\nmsgid \"Swipe from the left edge\"\nmsgstr \"Σύρσιμο από την αριστερή άκρη\"\n\n#: lib/logitech_receiver/settings_templates.py:1187\nmsgid \"Swipe from the right edge\"\nmsgstr \"Σύρσιμο από τη δεξιά άκρη\"\n\n#: lib/logitech_receiver/settings_templates.py:1188\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"Σύρσιμο από την κάτω άκρη\"\n\n#: lib/logitech_receiver/settings_templates.py:1190\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"Σύρσιμο δύο δάχτυλων από την αριστερή άκρη\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"Σύρσιμο δύο δάχτυλων από τη δεξιά άκρη\"\n\n#: lib/logitech_receiver/settings_templates.py:1192\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"Σύρσιμο δύο δάχτυλων από την κάτω άκρη\"\n\n#: lib/logitech_receiver/settings_templates.py:1193\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"Σύρσιμο δύο δάχτυλων από την επάνω άκρη\"\n\n#: lib/logitech_receiver/settings_templates.py:1194\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"Τσιμπήστε για σμίκρυνση, απλώστε για μεγέθυνση.\"\n\n#: lib/logitech_receiver/settings_templates.py:1194\nmsgid \"Zoom with two fingers.\"\nmsgstr \"Ζουμ με δύο δάχτυλα.\"\n\n#: lib/logitech_receiver/settings_templates.py:1195\nmsgid \"Pinch to zoom out.\"\nmsgstr \"Τσιμπήστε για σμίκρυνση.\"\n\n#: lib/logitech_receiver/settings_templates.py:1196\nmsgid \"Spread to zoom in.\"\nmsgstr \"Απλώστε για μεγέθυνση.\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid \"Zoom with three fingers.\"\nmsgstr \"Ζουμ με τρία δάχτυλα.\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid \"Zoom with two fingers\"\nmsgstr \"Ζουμ με δύο δάχτυλα\"\n\n#: lib/logitech_receiver/settings_templates.py:1216\nmsgid \"Pixel zone\"\nmsgstr \"Ζώνη pixel\"\n\n#: lib/logitech_receiver/settings_templates.py:1217\nmsgid \"Ratio zone\"\nmsgstr \"Ζώνη αναλογίας\"\n\n#: lib/logitech_receiver/settings_templates.py:1218\nmsgid \"Scale factor\"\nmsgstr \"Συντελεστής κλίμακας\"\n\n#: lib/logitech_receiver/settings_templates.py:1218\nmsgid \"Sets the cursor speed.\"\nmsgstr \"Ορίζει την ταχύτητα του δρομέα.\"\n\n#: lib/logitech_receiver/settings_templates.py:1222\nmsgid \"Left\"\nmsgstr \"Αριστερά\"\n\n#: lib/logitech_receiver/settings_templates.py:1222\nmsgid \"Left-most coordinate.\"\nmsgstr \"Αριστερότερη συντεταγμένη.\"\n\n#: lib/logitech_receiver/settings_templates.py:1223\nmsgid \"Bottom\"\nmsgstr \"Κάτω\"\n\n#: lib/logitech_receiver/settings_templates.py:1223\nmsgid \"Bottom coordinate.\"\nmsgstr \"Κάτωθεν συντεταγμένη.\"\n\n#: lib/logitech_receiver/settings_templates.py:1224\nmsgid \"Width\"\nmsgstr \"Πλάτος\"\n\n#: lib/logitech_receiver/settings_templates.py:1224\nmsgid \"Width.\"\nmsgstr \"Πλάτος.\"\n\n#: lib/logitech_receiver/settings_templates.py:1225\nmsgid \"Height\"\nmsgstr \"Ύψος\"\n\n#: lib/logitech_receiver/settings_templates.py:1225\nmsgid \"Height.\"\nmsgstr \"Ύψος.\"\n\n#: lib/logitech_receiver/settings_templates.py:1226\nmsgid \"Cursor speed.\"\nmsgstr \"Ταχύτητα δρομέα.\"\n\n#: lib/logitech_receiver/settings_templates.py:1226\nmsgid \"Scale\"\nmsgstr \"Κλίμακα\"\n\n#: lib/logitech_receiver/settings_templates.py:1232\nmsgid \"Gestures\"\nmsgstr \"Χειρονομίες\"\n\n#: lib/logitech_receiver/settings_templates.py:1233\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"Ρύθμιση της συμπεριφοράς του ποντικιού/του touchpad.\"\n\n#: lib/logitech_receiver/settings_templates.py:1249\nmsgid \"Gestures Diversion\"\nmsgstr \"Χειρονομίες εκτροπής\"\n\n#: lib/logitech_receiver/settings_templates.py:1250\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"Εκτροπή χειρονομιών του ποντικιού/του touchpad.\"\n\n#: lib/logitech_receiver/settings_templates.py:1266\nmsgid \"Gesture params\"\nmsgstr \"Παράμετροι χειρονομιών\"\n\n#: lib/logitech_receiver/settings_templates.py:1267\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"Αλλαγή των αριθμητικών παραμέτρων ενός ποντικιού/του touchpad.\"\n\n#: lib/logitech_receiver/settings_templates.py:1291\nmsgid \"M-Key LEDs\"\nmsgstr \"Λυχνίες LED M-Key\"\n\n#: lib/logitech_receiver/settings_templates.py:1293\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"Έλεγχος των λυχνιών LED του M-Key.\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\n#: lib/logitech_receiver/settings_templates.py:1328\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"\"\n\"Μπορεί να χρειαστεί εκτροπή των πλήκτρων G  για να είναι αποτελεσματική.\"\n\n#: lib/logitech_receiver/settings_templates.py:1303\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"Ανάβει το πλήκτρο %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1322\nmsgid \"MR-Key LED\"\nmsgstr \"MR-Πλήκτρο LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"Έλεγχος της λυχνίας LED πλήκτρου MR.\"\n\n#: lib/logitech_receiver/settings_templates.py:1345\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"Μόνιμη αντιστοίχιση πλήκτρων/κουμπιών\"\n\n#: lib/logitech_receiver/settings_templates.py:1347\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"Μόνιμη αλλαγή της αντιστοίχισης για το πλήκτρο ή το κουμπί.\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"\"\n\"Η αλλαγή σημαντικών πλήκτρων ή κουμπιών (όπως για παράδειγμα του αριστερού \"\n\"κουμπιού του ποντικιού) μπορεί να οδηγήσει σε ένα άχρηστο σύστημα.\"\n\n#: lib/logitech_receiver/settings_templates.py:1406\nmsgid \"Sidetone\"\nmsgstr \"Sidetone\"\n\n#: lib/logitech_receiver/settings_templates.py:1407\nmsgid \"Set sidetone level.\"\nmsgstr \"Ορισμός επιπέδου sidetone.\"\n\n#: lib/logitech_receiver/settings_templates.py:1416\nmsgid \"Equalizer\"\nmsgstr \"Ισοσταθμιστής\"\n\n#: lib/logitech_receiver/settings_templates.py:1417\nmsgid \"Set equalizer levels.\"\nmsgstr \"Ρύθμιση επιπέδων ισοσταθμιστή.\"\n\n#: lib/logitech_receiver/settings_templates.py:1439\nmsgid \"Hz\"\nmsgstr \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1445\nmsgid \"Power Management\"\nmsgstr \"Διαχείριση ενέργειας\"\n\n#: lib/logitech_receiver/settings_templates.py:1446\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"Απενεργοποίηση σε λεπτά (0 για ποτέ).\"\n\n#: lib/logitech_receiver/settings_templates.py:1457\nmsgid \"LED Control\"\nmsgstr \"Έλεγχος LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1458\nmsgid \"Switch control of LEDs between device and Solaar\"\nmsgstr \"Εναλλαγή ελέγχου των LED μεταξύ συσκευής και Solaar\"\n\n#: lib/logitech_receiver/settings_templates.py:1473\nmsgid \"LED Zone Effects\"\nmsgstr \"Εφέ ζώνης LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1474\nmsgid \"Set effect for LED Zone\"\nmsgstr \"Ρύθμιση εφέ για τη ζώνη LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1477\nmsgid \"Speed\"\nmsgstr \"Ταχύτητα\"\n\n#: lib/logitech_receiver/settings_templates.py:1478\nmsgid \"Period\"\nmsgstr \"Περίοδος\"\n\n#: lib/logitech_receiver/settings_templates.py:1479\nmsgid \"Intensity\"\nmsgstr \"Ένταση\"\n\n#: lib/logitech_receiver/settings_templates.py:1480\nmsgid \"Ramp\"\nmsgstr \"Κλίμακα\"\n\n#: lib/logitech_receiver/settings_templates.py:1494\nmsgid \"LEDs\"\nmsgstr \"Λυχνίες LED\"\n\n#: lib/solaar/ui/__init__.py:112\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"\"\n\"Μια άλλη διεργασία Solaar εκτελείται ήδη, οπότε απλά ανοίξτε το παράθυρό της\"\n\n#: lib/solaar/ui/about.py:38\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"Διαχειρίζεται δέκτες Logitech,\\n\"\n\"πληκτρολόγια, ποντίκια και τάμπλετ.\"\n\n#: lib/solaar/ui/about.py:46\nmsgid \"Additional Programming\"\nmsgstr \"Πρόσθετος προγραμματισμός\"\n\n#: lib/solaar/ui/about.py:47\nmsgid \"GUI design\"\nmsgstr \"Σχεδιασμός GUI\"\n\n#: lib/solaar/ui/about.py:49\nmsgid \"Testing\"\nmsgstr \"Δοκιμές\"\n\n#: lib/solaar/ui/about.py:57\nmsgid \"Logitech documentation\"\nmsgstr \"Τεκμηρίωση Logitech\"\n\n#: lib/solaar/ui/action.py:83 lib/solaar/ui/action.py:87\n#: lib/solaar/ui/window.py:199\nmsgid \"Unpair\"\nmsgstr \"Διαχωρισμός\"\n\n#: lib/solaar/ui/action.py:86 lib/solaar/ui/diversion_rules.py:104\nmsgid \"Cancel\"\nmsgstr \"Ακύρωση\"\n\n#: lib/solaar/ui/common.py:35\nmsgid \"Permissions error\"\nmsgstr \"Σφάλμα δικαιωμάτων\"\n\n#: lib/solaar/ui/common.py:37\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"\"\n\"Βρέθηκε ένας δέκτης ή μια συσκευή Logitech (%s), αλλά δεν είχατε την άδεια \"\n\"να την ανοίξετε.\"\n\n#: lib/solaar/ui/common.py:39\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"\"\n\"Εάν μόλις εγκαταστήσατε το Solaar, δοκιμάστε να αποσυνδέσετε το δέκτη ή τη \"\n\"συσκευή και στη συνέχεια να το επανασυνδέσετε.\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Cannot connect to device error\"\nmsgstr \"Δεν είναι δυνατή η σύνδεση σφάλμα συσκευής\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"Βρέθηκε ένας δέκτης ή μια συσκευή Logitech στη διεύθυνση %s, αλλά \"\n\"παρουσιάστηκε σφάλμα σύνδεσης.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"\"\n\"Δοκιμάστε να αποσυνδέσετε τη συσκευή και στη συνέχεια να την επανασυνδέσετε \"\n\"ή να την απενεργοποιήσετε και στη συνέχεια να την ενεργοποιήσετε.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Unpairing failed\"\nmsgstr \"Αποτυχία διαχωρισμού\"\n\n#: lib/solaar/ui/common.py:51\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"Απέτυχα να διαχωρίσω την συσκευή %{device} από τον %{receiver}.\"\n\n#: lib/solaar/ui/common.py:53\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"Ο δέκτης επέστρεψε ένα λάθος, χωρίς άλλες πληροφορίες.\"\n\n#: lib/solaar/ui/config_panel.py:231\nmsgid \"Complete - ENTER to change\"\nmsgstr \"Ολοκλήρωση - ENTER για αλλαγή\"\n\n#: lib/solaar/ui/config_panel.py:231\nmsgid \"Incomplete\"\nmsgstr \"Ελλιπής\"\n\n#: lib/solaar/ui/config_panel.py:476 lib/solaar/ui/config_panel.py:529\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d Τιμή\"\nmsgstr[1] \"%d τιμές\"\n\n#: lib/solaar/ui/config_panel.py:612\nmsgid \"Changes allowed\"\nmsgstr \"Επιτρεπτές αλλαγές\"\n\n#: lib/solaar/ui/config_panel.py:613\nmsgid \"No changes allowed\"\nmsgstr \"Μη επιτρεπτές αλλαγές\"\n\n#: lib/solaar/ui/config_panel.py:614\nmsgid \"Ignore this setting\"\nmsgstr \"Αγνόηση αυτής της ρύθμισης\"\n\n#: lib/solaar/ui/config_panel.py:659\nmsgid \"Working\"\nmsgstr \"Εργάζεται\"\n\n#: lib/solaar/ui/config_panel.py:662\nmsgid \"Read/write operation failed.\"\nmsgstr \"Αποτυχία λειτουργίας ανάγνωσης/εγγραφής.\"\n\n#: lib/solaar/ui/diversion_rules.py:66\nmsgid \"Built-in rules\"\nmsgstr \"Ενσωματωμένοι κανόνες\"\n\n#: lib/solaar/ui/diversion_rules.py:66\nmsgid \"User-defined rules\"\nmsgstr \"Κανόνες που ορίζονται από το χρήστη\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:1089\nmsgid \"Rule\"\nmsgstr \"Κανόνας\"\n\n#: lib/solaar/ui/diversion_rules.py:69 lib/solaar/ui/diversion_rules.py:538\n#: lib/solaar/ui/diversion_rules.py:665\nmsgid \"Sub-rule\"\nmsgstr \"Υποκανόνας\"\n\n#: lib/solaar/ui/diversion_rules.py:71\nmsgid \"[empty]\"\nmsgstr \"[κενό]\"\n\n#: lib/solaar/ui/diversion_rules.py:95\nmsgid \"Make changes permanent?\"\nmsgstr \"Να κάνετε τις αλλαγές μόνιμες;\"\n\n#: lib/solaar/ui/diversion_rules.py:100\nmsgid \"Yes\"\nmsgstr \"Ναι\"\n\n#: lib/solaar/ui/diversion_rules.py:102\nmsgid \"No\"\nmsgstr \"Όχι\"\n\n#: lib/solaar/ui/diversion_rules.py:107\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"Αν επιλέξετε Όχι, οι αλλαγές θα χαθούν όταν κλείσει το Solaar.\"\n\n#: lib/solaar/ui/diversion_rules.py:138\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Συντάκτης κανόνων Solaar\"\n\n#: lib/solaar/ui/diversion_rules.py:231\nmsgid \"Save changes\"\nmsgstr \"Αποθήκευση αλλαγών\"\n\n#: lib/solaar/ui/diversion_rules.py:236\nmsgid \"Discard changes\"\nmsgstr \"Απόρριψη αλλαγών\"\n\n#: lib/solaar/ui/diversion_rules.py:397\nmsgid \"Insert here\"\nmsgstr \"Εισαγωγή εδώ\"\n\n#: lib/solaar/ui/diversion_rules.py:399\nmsgid \"Insert above\"\nmsgstr \"Εισαγωγή επάνω\"\n\n#: lib/solaar/ui/diversion_rules.py:401\nmsgid \"Insert below\"\nmsgstr \"Εισαγωγή από κάτω\"\n\n#: lib/solaar/ui/diversion_rules.py:407\nmsgid \"Insert new rule here\"\nmsgstr \"Εισαγωγή νέου κανόνα εδώ\"\n\n#: lib/solaar/ui/diversion_rules.py:409\nmsgid \"Insert new rule above\"\nmsgstr \"Εισαγωγή νέου κανόνα επάνω\"\n\n#: lib/solaar/ui/diversion_rules.py:411\nmsgid \"Insert new rule below\"\nmsgstr \"Εισαγωγή νέου κανόνα από κάτω\"\n\n#: lib/solaar/ui/diversion_rules.py:456\nmsgid \"Paste here\"\nmsgstr \"Επικόλληση εδώ\"\n\n#: lib/solaar/ui/diversion_rules.py:458\nmsgid \"Paste above\"\nmsgstr \"Επικόλληση επάνω\"\n\n#: lib/solaar/ui/diversion_rules.py:460\nmsgid \"Paste below\"\nmsgstr \"Επικόλληση από κάτω\"\n\n#: lib/solaar/ui/diversion_rules.py:466\nmsgid \"Paste rule here\"\nmsgstr \"Επικόλληση κανόνα εδώ\"\n\n#: lib/solaar/ui/diversion_rules.py:468\nmsgid \"Paste rule above\"\nmsgstr \"Επικόλληση κανόνα επάνω\"\n\n#: lib/solaar/ui/diversion_rules.py:470\nmsgid \"Paste rule below\"\nmsgstr \"Επικόλληση κανόνα από κάτω\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid \"Paste rule\"\nmsgstr \"Επικόλληση κανόνα\"\n\n#: lib/solaar/ui/diversion_rules.py:503\nmsgid \"Flatten\"\nmsgstr \"Ισοπέδωση\"\n\n#: lib/solaar/ui/diversion_rules.py:536\nmsgid \"Insert\"\nmsgstr \"Εισαγωγή\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:667\n#: lib/solaar/ui/diversion_rules.py:1129\nmsgid \"Or\"\nmsgstr \"Ή\"\n\n#: lib/solaar/ui/diversion_rules.py:540 lib/solaar/ui/diversion_rules.py:666\n#: lib/solaar/ui/diversion_rules.py:1115\nmsgid \"And\"\nmsgstr \"Και\"\n\n#: lib/solaar/ui/diversion_rules.py:542\nmsgid \"Condition\"\nmsgstr \"Συνθήκη\"\n\n#: lib/solaar/ui/diversion_rules.py:544 lib/solaar/ui/diversion_rules.py:1290\nmsgid \"Feature\"\nmsgstr \"Χαρακτηριστικό\"\n\n#: lib/solaar/ui/diversion_rules.py:545 lib/solaar/ui/diversion_rules.py:1325\nmsgid \"Report\"\nmsgstr \"Αναφορά\"\n\n#: lib/solaar/ui/diversion_rules.py:546 lib/solaar/ui/diversion_rules.py:1204\nmsgid \"Process\"\nmsgstr \"Διεργασία\"\n\n#: lib/solaar/ui/diversion_rules.py:547\nmsgid \"Mouse process\"\nmsgstr \"Διεργασία ποντικιού\"\n\n#: lib/solaar/ui/diversion_rules.py:548 lib/solaar/ui/diversion_rules.py:1362\nmsgid \"Modifiers\"\nmsgstr \"Τροποποιητικοί Παράγοντες\"\n\n#: lib/solaar/ui/diversion_rules.py:549 lib/solaar/ui/diversion_rules.py:1414\nmsgid \"Key\"\nmsgstr \"Πλήκτρο\"\n\n#: lib/solaar/ui/diversion_rules.py:550 lib/solaar/ui/diversion_rules.py:1455\nmsgid \"KeyIsDown\"\nmsgstr \"ΤοΠλήκτροΕίναιΠατημένο\"\n\n#: lib/solaar/ui/diversion_rules.py:551 lib/solaar/ui/diversion_rules.py:2260\nmsgid \"Active\"\nmsgstr \"Ενεργό\"\n\n#: lib/solaar/ui/diversion_rules.py:552 lib/solaar/ui/diversion_rules.py:2217\n#: lib/solaar/ui/diversion_rules.py:2269 lib/solaar/ui/diversion_rules.py:2319\nmsgid \"Device\"\nmsgstr \"Συσκευή\"\n\n#: lib/solaar/ui/diversion_rules.py:553 lib/solaar/ui/diversion_rules.py:2295\nmsgid \"Host\"\nmsgstr \"ΟικοδεσπότηςΥποδοχέας\"\n\n#: lib/solaar/ui/diversion_rules.py:554 lib/solaar/ui/diversion_rules.py:2337\nmsgid \"Setting\"\nmsgstr \"Ρύθμιση\"\n\n#: lib/solaar/ui/diversion_rules.py:555 lib/solaar/ui/diversion_rules.py:1470\n#: lib/solaar/ui/diversion_rules.py:1519\nmsgid \"Test\"\nmsgstr \"Δοκιμή\"\n\n#: lib/solaar/ui/diversion_rules.py:556 lib/solaar/ui/diversion_rules.py:1633\nmsgid \"Test bytes\"\nmsgstr \"Δοκιμαστικά bytes\"\n\n#: lib/solaar/ui/diversion_rules.py:557 lib/solaar/ui/diversion_rules.py:1734\nmsgid \"Mouse Gesture\"\nmsgstr \"Χειρονομία ποντικιού\"\n\n#: lib/solaar/ui/diversion_rules.py:561\nmsgid \"Action\"\nmsgstr \"Ενέργεια\"\n\n#: lib/solaar/ui/diversion_rules.py:563 lib/solaar/ui/diversion_rules.py:1844\nmsgid \"Key press\"\nmsgstr \"Πάτημα πλήκτρου\"\n\n#: lib/solaar/ui/diversion_rules.py:564 lib/solaar/ui/diversion_rules.py:1895\nmsgid \"Mouse scroll\"\nmsgstr \"Κύλιση ποντικιού\"\n\n#: lib/solaar/ui/diversion_rules.py:565 lib/solaar/ui/diversion_rules.py:1956\nmsgid \"Mouse click\"\nmsgstr \"Κλικ ποντικιού\"\n\n#: lib/solaar/ui/diversion_rules.py:566\nmsgid \"Set\"\nmsgstr \"Ορισμός\"\n\n#: lib/solaar/ui/diversion_rules.py:567 lib/solaar/ui/diversion_rules.py:2026\nmsgid \"Execute\"\nmsgstr \"Εκτέλεση\"\n\n#: lib/solaar/ui/diversion_rules.py:568 lib/solaar/ui/diversion_rules.py:1160\nmsgid \"Later\"\nmsgstr \"Αργότερα\"\n\n#: lib/solaar/ui/diversion_rules.py:597\nmsgid \"Insert new rule\"\nmsgstr \"Εισαγωγή νέου κανόνα\"\n\n#: lib/solaar/ui/diversion_rules.py:617 lib/solaar/ui/diversion_rules.py:1681\n#: lib/solaar/ui/diversion_rules.py:1786 lib/solaar/ui/diversion_rules.py:1985\nmsgid \"Delete\"\nmsgstr \"Διαγραφή\"\n\n#: lib/solaar/ui/diversion_rules.py:639\nmsgid \"Negate\"\nmsgstr \"Αρνηση\"\n\n#: lib/solaar/ui/diversion_rules.py:663\nmsgid \"Wrap with\"\nmsgstr \"Τύλιγμα με\"\n\n#: lib/solaar/ui/diversion_rules.py:685\nmsgid \"Cut\"\nmsgstr \"Αποκοπή\"\n\n#: lib/solaar/ui/diversion_rules.py:700\nmsgid \"Paste\"\nmsgstr \"Επικόλληση\"\n\n#: lib/solaar/ui/diversion_rules.py:706\nmsgid \"Copy\"\nmsgstr \"Αντιγραφή\"\n\n#: lib/solaar/ui/diversion_rules.py:1070\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"\"\n\"Αυτός ο συντάκτης δεν υποστηρίζει ακόμη την επιλεγμένη συνιστώσα κανόνα.\"\n\n#: lib/solaar/ui/diversion_rules.py:1140\nmsgid \"Number of seconds to delay.\"\nmsgstr \"Αριθμός δευτερολέπτων καθυστέρησης.\"\n\n#: lib/solaar/ui/diversion_rules.py:1178\nmsgid \"Not\"\nmsgstr \"Μη\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"Ενεργή διαδικασία X11. Για χρήση μόνο στο X11.\"\n\n#: lib/solaar/ui/diversion_rules.py:1217\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"Διαδικασία ποντικιού X11. Για χρήση μόνο στο X11.\"\n\n#: lib/solaar/ui/diversion_rules.py:1234\nmsgid \"MouseProcess\"\nmsgstr \"ΔιαδικασίαΠοντικιού\"\n\n#: lib/solaar/ui/diversion_rules.py:1258\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"\"\n\"Όνομα χαρακτηριστικού της ειδοποίησης που ενεργοποιεί την επεξεργασία κανόνα.\"\n\n#: lib/solaar/ui/diversion_rules.py:1305\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"\"\n\"Αριθμός αναφοράς της ειδοποίησης που ενεργοποιεί την επεξεργασία του κανόνα.\"\n\n#: lib/solaar/ui/diversion_rules.py:1338\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"\"\n\"Ενεργοί τροποποιούμενοι παράγοντες πληκτρολογίου. Δεν είναι πάντα διαθέσιμο \"\n\"στο Wayland.\"\n\n#: lib/solaar/ui/diversion_rules.py:1378\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Εκτροπή πλήκτρου ή κουμπιού πατημένο ή απελευθερωμένο.\\n\"\n\"Χρησιμοποιήστε τις ρυθμίσεις εκτροπής πλήκτρων/κουμπιών και εκτροπής \"\n\"πλήκτρων G για να εκτρέψετε πλήκτρα και κουμπιά.\"\n\n#: lib/solaar/ui/diversion_rules.py:1387\nmsgid \"Key down\"\nmsgstr \"Πλήκτρο κάτω\"\n\n#: lib/solaar/ui/diversion_rules.py:1390\nmsgid \"Key up\"\nmsgstr \"Πλήκτρο πάνω\"\n\n#: lib/solaar/ui/diversion_rules.py:1430\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Το πλήκτρο ή το κουμπί εκτροπής είναι προς το παρόν κατεβασμένο.\\n\"\n\"Χρησιμοποιήστε τις ρυθμίσεις εκτροπής πλήκτρων/κουμπιών και εκτροπής \"\n\"πλήκτρων G για να εκτρέψετε πλήκτρα και κουμπιά.\"\n\n#: lib/solaar/ui/diversion_rules.py:1468\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"\"\n\"Συνθήκη δοκιμής για την ειδοποίηση που ενεργοποιεί την επεξεργασία κανόνα.\"\n\n#: lib/solaar/ui/diversion_rules.py:1472\nmsgid \"Parameter\"\nmsgstr \"Παράμετρος\"\n\n#: lib/solaar/ui/diversion_rules.py:1534\nmsgid \"begin (inclusive)\"\nmsgstr \"αρχή ( συμπεριλαμβανομένου)\"\n\n#: lib/solaar/ui/diversion_rules.py:1535\nmsgid \"end (exclusive)\"\nmsgstr \"τέλος ( αποκλειστικό)\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid \"range\"\nmsgstr \"εύρος\"\n\n#: lib/solaar/ui/diversion_rules.py:1546\nmsgid \"minimum\"\nmsgstr \"ελάχιστο\"\n\n#: lib/solaar/ui/diversion_rules.py:1547\nmsgid \"maximum\"\nmsgstr \"μέγιστο\"\n\n#: lib/solaar/ui/diversion_rules.py:1549\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"bytes %(0)d έως %(1)d, από %(2)d έως %(3)d\"\n\n#: lib/solaar/ui/diversion_rules.py:1552 lib/solaar/ui/diversion_rules.py:1553\nmsgid \"mask\"\nmsgstr \"μάσκα\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"bytes %(0)d έως %(1)d, μάσκα %(2)d\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\"Δοκιμή bit ή εύρους σε bytes στο μήνυμα ειδοποίησης που ενεργοποιεί την \"\n\"επεξεργασία κανόνα.\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid \"type\"\nmsgstr \"τύπος\"\n\n#: lib/solaar/ui/diversion_rules.py:1661\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"\"\n\"Χειρονομία ποντικιού με προαιρετικό κουμπί εκκίνησης που ακολουθείται από \"\n\"μηδέν ή περισσότερες κινήσεις του ποντικιού.\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid \"Add movement\"\nmsgstr \"Προσθήκη κίνησης\"\n\n#: lib/solaar/ui/diversion_rules.py:1760\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Προσομοίωση ενός χορδισμένου πλήκτρου κλικ ή πάτημα ή απελευθέρωση.\\n\"\n\"Στο Wayland απαιτεί πρόσβαση εγγραφής στο /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1765\nmsgid \"Add key\"\nmsgstr \"Προσθήκη πλήκτρου\"\n\n#: lib/solaar/ui/diversion_rules.py:1768\nmsgid \"Click\"\nmsgstr \"Κλικ\"\n\n#: lib/solaar/ui/diversion_rules.py:1771\nmsgid \"Depress\"\nmsgstr \"Απελευθέρωση\"\n\n#: lib/solaar/ui/diversion_rules.py:1774\nmsgid \"Release\"\nmsgstr \"Αποδέσμευση\"\n\n#: lib/solaar/ui/diversion_rules.py:1859\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Προσομοίωση κύλισης ποντικιού.\\n\"\n\"Στο Wayland απαιτεί πρόσβαση εγγραφής στο /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1915\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Προσομοίωση ενός κλικ του ποντικιού.\\n\"\n\"Στο Wayland απαιτεί πρόσβαση εγγραφής στο /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid \"Button\"\nmsgstr \"Κουμπί\"\n\n#: lib/solaar/ui/diversion_rules.py:1919\nmsgid \"Count and Action\"\nmsgstr \"Καταμέτρηση και Δράση\"\n\n#: lib/solaar/ui/diversion_rules.py:1968\nmsgid \"Execute a command with arguments.\"\nmsgstr \"Εκτέλεση μιας εντολής με ορίσματα.\"\n\n#: lib/solaar/ui/diversion_rules.py:1971\nmsgid \"Add argument\"\nmsgstr \"Προσθήκη ορίσματος\"\n\n#: lib/solaar/ui/diversion_rules.py:2046\nmsgid \"Toggle\"\nmsgstr \"Εναλλαγή\"\n\n#: lib/solaar/ui/diversion_rules.py:2047\nmsgid \"True\"\nmsgstr \"Αληθές\"\n\n#: lib/solaar/ui/diversion_rules.py:2048\nmsgid \"False\"\nmsgstr \"Ψευδές\"\n\n#: lib/solaar/ui/diversion_rules.py:2061\nmsgid \"Unsupported setting\"\nmsgstr \"Μη υποστηριζόμενη ρύθμιση\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2243\n#: lib/solaar/ui/diversion_rules.py:2325 lib/solaar/ui/diversion_rules.py:2568\n#: lib/solaar/ui/diversion_rules.py:2586\nmsgid \"Originating device\"\nmsgstr \"Συσκευή προέλευσης\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"Η συσκευή είναι ενεργή και οι ρυθμίσεις της μπορούν να αλλάξουν.\"\n\n#: lib/solaar/ui/diversion_rules.py:2265\nmsgid \"Device that originated the current notification.\"\nmsgstr \"Συσκευή από την οποία προήλθε η τρέχουσα ειδοποίηση.\"\n\n#: lib/solaar/ui/diversion_rules.py:2278\nmsgid \"Name of host computer.\"\nmsgstr \"Όνομα του υπολογιστή υποδοχής.\"\n\n#: lib/solaar/ui/diversion_rules.py:2345\nmsgid \"Value\"\nmsgstr \"Τιμή\"\n\n#: lib/solaar/ui/diversion_rules.py:2353\nmsgid \"Item\"\nmsgstr \"Στοιχείο\"\n\n#: lib/solaar/ui/diversion_rules.py:2627\nmsgid \"Change setting on device\"\nmsgstr \"Αλλαγή ρύθμισης στη συσκευή\"\n\n#: lib/solaar/ui/diversion_rules.py:2643\nmsgid \"Setting on device\"\nmsgstr \"Ρύθμιση στη συσκευή\"\n\n#: lib/solaar/ui/notify.py:118\nmsgid \"unspecified reason\"\nmsgstr \"αδιευκρίνιστος λόγος\"\n\n#: lib/solaar/ui/pair_window.py:126 lib/solaar/ui/pair_window.py:260\n#: lib/solaar/ui/pair_window.py:296\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: ζεύξη νέας συσκευής\"\n\n#: lib/solaar/ui/pair_window.py:127\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"Πληκτρολογήστε τον κωδικό πρόσβασης στο %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:130\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"\"\n\"Πληκτρολογήστε %(passcode)s και, στη συνέχεια, πατήστε το πλήκτρο enter.\"\n\n#: lib/solaar/ui/pair_window.py:133\nmsgid \"left\"\nmsgstr \"αριστερά\"\n\n#: lib/solaar/ui/pair_window.py:133\nmsgid \"right\"\nmsgstr \"δεξιά\"\n\n#: lib/solaar/ui/pair_window.py:135\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"Πατήστε %(code)s\\n\"\n\"και στη συνέχεια πατήστε ταυτόχρονα το αριστερό και το δεξί κουμπί.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid \"Pairing failed\"\nmsgstr \"Αποτυχία συνταιρίασματος\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"\"\n\"Σιγουρέψου ότι η συσκευή είναι εντός εμβέλειας, και έχει επαρκώς φορτισμένη \"\n\"μπαταρία.\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"Εντοπίστηκε μια συσκευή, αλλά δεν είναι συμβατή με αυτόν τον δέκτη.\"\n\n#: lib/solaar/ui/pair_window.py:198\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"\"\n\"Περισσότερες συζευγμένες συσκευές από όσες μπορεί να υποστηρίξει ο δέκτης.\"\n\n#: lib/solaar/ui/pair_window.py:200\nmsgid \"No further details are available about the error.\"\nmsgstr \"Δεν υπάρχουν άλλες πληροφορίες για το σφάλμα.\"\n\n#: lib/solaar/ui/pair_window.py:214\nmsgid \"Found a new device:\"\nmsgstr \"Βρήκα μια νέα συσκευή:\"\n\n#: lib/solaar/ui/pair_window.py:239\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"Η ασύρματη σύνδεση είναι χωρίς κρυπτογράφηση\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"Οι δέκτες Unifying είναι συμβατοί μόνο με συσκευές Unifying.\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Οι δέκτες Bolt είναι συμβατοί μόνο με συσκευές Bolt.\"\n\n#: lib/solaar/ui/pair_window.py:272\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"Άλλοι δέκτες είναι συμβατοί μόνο με λίγες συσκευές.\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"\"\n\"Η συσκευή δεν πρέπει να είναι συνδεδεμένη με έναν κοντινό ενεργοποιημένο \"\n\"δέκτη.\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"\"\n\"Πιέστε ένα κουμπί ή πλήκτρο ζεύξης μέχρι να αναβοσβήσει γρήγορα η φωτεινή \"\n\"ένδειξη ζεύξης.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid \"You may have to first turn the device off and on again.\"\nmsgstr \"\"\n\"Ίσως χρειαστεί πρώτα να απενεργοποιήσετε και να ενεργοποιήσετε ξανά τη \"\n\"συσκευή.\"\n\n#: lib/solaar/ui/pair_window.py:282\nmsgid \"Turn on the device you want to pair.\"\nmsgstr \"Άνοιξε την συσκευή που θέλεις να συνταιριάξεις.\"\n\n#: lib/solaar/ui/pair_window.py:284\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"\"\n\"Εάν η συσκευή είναι ήδη ενεργοποιημένη, απενεργοποιήστε την και \"\n\"ενεργοποιήστε την ξανά.\"\n\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"Αυτός ο δέκτης έχει %d ζεύξη που απομένει.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"Αυτός ο δέκτης έχει %d ζεύξεις που απομένουν.\"\n\n#: lib/solaar/ui/pair_window.py:294\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"Η ακύρωση σε αυτό το σημείο δεν θα χρησιμοποιήσει μια αντιστοίχιση.\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid \"No supported device found\"\nmsgstr \"Δεν βρέθηκε υποστηριζόμενη συσκευή\"\n\n#: lib/solaar/ui/tray.py:63 lib/solaar/ui/window.py:321\n#, python-format\nmsgid \"About %s\"\nmsgstr \"Περί %s\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"Έξοδος %s\"\n\n#: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:302\nmsgid \"no receiver\"\nmsgstr \"χωρίς δέκτη\"\n\n#: lib/solaar/ui/tray.py:315 lib/solaar/ui/tray.py:320\nmsgid \"offline\"\nmsgstr \"εκτός σύνδεσης\"\n\n#: lib/solaar/ui/tray.py:318\nmsgid \"no status\"\nmsgstr \"χωρίς κατάσταση\"\n\n#: lib/solaar/ui/window.py:99\nmsgid \"Scanning\"\nmsgstr \"Σάρωση\"\n\n#: lib/solaar/ui/window.py:132\nmsgid \"Battery\"\nmsgstr \"Μπαταρία\"\n\n#: lib/solaar/ui/window.py:135\nmsgid \"Wireless Link\"\nmsgstr \"Ασύρματη ζεύξη\"\n\n#: lib/solaar/ui/window.py:139\nmsgid \"Lighting\"\nmsgstr \"Φωτισμός\"\n\n#: lib/solaar/ui/window.py:173\nmsgid \"Show Technical Details\"\nmsgstr \"Εμφάνιση τεχνικών λεπτομερειών\"\n\n#: lib/solaar/ui/window.py:189\nmsgid \"Pair new device\"\nmsgstr \"Συνταίριασμα νέας συσκευής\"\n\n#: lib/solaar/ui/window.py:207\nmsgid \"Select a device\"\nmsgstr \"Επέλεξε μια συσκευή\"\n\n#: lib/solaar/ui/window.py:324\nmsgid \"Rule Editor\"\nmsgstr \"Συντάκτης κανόνων\"\n\n#: lib/solaar/ui/window.py:543\nmsgid \"Path\"\nmsgstr \"Διαδρομή\"\n\n#: lib/solaar/ui/window.py:546\nmsgid \"USB ID\"\nmsgstr \"USB ID\"\n\n#: lib/solaar/ui/window.py:549 lib/solaar/ui/window.py:551\n#: lib/solaar/ui/window.py:566 lib/solaar/ui/window.py:568\nmsgid \"Serial\"\nmsgstr \"Serial\"\n\n#: lib/solaar/ui/window.py:555\nmsgid \"Index\"\nmsgstr \"Index\"\n\n#: lib/solaar/ui/window.py:557\nmsgid \"Wireless PID\"\nmsgstr \"Wireless PID\"\n\n#: lib/solaar/ui/window.py:559\nmsgid \"Product ID\"\nmsgstr \"Αναγνωριστικό προϊόντος\"\n\n#: lib/solaar/ui/window.py:561\nmsgid \"Protocol\"\nmsgstr \"Πρωτόκολλο\"\n\n#: lib/solaar/ui/window.py:561\nmsgid \"Unknown\"\nmsgstr \"Άγνωστο\"\n\n#: lib/solaar/ui/window.py:563\nmsgid \"Polling rate\"\nmsgstr \"Ρυθμός ανανέωσης\"\n\n#: lib/solaar/ui/window.py:570\nmsgid \"Unit ID\"\nmsgstr \"Unit ID\"\n\n#: lib/solaar/ui/window.py:584\nmsgid \"Notifications\"\nmsgstr \"Ειδοποιήσεις\"\n\n#: lib/solaar/ui/window.py:628\nmsgid \"No device paired.\"\nmsgstr \"Δεν υπάρχει αντιστοιχισμένη συσκευή.\"\n\n#: lib/solaar/ui/window.py:637\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"\"\n\"Έως και %(max_count)s συσκευή μπορεί να συνδεθεί με αυτόν τον δέκτη.\"\nmsgstr[1] \"\"\n\"Έως και %(max_count)s συσκευές μπορούν να αντιστοιχιστούν σε αυτόν τον δέκτη.\"\n\n#: lib/solaar/ui/window.py:648\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"Αυτός ο δέκτης έχει %d ζεύξη που απομένει.\"\nmsgstr[1] \"Αυτός ο δέκτης έχει %d ζεύξεις που απομένουν.\"\n\n#: lib/solaar/ui/window.py:705\nmsgid \"Battery Voltage\"\nmsgstr \"Τάση μπαταρίας\"\n\n#: lib/solaar/ui/window.py:707\nmsgid \"Voltage reported by battery\"\nmsgstr \"Τάση που αναφέρεται από την μπαταρία\"\n\n#: lib/solaar/ui/window.py:709\nmsgid \"Battery Level\"\nmsgstr \"Στάθμη μπαταρίας\"\n\n#: lib/solaar/ui/window.py:711\nmsgid \"Approximate level reported by battery\"\nmsgstr \"Προσεγγιστικό επίπεδο που αναφέρεται από την μπαταρία\"\n\n#: lib/solaar/ui/window.py:718 lib/solaar/ui/window.py:720\nmsgid \"next reported \"\nmsgstr \"επόμενο αναφερόμενο \"\n\n#: lib/solaar/ui/window.py:721\nmsgid \" and next level to be reported.\"\nmsgstr \" και το επόμενο επίπεδο που θα αναφερθεί.\"\n\n#: lib/solaar/ui/window.py:737\nmsgid \"encrypted\"\nmsgstr \"κρυπτογραφημένη\"\n\n#: lib/solaar/ui/window.py:739\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"\"\n\"Η ασύρματη ζεύξη μεταξύ αυτής της συσκευής και του δέκτη είναι  \"\n\"κρυπτογραφημένη.\"\n\n#: lib/solaar/ui/window.py:741\nmsgid \"not encrypted\"\nmsgstr \"χωρίς κρυπτογράφηση\"\n\n#: lib/solaar/ui/window.py:745\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"Η ασύρματη σύνδεση μεταξύ αυτής της συσκευής και του δέκτη της δεν είναι \"\n\"κρυπτογραφημένη.\\n\"\n\"Αυτό είναι ένα ζήτημα ασφάλειας για τις συσκευές επισήμανσης και ένα \"\n\"σημαντικό ζήτημα ασφάλειας για τις συσκευές εισαγωγής κειμένου.\"\n\n#: lib/solaar/ui/window.py:761\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d lux\"\n\n#~ msgid \"Turn illumination on or off on keyboard.\"\n#~ msgstr \"Ενεργοποίηση ή απενεργοποίηση του φωτισμού στο πληκτρολόγιο.\"\n\n#~ msgid \"Polling Rate (ms)\"\n#~ msgstr \"Ρυθμός κλήσεων (ms)\"\n\n#~ msgid \"May also make M keys and MR key send HID++ notifications\"\n#~ msgstr \"\"\n#~ \"Μπορεί επίσης να κάνει τα κλειδιά M και MR να στέλνουν ειδοποιήσεις HID++\"\n\n#, python-format\n#~ msgid \"Battery: %(level)s\"\n#~ msgstr \"Μπαταρία: %(level)s\"\n\n#, python-format\n#~ msgid \"Battery: %(percent)d%%\"\n#~ msgstr \"Μπαταρία: %(percent)d%%\"\n\n#, python-format\n#~ msgid \"Lighting: %(level)s lux\"\n#~ msgstr \"Φωτισμός: %(level)s lux\"\n\n#, python-format\n#~ msgid \"%(rate)d ms (%(rate_hz)dHz)\"\n#~ msgstr \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#~ msgid \"none\"\n#~ msgstr \"καμία\"\n\n#~ msgid \"Only one device can be paired to this receiver.\"\n#~ msgstr \"Μόνο μία συσκευή μπορεί να συνδεθεί με αυτόν τον δέκτη.\"\n\n#~ msgid \"last known\"\n#~ msgstr \"τελευταία γνωστή\"\n\n#~ msgid \" paired devices.\"\n#~ msgstr \" συνταιριασμένες συσκευές.\"\n\n#~ msgid \"1 paired device.\"\n#~ msgstr \"Μία συνταιριασμένη συσκευή\"\n\n#~ msgid \"Count\"\n#~ msgstr \"Πλήθος\"\n\n#~ msgid \"Device originated the current notification.\"\n#~ msgstr \"Η συσκευή από την οποία προήλθε η τρέχουσα ειδοποίηση.\"\n\n#, python-format\n#~ msgid \"\"\n#~ \"Found a Logitech Receiver (%s), but did not have permission to open it.\"\n#~ msgstr \"\"\n#~ \"Βρέθηκε ένας δέκτης Logitech (%s), αλλά δεν έχετε δικαίωμα να τον \"\n#~ \"ανοίξετε.\"\n\n#~ msgid \"Found a new device\"\n#~ msgstr \"Βρέθηκε νέα συσκευή\"\n\n#~ msgid \"\"\n#~ \"If the device is already turned on,\\n\"\n#~ \"turn if off and on again.\"\n#~ msgstr \"\"\n#~ \"Αν η συσκευή είναι ήδη ανοικτή,\\n\"\n#~ \"κλείσε την και μετά άνοιξε την ξανά.\"\n\n#~ msgid \"\"\n#~ \"If you've just installed Solaar, try removing the receiver and plugging \"\n#~ \"it back in.\"\n#~ msgstr \"\"\n#~ \"Εάν μόλις κάνατε εγκατάσταση του  Solaar, δοκιμάστε να αφαιρέσετε τον \"\n#~ \"δέκτη και να τον ξανασυνδέσετε.\"\n\n#~ msgid \"No Logitech device found\"\n#~ msgstr \"Δεν βρέθηκε συσκευή Logitech\"\n\n#~ msgid \"No Logitech receiver found\"\n#~ msgstr \"Δεν βρέθηκε δέκτης Logitech\"\n\n#~ msgid \"No device paired\"\n#~ msgstr \"Χωρίς συνταιριασμένες συσκευές\"\n\n#~ msgid \"Only one device can be paired to this receiver\"\n#~ msgstr \"Μόνο μία συσκευή μπορεί να συνταιριαστεί σε αυτόν τον δέκτη\"\n\n#~ msgid \"\"\n#~ \"Shows status of devices connected\\n\"\n#~ \"through wireless Logitech receivers.\"\n#~ msgstr \"\"\n#~ \"Δείχνει την κατάσταση των συσκευών που συνδέονται\\n\"\n#~ \"ασύρματα σε δέκτες Logitech.\"\n\n#~ msgid \"Smooth Scrolling\"\n#~ msgstr \"Ομαλή κύλιση\"\n\n#, python-format\n#~ msgid \"The receiver only supports %d paired device(s).\"\n#~ msgstr \"Ο δέκτης υποστηρίζει μέχρι %d συνταιριασμένες συσκευές.\"\n\n#~ msgid \"The receiver was unplugged.\"\n#~ msgstr \"Ο δέκτης αποσυνδέθηκε.\"\n\n#~ msgid \"\"\n#~ \"The wireless link between this device and its receiver is not encrypted.\\n\"\n#~ \"\\n\"\n#~ \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~ \"security issue.\\n\"\n#~ \"\\n\"\n#~ \"It is, however, a major security issue for text-input devices (keyboards, \"\n#~ \"numpads),\\n\"\n#~ \"because typed text can be sniffed inconspicuously by 3rd parties within \"\n#~ \"range.\"\n#~ msgstr \"\"\n#~ \"Η ασύρματη ζεύξη μεταξύ αυτής της συσκευής και του δέκτη της είναι χωρίς \"\n#~ \"κρυπτογράφηση.\\n\"\n#~ \"\\n\"\n#~ \"Για συσκευές κατάδειξης (ποντίκια, ιχνόσφαιρες, επιφάνειες αφής), αυτό \"\n#~ \"είναι ένα μικρό πρόβλημα ασφάλειας.\\n\"\n#~ \"\\n\"\n#~ \"Είναι όμως μεγάλο πρόβλημα ασφάλειας για συσκευές εισαγωγής κειμένου \"\n#~ \"(πληκτρολόγια),\\n\"\n#~ \"μιας και το κείμενο μπορεί να υποκλαπεί από κακόβουλους εντός εμβέλειας.\"\n\n#~ msgid \"USB id\"\n#~ msgstr \"USB id\"\n\n#~ msgid \"Up to %d devices can be paired to this receiver\"\n#~ msgstr \"Μέχρι %d συσκευές μπορούν να συνταιριαστούν σε αυτόν τον δέκτη\"\n\n#~ msgid \"closed\"\n#~ msgstr \"κλειστή\"\n\n#~ msgid \"height\"\n#~ msgstr \"ύψος\"\n\n#~ msgid \"lux\"\n#~ msgstr \"lux\"\n\n#~ msgid \"open\"\n#~ msgstr \"ανοιχτή\"\n\n#~ msgid \"pair new device\"\n#~ msgstr \"συνταίριασε μια νέα συσκευή\"\n\n#~ msgid \"paired devices\"\n#~ msgstr \"συνταιριασμένες συσκευές\"\n\n#~ msgid \"pairing lock is \"\n#~ msgstr \"το κλείδωμα ταιριάσματος είναι\"\n\n#~ msgid \"unknown\"\n#~ msgstr \"άγνωστο\"\n\n#~ msgid \"width\"\n#~ msgstr \"πλάτος\"\n"
  },
  {
    "path": "po/es.po",
    "content": "# Spanish translations for Solaar package.\n# Copyright (C) 2021 THE Solaar's COPYRIGHT HOLDER.\n# This file is distributed under the same license as the Solaar package.\n# Marc Serra <hola@webolot.com>, 2021.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 1.1.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n\"PO-Revision-Date: 2023-12-28 18:53+0100\\n\"\n\"Last-Translator: Jose Luis Tirado <joseluis.tirado@gmail.com>\\n\"\n\"Language-Team: none\\n\"\n\"Language: es\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.4.1\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid \"Bolt Receiver\"\nmsgstr \"Receptor Bolt\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid \"Unifying Receiver\"\nmsgstr \"Receptor Unifying\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid \"Nano Receiver\"\nmsgstr \"Receptor Nano\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Receptor Lightspeed\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"Receptor EX100 27 Mhz\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"empty\"\nmsgstr \"vacía\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"critical\"\nmsgstr \"crítica\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"low\"\nmsgstr \"baja\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"average\"\nmsgstr \"media\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid \"good\"\nmsgstr \"buena\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"full\"\nmsgstr \"llena\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"discharging\"\nmsgstr \"descargando\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"recharging\"\nmsgstr \"recargando\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid \"charging\"\nmsgstr \"cargando\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"not charging\"\nmsgstr \"no cargando\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"almost full\"\nmsgstr \"casi llena\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"charged\"\nmsgstr \"cargado\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"slow recharge\"\nmsgstr \"recarga lenta\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"invalid battery\"\nmsgstr \"batería no válida\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"thermal error\"\nmsgstr \"error térmico\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"error\"\nmsgstr \"error\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid \"standard\"\nmsgstr \"estándar\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"fast\"\nmsgstr \"rápido\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"slow\"\nmsgstr \"lento\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid \"device timeout\"\nmsgstr \"tiempo agotado para el dispositivo\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid \"device not supported\"\nmsgstr \"dispositivo no soportado\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"too many devices\"\nmsgstr \"demasiados dispositivos\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"sequence timeout\"\nmsgstr \"tiempo agotado de secuencia\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid \"Firmware\"\nmsgstr \"Firmware\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Bootloader\"\nmsgstr \"Gestor de arranque\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Hardware\"\nmsgstr \"Hardware\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Other\"\nmsgstr \"Otros\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Left Button\"\nmsgstr \"Botón Izquierdo\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"Right Button\"\nmsgstr \"Botón Derecho\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Middle Button\"\nmsgstr \"Botón Central\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Back Button\"\nmsgstr \"Botón Atrás\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Forward Button\"\nmsgstr \"Botón Adelante\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Mouse Gesture Button\"\nmsgstr \"Botón Gestos Ratón\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Smart Shift\"\nmsgstr \"Cambio inteligente\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"DPI Switch\"\nmsgstr \"Selector DPI\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Left Tilt\"\nmsgstr \"Inclinación a la Izquierda\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Right Tilt\"\nmsgstr \"Inclinación a la Derecha\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Left Click\"\nmsgstr \"Clic Izquierdo\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Right Click\"\nmsgstr \"Clic Derecho\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid \"Mouse Middle Button\"\nmsgstr \"Clic Central Ratón\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"Mouse Back Button\"\nmsgstr \"Clic Atrás Ratón\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"Mouse Forward Button\"\nmsgstr \"Clic Adelante Ratón\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid \"Gesture Button Navigation\"\nmsgstr \"Navegación con Botón de Gestos\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"Botón desplazamiento a la Izquierda\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"Botón de desplazamiento a la Derecha\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid \"pressed\"\nmsgstr \"pulsado\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid \"released\"\nmsgstr \"liberado\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid \"pairing lock is closed\"\nmsgstr \"el bloqueo de vinculación está cerrado\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid \"pairing lock is open\"\nmsgstr \"el bloqueo de vinculación está abierto\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid \"discovery lock is closed\"\nmsgstr \"el bloqueo de descubrimiento está cerrado\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid \"discovery lock is open\"\nmsgstr \"el bloqueo de detección está abierto\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid \"connected\"\nmsgstr \"conectado\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid \"disconnected\"\nmsgstr \"desconectado\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid \"unpaired\"\nmsgstr \"desvinculado\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid \"powered on\"\nmsgstr \"encendido\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid \"register\"\nmsgstr \"registrar\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid \"feature\"\nmsgstr \"característica\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid \"Swap Fx function\"\nmsgstr \"Intercambiar función Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"Al activarse, las teclas F1..F12 activarán sus funciones especiales,\\n\"\n\"y debe mantener pulsada la tecla FN para activar su función estándar.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"Al desactivarse, las teclas F1..F12 activarán sus funciones estándar,\\n\"\n\"y debe mantener pulsada la tecla FN para activar su función especial.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid \"Hand Detection\"\nmsgstr \"Detección de manos\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"Encender la iluminación cuando las manos pasen sobre el teclado.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"Desplazamiento suave de la rueda de desplazamiento\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"Modo de alta sensibilidad para desplazamiento vertical con la rueda.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid \"Side Scrolling\"\nmsgstr \"Desplazamiento lateral\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"Al desactivarse, presionar la rueda lateralmente envía eventos de botones \"\n\"personalizados\\n\"\n\"en vez de los eventos estándar de desplazamiento lateral.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"Sensibilidad (DPI - ratones más viejos)\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"Sensibildad de movimientro del ratón\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid \"Backlight\"\nmsgstr \"Retroiluminación\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"Establecer el tiempo de iluminación para el teclado.\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid \"Turn illumination on or off on keyboard.\"\nmsgstr \"Encencer o apagar la iluminación del teclado.\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"Rueda de Desplazamiento de Alta Resolución\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"\"\n\"Establecido para ignorar si el desplazamiento es anormalmente rápido o lento\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"Desvío de la Rueda de Desplazamiento\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Hacer que la rueda de desplazamiento envíe notificaciones HID++ de \"\n\"LOWRES_WHEEL (que activan reglas de Solaar, pero que, por lo demás, se \"\n\"ignoran).\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"Dirección de la Rueda de Desplazamiento\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"Invertir dirección para desplazamiento vertical con la rueda.\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"Resolución de la Rueda de Desplazamiento\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Hacer que la rueda de desplazamiento envíe notificaciones HID++ de \"\n\"HIRES_WHEEL (que activan las reglas de Solaar, pero que, por lo demás, se \"\n\"ignoran).\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"Sensibilidad (Velocidad del puntero)\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"\"\n\"Multiplicador de velocidad para el ratón (256 es un multiplicador normal)\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"Desvío de la Rueda del Pulgar\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Hacer que la rueda del pulgar envíe notificaciones THUMB_WHEEL HID++ (que \"\n\"desencadenan reglas de Solaar, pero que, por lo demás, se ignoran).\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"Dirección de la Rueda del Pulgar\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"Invertir la dirección de desplazamiento de la rueda del pulgar.\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid \"Onboard Profiles\"\nmsgstr \"Perfiles integrados\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid \"\"\n\"Enable onboard profiles, which often control report rate and keyboard \"\n\"lighting\"\nmsgstr \"\"\n\"Habilite los perfiles integrados, que a menudo controlan la tasa de informes \"\n\"y iluminación del teclado\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid \"Polling Rate (ms)\"\nmsgstr \"Tasa de Sondeo (ms)\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid \"Frequency of device polling, in milliseconds\"\nmsgstr \"Frecuencia de sondeo del dispositivo, en milisegundos\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"\"\n\"Es posible que los Perfiles integrados se desactiven para que sean efectivos.\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid \"Divert crown events\"\nmsgstr \"Desviar eventos de la corona\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Hacer que la corona envíe notificaciones de CROWN HID ++ (que activan las \"\n\"reglas de Solaar, pero que, por lo demás, se ignoran).\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid \"Crown smooth scroll\"\nmsgstr \"Desplazamiento suave de la corona\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid \"Set crown smooth scroll\"\nmsgstr \"Establecer desplazamiento suave de la corona\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid \"Divert G Keys\"\nmsgstr \"Desviar Teclas G\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid \"\"\n\"Make G keys send GKEY HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Hacer que las teclas G envíen notificaciones GKEY HID ++ (que activan las \"\n\"reglas de Solaar, pero que, por lo demás, se ignoran).\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid \"May also make M keys and MR key send HID++ notifications\"\nmsgstr \"También puede hacer que las teclas M y  MR envíen notificaciones HID++\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"Rueda de desplazamiento con carraca\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"\"\n\"Cambie la rueda del ratón entre carraca controlada por velocidad y siempre \"\n\"giro libre.\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid \"Freespinning\"\nmsgstr \"Giro libre\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid \"Ratcheted\"\nmsgstr \"Carraca\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"Rueda de desplazamiento Velocidad de carraca\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"Utilice la velocidad de la rueda del ratón para cambiar entre carraca y giro \"\n\"libre.\\n\"\n\"La rueda del mouse siempre está ajustada a 50.\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid \"Key/Button Actions\"\nmsgstr \"Acciones de Tecla/Botón\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid \"Change the action for the key or button.\"\nmsgstr \"Cambiar la acción para la tecla o botón.\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid \"Overridden by diversion.\"\nmsgstr \"Anulado por la diversión.\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"\"\n\"Cambiar acciones importantes (por ejemplo el botón izquierdo del ratón) \"\n\"puede dejar su sistema inutilizable.\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid \"Key/Button Diversion\"\nmsgstr \"Desvio de Tecla/Botón\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse \"\n\"Gestures or Sliding DPI\"\nmsgstr \"\"\n\"Haga que la tecla o el botón envíe notificaciones HID++ (Desviado) o iniciar \"\n\"gestos de mouse o DPI deslizante\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid \"Diverted\"\nmsgstr \"Desviado\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid \"Mouse Gestures\"\nmsgstr \"Gestos de Ratón\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid \"Regular\"\nmsgstr \"Normal\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid \"Sliding DPI\"\nmsgstr \"DPI deslizante\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"Sensibilidad (PPP)\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid \"Sensitivity Switching\"\nmsgstr \"Cambio de sensibilidad\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key \"\n\"or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\"Cambie la sensibilidad actual y la sensibilidad recordada cuando se presiona \"\n\"la tecla o el botón.\\n\"\n\"Si no hay sensibilidad recordada, solo recuerde la corriente sensibilidad\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid \"Off\"\nmsgstr \"Off\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid \"Disable keys\"\nmsgstr \"Desactivar teclas\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"Desactivar teclas específicas del teclado.\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"Desactiva la tecla %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid \"Set OS\"\nmsgstr \"Especificar SO\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid \"Change keys to match OS.\"\nmsgstr \"Cambiar teclas para coincidir son el S.O.\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid \"Change Host\"\nmsgstr \"Cambiar Equipo\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid \"Switch connection to a different host\"\nmsgstr \"Cambiar la conexión a un equipo diferente\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid \"Performs a left click.\"\nmsgstr \"Realiza un clic izquierdo.\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid \"Single tap\"\nmsgstr \"Un toque\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid \"Performs a right click.\"\nmsgstr \"Realiza un click derecho.\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid \"Single tap with two fingers\"\nmsgstr \"Un toque con dos dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid \"Single tap with three fingers\"\nmsgstr \"Un toque con tres dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid \"Double tap\"\nmsgstr \"Doble toque\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid \"Performs a double click.\"\nmsgstr \"Realiza un click doble.\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid \"Double tap with two fingers\"\nmsgstr \"Doble toque con dos dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid \"Double tap with three fingers\"\nmsgstr \"Doble toque con tres dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"Arrastra elementos arrastrando el dedo después de tocar dos veces.\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid \"Tap and drag\"\nmsgstr \"Tocar y arrastrar\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"Arrastra elementos arrastrando los dedos después de tocar dos veces.\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"Tocar y arrastrar con dos dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"Tocar y arrastrar con tres dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"\"\n\"Desactiva los gestos de toque y borde (equivalente a pulsar \"\n\"Fn+ClicIzquierdo).\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"Elimina los gestos de toque y borde\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid \"Scroll with one finger\"\nmsgstr \"Desplaza con un dedo\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid \"Scrolls.\"\nmsgstr \"Desplazamiento.\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid \"Scroll with two fingers\"\nmsgstr \"Desplaza con dos dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"Desplaza horizontalmente con dos dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid \"Scrolls horizontally.\"\nmsgstr \"Desplaza horizontalmente.\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"Desplazar verticalmente con dos dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid \"Scrolls vertically.\"\nmsgstr \"Desplaza verticalmente.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"Invierte la dirección de desplazamiento.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid \"Natural scrolling\"\nmsgstr \"Desplazamiento natural\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"Activa la rueda del pulgar.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid \"Thumbwheel\"\nmsgstr \"Rueda del pulgar\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid \"Swipe from the top edge\"\nmsgstr \"Deslizar desde el borde superior\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid \"Swipe from the left edge\"\nmsgstr \"Deslizar desde el borde izquierdo\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid \"Swipe from the right edge\"\nmsgstr \"Deslizar desde el borde derecho\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"Deslizar desde el borde inferior\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"Deslizar dos dedos desde el borde izquierdo\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"Deslizar dos dedos desde el borde derecho\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"Deslizar dos dedos desde el borde inferior\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"Deslizar dos dedos desde el borde superior\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"Pellizcar para alejar; Extender para acercar.\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid \"Zoom with two fingers.\"\nmsgstr \"Zoom con dos dedos.\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid \"Pinch to zoom out.\"\nmsgstr \"Pellizcar para alejar.\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid \"Spread to zoom in.\"\nmsgstr \"Extender para acercar.\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid \"Zoom with three fingers.\"\nmsgstr \"Zoom con tres dedos.\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid \"Zoom with two fingers\"\nmsgstr \"Zoom con dos dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid \"Pixel zone\"\nmsgstr \"Zona de píxeles\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid \"Ratio zone\"\nmsgstr \"Zona de relación\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid \"Scale factor\"\nmsgstr \"Factor de escalado\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid \"Sets the cursor speed.\"\nmsgstr \"Establece la velocidad del cursor.\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid \"Left\"\nmsgstr \"Izquierda\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid \"Left-most coordinate.\"\nmsgstr \"Coordenada más a la izquierda.\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid \"Bottom\"\nmsgstr \"Abajo\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid \"Bottom coordinate.\"\nmsgstr \"Coordenada inferior.\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid \"Width\"\nmsgstr \"Anchura\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid \"Width.\"\nmsgstr \"Anchura.\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid \"Height\"\nmsgstr \"Altura\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid \"Height.\"\nmsgstr \"Altura.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid \"Cursor speed.\"\nmsgstr \"Velocidad del cursor.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid \"Scale\"\nmsgstr \"Escala\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid \"Gestures\"\nmsgstr \"Gestos\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"Modificar el comportamiento del mouse/panel táctil.\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid \"Gestures Diversion\"\nmsgstr \"Desvío de gestos\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"Desviar los gestos del mouse/panel táctil.\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid \"Gesture params\"\nmsgstr \"Parámetros de gestos\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"Cambiar parámetros numéricos de un mouse/panel táctil.\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid \"M-Key LEDs\"\nmsgstr \"LEDs de teclas M\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"Control de los LEDs de teclas M.\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"Puede necesitar desviar las llaves G para ser efectiva.\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"Se enciende la tecla %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid \"MR-Key LED\"\nmsgstr \"MR-Key LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"Controle el LED MR-Key.\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"Asignación persistente de teclas/botones\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"Cambie permanentemente la asignación de la tecla o el botón.\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"\"\n\"Cambiar teclas o botones importantes (como el botón izquierdo del ratón) \"\n\"puede resultar en un sistema inutilizable.\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid \"Sidetone\"\nmsgstr \"Tono lateral\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid \"Set sidetone level.\"\nmsgstr \"Establezca el nivel de tono lateral.\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid \"Equalizer\"\nmsgstr \"Ecualizador\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid \"Set equalizer levels.\"\nmsgstr \"Establecer niveles del ecualizador.\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid \"Hz\"\nmsgstr \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid \"Power Management\"\nmsgstr \"Gestión de energía\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"Apagar a los minutos (0 para nunca)\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid \"No paired devices.\"\nmsgstr \"Ningún dispositivo conectado.\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s dispositivo vinculado.\"\nmsgstr[1] \"%(count)s dispositivos vinculados.\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid \"Battery: %(level)s\"\nmsgstr \"Batería: %(level)s\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid \"Battery: %(percent)d%%\"\nmsgstr \"Batería: %(percent)d%%\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid \"Lighting: %(level)s lux\"\nmsgstr \"Iluminación: %(level)s lux\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"Batería: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"Batería: %(percent)d%% (%(status)s)\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid \"Permissions error\"\nmsgstr \"Error de permisos\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"\"\n\"Se ha encontrado un receptor Logitech o dispositivo (%s), pero no se dispone \"\n\"de permisos para abrirlo.\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"\"\n\"Si acaba de instalar Solaar, pruebe a desconectar y volver a conectar el \"\n\"receptor o dispositivo.\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid \"Cannot connect to device error\"\nmsgstr \"Error al conectar al dispositivo\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"Se encontró un receptor o dispositivo Logitech en %s, pero se produjo un \"\n\"error al conectarse.\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"\"\n\"Pruebe a desconectar y volver a conectar el dispositivo o a apagarlo y \"\n\"encenderlo de nuevo.\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid \"Unpairing failed\"\nmsgstr \"Desvinculación fallida\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"Fallo al desvincular %{device} de %{receiver}.\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"El receptor devolvió un error, sin detalles adicionales.\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"\"\n\"Ya se está ejecutando otro proceso de Solaar, así que simplemente se muestra \"\n\"su ventana\"\n\n#: lib/solaar/ui/about.py:36\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"Gestiona receptores Logitech,\\n\"\n\"teclados, ratones y tabletas.\"\n\n#: lib/solaar/ui/about.py:44\nmsgid \"Additional Programming\"\nmsgstr \"Programación adicional\"\n\n#: lib/solaar/ui/about.py:45\nmsgid \"GUI design\"\nmsgstr \"Diseño de la interfaz gráfica\"\n\n#: lib/solaar/ui/about.py:47\nmsgid \"Testing\"\nmsgstr \"Prueba\"\n\n#: lib/solaar/ui/about.py:54\nmsgid \"Logitech documentation\"\nmsgstr \"Documentación de Logitech\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid \"Unpair\"\nmsgstr \"Desvincular\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid \"Cancel\"\nmsgstr \"Cancelar\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid \"Complete - ENTER to change\"\nmsgstr \"Completa - ENTER para cambiar\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid \"Incomplete\"\nmsgstr \"Incompleta\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d valor\"\nmsgstr[1] \"%d valores\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid \"Changes allowed\"\nmsgstr \"Cambios permitidos\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid \"No changes allowed\"\nmsgstr \"Cambios no permitidos\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid \"Ignore this setting\"\nmsgstr \"Ignorar esta opción\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid \"Working\"\nmsgstr \"Funcionando\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid \"Read/write operation failed.\"\nmsgstr \"Operación de lectura/escritura fallida.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid \"Built-in rules\"\nmsgstr \"Reglas integradas\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid \"User-defined rules\"\nmsgstr \"Reglas definidas por el usuario\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid \"Rule\"\nmsgstr \"Regla\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid \"Sub-rule\"\nmsgstr \"Subregla\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid \"[empty]\"\nmsgstr \"[vacío]\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Editor de Reglas Solaar\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid \"Make changes permanent?\"\nmsgstr \"¿Hacer los cambios permanentes?\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid \"Yes\"\nmsgstr \"Sí\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid \"No\"\nmsgstr \"No\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"Si elige No, los cambios se perderán cuando se cierre Solaar.\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid \"Save changes\"\nmsgstr \"Guardar cambios\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid \"Discard changes\"\nmsgstr \"Descartar cambios\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid \"Insert here\"\nmsgstr \"Insertar aquí\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid \"Insert above\"\nmsgstr \"Insertar encima\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid \"Insert below\"\nmsgstr \"Insertar debajo\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid \"Insert new rule here\"\nmsgstr \"Insertar nueva regla aquí\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid \"Insert new rule above\"\nmsgstr \"Insertar nueva regla encima\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid \"Insert new rule below\"\nmsgstr \"Insertar nueva regla debajo\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid \"Paste here\"\nmsgstr \"Pegar aquí\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid \"Paste above\"\nmsgstr \"Pegar encima\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid \"Paste below\"\nmsgstr \"Pegar debajo\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid \"Paste rule here\"\nmsgstr \"Pegar regla aquí\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid \"Paste rule above\"\nmsgstr \"Pegar regla encima\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid \"Paste rule below\"\nmsgstr \"Pegar regla debajo\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid \"Paste rule\"\nmsgstr \"Pegar regla\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid \"Flatten\"\nmsgstr \"Aplanar\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid \"Insert\"\nmsgstr \"Insertar\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid \"Or\"\nmsgstr \"O\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid \"And\"\nmsgstr \"Y\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid \"Condition\"\nmsgstr \"Condición\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid \"Feature\"\nmsgstr \"Característica\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid \"Report\"\nmsgstr \"Informar\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid \"Process\"\nmsgstr \"Proceso\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid \"Mouse process\"\nmsgstr \"Proceso de ratón\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid \"Modifiers\"\nmsgstr \"Modificadores\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid \"Key\"\nmsgstr \"Tecla\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid \"KeyIsDown\"\nmsgstr \"TeclaPulsada\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid \"Active\"\nmsgstr \"Activo\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid \"Device\"\nmsgstr \"Dispositivo\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid \"Host\"\nmsgstr \"Equipo\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid \"Setting\"\nmsgstr \"Ajuste\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid \"Test\"\nmsgstr \"Prueba\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid \"Test bytes\"\nmsgstr \"Bytes de prueba\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid \"Mouse Gesture\"\nmsgstr \"Gesto de Ratón\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid \"Action\"\nmsgstr \"Acción\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid \"Key press\"\nmsgstr \"Pulsación de tecla\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid \"Mouse scroll\"\nmsgstr \"Desplazamiento rueda del ratón\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid \"Mouse click\"\nmsgstr \"Click del ratón\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid \"Set\"\nmsgstr \"Establecer\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid \"Execute\"\nmsgstr \"Ejecutar\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid \"Later\"\nmsgstr \"Luego\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid \"Insert new rule\"\nmsgstr \"Añadir nueva regla\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid \"Delete\"\nmsgstr \"Borrar\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid \"Negate\"\nmsgstr \"Negar\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid \"Wrap with\"\nmsgstr \"Envolver con\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid \"Cut\"\nmsgstr \"Cortar\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid \"Paste\"\nmsgstr \"Pegar\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid \"Copy\"\nmsgstr \"Copiar\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"\"\n\"Este editor aún no es compatible con el componente de regla seleccionado.\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid \"Number of seconds to delay.\"\nmsgstr \"Número de segundos a retrasar.\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid \"Not\"\nmsgstr \"No\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"Proceso activo X11. Solo para uso en X11.\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"Proceso de ratón X11. Solo para uso en X11.\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid \"MouseProcess\"\nmsgstr \"ProcesoRatón\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"\"\n\"Nombre de la característica del procesamiento de la regla de activación de \"\n\"notificaciones.\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"\"\n\"Número de informe de procesamiento de regla de activación de notificación.\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"Modificadores de teclado activos. No siempre disponible en Wayland.\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Tecla desviada o botón pulsado o liberado.\\n\"\n\"Use Desvío de Tecla/Botón y Desviar de Teclas G para desviar teclas y \"\n\"botones.\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid \"Key down\"\nmsgstr \"Tecla abajo\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid \"Key up\"\nmsgstr \"Tecla arriba\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"La tecla o botón desviado está actualmente pulsado.\\n\"\n\"Use los ajustes Desvío de Tecla/Botón y Desviar Teclas G para desviar teclas \"\n\"y botones.\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"\"\n\"Condición de prueba en el procesamiento de la regla de activación de \"\n\"notificación.\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid \"Parameter\"\nmsgstr \"Parámetro\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid \"begin (inclusive)\"\nmsgstr \"inicio (incluido)\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid \"end (exclusive)\"\nmsgstr \"fin (excluido)\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid \"range\"\nmsgstr \"rango\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid \"minimum\"\nmsgstr \"mínimo\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid \"maximum\"\nmsgstr \"máximo\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"bytes %(0)d a %(1)d, que van desde %(2)d a %(3)d\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid \"mask\"\nmsgstr \"máscara\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"bytes %(0)d a %(1)d, máscara %(2)d\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\"Prueba de bit o rango en bytes en el mensaje de notificación que activa el \"\n\"procesamiento de reglas.\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid \"type\"\nmsgstr \"tipo\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"\"\n\"Gesto del mouse con botón de inicio opcional seguido de cero o más \"\n\"movimientos del mouse.\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid \"Add movement\"\nmsgstr \"Añadir movimiento\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simular un clic de teclas combinadas o pulsación o liberación.\\n\"\n\"En Wayland requiere acceso de escritura a /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid \"Add key\"\nmsgstr \"Añadir tecla\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid \"Click\"\nmsgstr \"Hacer clic\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid \"Depress\"\nmsgstr \"Pulsar\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid \"Release\"\nmsgstr \"Liberar\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simular un desplazamiento del ratón.\\n\"\n\"En Wayland requiere acceso de escritura a /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simular un clic del ratón.\\n\"\n\"En Wayland requiere acceso de escritura a /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid \"Button\"\nmsgstr \"Botón\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid \"Count and Action\"\nmsgstr \"Pulsaciones y Acción\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid \"Execute a command with arguments.\"\nmsgstr \"Ejecutar un comando con parámetros.\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid \"Add argument\"\nmsgstr \"Añadir parámetro\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid \"Toggle\"\nmsgstr \"Invertir\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid \"True\"\nmsgstr \"Verdadero\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid \"False\"\nmsgstr \"Falso\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid \"Unsupported setting\"\nmsgstr \"Configuración no admitida\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid \"Originating device\"\nmsgstr \"Dispositivo emisor\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"El dispositivo está activo y su configuración se puede cambiar.\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid \"Device that originated the current notification.\"\nmsgstr \"Dispositivo que ha causado la notificación actual.\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid \"Name of host computer.\"\nmsgstr \"Nombre del equipo.\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid \"Value\"\nmsgstr \"Valor\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid \"Item\"\nmsgstr \"Artículo\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid \"Change setting on device\"\nmsgstr \"Cambiar la configuración en el dispositivo\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid \"Setting on device\"\nmsgstr \"Configuración en el dispositivo\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid \"offline\"\nmsgstr \"desconectado\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: vincular nuevo dispositivo\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"Introduzca el código de acceso en %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"Escriba %(passcode)s y luego presione la tecla Enter.\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid \"left\"\nmsgstr \"izquierda\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid \"right\"\nmsgstr \"derecha\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"Pulse %(code)s\\n\"\n\"y luego los botones izquierdo y derecho simultáneamente.\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid \"Pairing failed\"\nmsgstr \"Vinculación fallida\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"\"\n\"Asegúrese de que su dispositivo esté dentro del alcance del receptor y que \"\n\"la batería tenga suficiente carga.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"\"\n\"Se detectó un nuevo dispositivo, pero no es compatible con este receptor.\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"Más dispositivos emparejados de los que admite el receptor.\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid \"No further details are available about the error.\"\nmsgstr \"No hay más detalles disponibles sobre este error.\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid \"Found a new device:\"\nmsgstr \"Se encontró un nuevo dispositivo:\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"La conexión inalámbrica no está cifrada\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"\"\n\"Los receptores Unifying solo son compatibles con dispositivos Unifying.\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Los receptores Bolt solo son compatibles con dispositivos Bolt.\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"Otros receptores son solo compatibles con unos pocos dispositivos.\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"\"\n\"El dispositivo no se debe estar emparejado con un receptor cercano encendido.\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"\"\n\"Presione un botón o tecla de emparejamiento hasta que la luz de \"\n\"emparejamiento parpadee rápidamente.\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid \"You may have to first turn the device off and on again.\"\nmsgstr \"\"\n\"Es posible que primero deba apagar el dispositivo y volver a encenderlo.\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid \"Turn on the device you want to pair.\"\nmsgstr \"Encienda el dispositivo que desea vincular.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"Si el dispositivo ya está encendido, apague y vuelva a encenderlo.\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"Este receptor tiene %d emparejamiento restante.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"Este receptor tiene %d emparejamientos restantes.\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"Si cancela en este punto no se usará un vínculo.\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid \"No supported device found\"\nmsgstr \"No se ha encontrado ningún dispositivo compatible\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid \"About %s\"\nmsgstr \"Acerca de %s\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"Salir de %s\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid \"no receiver\"\nmsgstr \"sin receptor\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid \"no status\"\nmsgstr \"sin estado\"\n\n#: lib/solaar/ui/window.py:96\nmsgid \"Scanning\"\nmsgstr \"Explorando\"\n\n#: lib/solaar/ui/window.py:129\nmsgid \"Battery\"\nmsgstr \"Batería\"\n\n#: lib/solaar/ui/window.py:132\nmsgid \"Wireless Link\"\nmsgstr \"Enlace inalámbrico\"\n\n#: lib/solaar/ui/window.py:136\nmsgid \"Lighting\"\nmsgstr \"Iluminación\"\n\n#: lib/solaar/ui/window.py:170\nmsgid \"Show Technical Details\"\nmsgstr \"Mostrar detalles técnicos\"\n\n#: lib/solaar/ui/window.py:186\nmsgid \"Pair new device\"\nmsgstr \"Vincular nuevo dispositivo\"\n\n#: lib/solaar/ui/window.py:205\nmsgid \"Select a device\"\nmsgstr \"Seleccionar un dispositivo\"\n\n#: lib/solaar/ui/window.py:322\nmsgid \"Rule Editor\"\nmsgstr \"Editor de Reglas\"\n\n#: lib/solaar/ui/window.py:533\nmsgid \"Path\"\nmsgstr \"Ruta\"\n\n#: lib/solaar/ui/window.py:536\nmsgid \"USB ID\"\nmsgstr \"ID USB\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid \"Serial\"\nmsgstr \"Serie\"\n\n#: lib/solaar/ui/window.py:545\nmsgid \"Index\"\nmsgstr \"Índice\"\n\n#: lib/solaar/ui/window.py:547\nmsgid \"Wireless PID\"\nmsgstr \"PID inalámbrico\"\n\n#: lib/solaar/ui/window.py:549\nmsgid \"Product ID\"\nmsgstr \"ID del producto\"\n\n#: lib/solaar/ui/window.py:551\nmsgid \"Protocol\"\nmsgstr \"Protocolo\"\n\n#: lib/solaar/ui/window.py:551\nmsgid \"Unknown\"\nmsgstr \"Desconocido\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#: lib/solaar/ui/window.py:554\nmsgid \"Polling rate\"\nmsgstr \"Tasa de sondeo\"\n\n#: lib/solaar/ui/window.py:565\nmsgid \"Unit ID\"\nmsgstr \"ID Unidad\"\n\n#: lib/solaar/ui/window.py:576\nmsgid \"none\"\nmsgstr \"ninguno\"\n\n#: lib/solaar/ui/window.py:577\nmsgid \"Notifications\"\nmsgstr \"Notificaciones\"\n\n#: lib/solaar/ui/window.py:621\nmsgid \"No device paired.\"\nmsgstr \"No hay dispositivos vinculados.\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"Se puede vincular hasta %(max_count)s dispositivo a este receptor.\"\nmsgstr[1] \"\"\n\"Se pueden vincular hasta %(max_count)s dispositivos a este receptor.\"\n\n#: lib/solaar/ui/window.py:634\nmsgid \"Only one device can be paired to this receiver.\"\nmsgstr \"Solo un dispositivo se puede vincular a este receptor.\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"Este receptor tiene %d emparejamiento restante.\"\nmsgstr[1] \"Este receptor tiene %d emparejamientos restantes.\"\n\n#: lib/solaar/ui/window.py:692\nmsgid \"Battery Voltage\"\nmsgstr \"Voltaje de la batería\"\n\n#: lib/solaar/ui/window.py:694\nmsgid \"Voltage reported by battery\"\nmsgstr \"Voltaje informado por la batería\"\n\n#: lib/solaar/ui/window.py:696\nmsgid \"Battery Level\"\nmsgstr \"Nivel de Batería\"\n\n#: lib/solaar/ui/window.py:698\nmsgid \"Approximate level reported by battery\"\nmsgstr \"Nivel aproximado informado por batería\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid \"next reported \"\nmsgstr \"siguiente informe \"\n\n#: lib/solaar/ui/window.py:708\nmsgid \" and next level to be reported.\"\nmsgstr \" y siguiente nivel que será reportado.\"\n\n#: lib/solaar/ui/window.py:713\nmsgid \"last known\"\nmsgstr \"último conocido\"\n\n#: lib/solaar/ui/window.py:724\nmsgid \"encrypted\"\nmsgstr \"cifrado\"\n\n#: lib/solaar/ui/window.py:726\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"\"\n\"La conexión inalámbrica entre el dispositivo y su receptor está cifrada.\"\n\n#: lib/solaar/ui/window.py:728\nmsgid \"not encrypted\"\nmsgstr \"no cifrado\"\n\n#: lib/solaar/ui/window.py:732\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"El enlace inalámbrico entre este dispositivo y su receptor no está \"\n\"encriptado.\\n\"\n\"Este es un problema de seguridad para los dispositivos señaladores y un \"\n\"problema de seguridad importante para los dispositivos de entrada de texto.\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d lux\"\n\n#~ msgid \"\"\n#~ \"\\n\"\n#~ \"\\n\"\n#~ \"This receiver has %d pairing(s) remaining.\"\n#~ msgstr \"\"\n#~ \"\\n\"\n#~ \"\\n\"\n#~ \"Este receptor tiene %d vínculo(s) disponibles.\"\n\n#~ msgid \"%(battery_level)s\"\n#~ msgstr \"%(battery_level)s\"\n\n#~ msgid \"%(battery_percent)d%%\"\n#~ msgstr \"%(battery_percent)d%%\"\n\n#~ msgid \"Add action\"\n#~ msgstr \"Añadir acción\"\n\n#~ msgid \"\"\n#~ \"Adjust the DPI by sliding the mouse horizontally while holding the button \"\n#~ \"down.\"\n#~ msgstr \"\"\n#~ \"Ajustar los DPI deslizando el ratón horizontalmente mientras se mantiene \"\n#~ \"el botón presionado.\"\n\n#~ msgid \"\"\n#~ \"Automatically switch the mouse wheel between ratchet and freespin mode.\\n\"\n#~ \"The mouse wheel is always free at 0, and always locked at 50\"\n#~ msgstr \"\"\n#~ \"Cambia automáticamente el modo de la rueda del ratón entre bloqueado y \"\n#~ \"giro libre.\\n\"\n#~ \"La rueda del ratón siempre está libre a 0 y siempre bloqueado a 50\"\n\n#~ msgid \"\"\n#~ \"Automatically switch the mouse wheel between ratchet and freespin mode.\\n\"\n#~ \"The mouse wheel is always free at 0, and always ratcheted at 50\"\n#~ msgstr \"\"\n#~ \"Cambiar automáticamente la rueda del mouse entre el modo de trinquete y \"\n#~ \"el modo de giro libre.\\n\"\n#~ \"La rueda del mouse siempre está libre en 0 y siempre con trinquete en 50\"\n\n#~ msgid \"Battery information unknown.\"\n#~ msgstr \"Información de la batería desconocida.\"\n\n#~ msgid \"Count\"\n#~ msgstr \"Cuenta\"\n\n#~ msgid \"DPI Sliding Adjustment\"\n#~ msgstr \"Ajustar DPI deslizando\"\n\n#~ msgid \"\"\n#~ \"Diverted key or button depressed or released.\\n\"\n#~ \"Use the Key/Button Diversion setting to divert keys and buttons.\"\n#~ msgstr \"\"\n#~ \"Tecla desviada o botón presionado o liberado.\\n\"\n#~ \"Use la configuración Desvío de teclas/botones para desviar teclas y \"\n#~ \"botones.\"\n\n#~ msgid \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr \"Desactiva eficazmente el desplazamiento con el pulgar en Linux.\"\n\n#~ msgid \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr \"Desactiva eficazmente el desplazamiento de la rueda en Linux.\"\n\n#, python-format\n#~ msgid \"\"\n#~ \"Found a Logitech Receiver (%s), but did not have permission to open it.\"\n#~ msgstr \"\"\n#~ \"Se encontró un receptor Logitech (%s), pero no tiene permisos para \"\n#~ \"abrirlo.\"\n\n#~ msgid \"HID++ Scrolling\"\n#~ msgstr \"Desplazamiento HID++\"\n\n#~ msgid \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr \"Modo HID++ para desplazamientor horizontal con la rueda del pulgar.\"\n\n#~ msgid \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr \"Modo HID++ para el desplazamiento vertical con la rueda.\"\n\n#~ msgid \"High Resolution Scrolling\"\n#~ msgstr \"Desplazamiento de alta resolución\"\n\n#~ msgid \"High Resolution Wheel Invert\"\n#~ msgstr \"Invertir rueda en alta resolución \"\n\n#~ msgid \"High-sensitivity wheel invert mode for vertical scroll.\"\n#~ msgstr \"\"\n#~ \"Modo inverso de alta resolución en la rueda para desplazamiento vertical.\"\n\n#~ msgid \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr \"\"\n#~ \"Si el dispositivo ya está encendido, apáguelo y vuelva a encenderlo.\"\n\n#~ msgid \"\"\n#~ \"If you've just installed Solaar, try removing the receiver and plugging \"\n#~ \"it back in.\"\n#~ msgstr \"\"\n#~ \"Si acaba de instalar Solaar, intente quitar el receptor y conectarlo de \"\n#~ \"nuevo.\"\n\n#~ msgid \"\"\n#~ \"Make the key or button send HID++ notifications (which trigger Solaar \"\n#~ \"rules but are otherwise ignored).\"\n#~ msgstr \"\"\n#~ \"Haga que la tecla o el botón envíe notificaciones HID ++ (que activan las \"\n#~ \"reglas de Solaar, de lo contrario se ignoran).\"\n\n#~ msgid \"No Logitech device found\"\n#~ msgstr \"No se encontró ningún dispositivo Logitech\"\n\n#~ msgid \"No Logitech receiver found\"\n#~ msgstr \"No se encontró ningún receptor Logitech\"\n\n#~ msgid \"Scroll Wheel Rachet\"\n#~ msgstr \"Trinquete Rueda Desplazamiento\"\n\n#~ msgid \"Send a gesture by sliding the mouse while holding the button down.\"\n#~ msgstr \"\"\n#~ \"Envíe un gesto deslizando el ratón mientras mantiene presionado el botón.\"\n\n#~ msgid \"\"\n#~ \"Shows status of devices connected\\n\"\n#~ \"through wireless Logitech receivers.\"\n#~ msgstr \"\"\n#~ \"Mostrar el estado de dispositivos conectados\\n\"\n#~ \"mediante receptores inalámbricos Logitech.\"\n\n#~ msgid \"Smooth Scrolling\"\n#~ msgstr \"Desplazamiento suave\"\n\n#~ msgid \"The receiver only supports %d paired device(s).\"\n#~ msgstr \"El receptor solo soporta %d dispositivo(s) vinculado(s).\"\n\n#~ msgid \"The receiver was unplugged.\"\n#~ msgstr \"El receptor se desconectó.\"\n\n#~ msgid \"\"\n#~ \"The wireless link between this device and its receiver is not encrypted.\\n\"\n#~ \"\\n\"\n#~ \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~ \"security issue.\\n\"\n#~ \"\\n\"\n#~ \"It is, however, a major security issue for text-input devices (keyboards, \"\n#~ \"numpads),\\n\"\n#~ \"because typed text can be sniffed inconspicuously by 3rd parties within \"\n#~ \"range.\"\n#~ msgstr \"\"\n#~ \"La conexión inalámbrica entre el dispositivo y su receptor no está \"\n#~ \"cifrada.\\n\"\n#~ \"\\n\"\n#~ \"Para dispositivos apuntadores (ratones, trackballs, trackpads), este es \"\n#~ \"un problema menor de seguridad.\\n\"\n#~ \"\\n\"\n#~ \"Sin embargo, para dispositivos de entrada de texto (teclados, teclados \"\n#~ \"numéricos) sí es un problema grave,\\n\"\n#~ \"pues el texto introducido puede ser capturado de forma inadvertida por \"\n#~ \"terceros que estén cerca.\"\n\n#~ msgid \"This receiver has %d pairing(s) remaining.\"\n#~ msgstr \"Este receptor tiene %d vínculo(s) disponibles.\"\n\n#~ msgid \"Top-most coordinate.\"\n#~ msgstr \"Coordenada superior.\"\n\n#~ msgid \"\"\n#~ \"Try removing the device and plugging it back in or turning it off and \"\n#~ \"then on.\"\n#~ msgstr \"\"\n#~ \"Intente quitar el dispositivo y volver a enchufarlo o apagarlo y \"\n#~ \"encenderlo.\"\n\n#~ msgid \"USB id\"\n#~ msgstr \"id USB\"\n\n#~ msgid \"Wheel Resolution\"\n#~ msgstr \"Resolución de la rueda\"\n\n#~ msgid \"height\"\n#~ msgstr \"altura\"\n\n#~ msgid \"top\"\n#~ msgstr \"superior\"\n\n#~ msgid \"unknown\"\n#~ msgstr \"desconocido\"\n\n#~ msgid \"width\"\n#~ msgstr \"anchura\"\n"
  },
  {
    "path": "po/fi.po",
    "content": "# Finnish translations for solaar package.\n# Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2013.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 0.9.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-03-05 13:08+0200\\n\"\n\"PO-Revision-Date: 2013-08-05 18:49+0300\\n\"\n\"Last-Translator: Niko Savola\\n\"\n\"Language-Team: none\\n\"\n\"Language: fi\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\n#: lib/logitech_receiver/base_usb.py:52\nmsgid \"Bolt Receiver\"\nmsgstr \"Bolt-vastaanotin\"\n\n#: lib/logitech_receiver/base_usb.py:64\nmsgid \"Unifying Receiver\"\nmsgstr \"Unifying-vastaanotin\"\n\n#: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87\n#: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113\nmsgid \"Nano Receiver\"\nmsgstr \"Nano-vastaanotin\"\n\n#: lib/logitech_receiver/base_usb.py:125\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Lightspeed-vastaanotin\"\n\n#: lib/logitech_receiver/base_usb.py:136\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"EX100 27 MHz -vastaanotin\"\n\n#: lib/logitech_receiver/common.py:649\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"Akku: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:652\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"Akku: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:1048\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid \"Disabled\"\nmsgstr \"Pois käytöstä\"\n\n#: lib/logitech_receiver/hidpp20.py:1049\nmsgid \"Static\"\nmsgstr \"Muuttumaton\"\n\n#: lib/logitech_receiver/hidpp20.py:1050\nmsgid \"Pulse\"\nmsgstr \"Pulssi\"\n\n#: lib/logitech_receiver/hidpp20.py:1051\nmsgid \"Cycle\"\nmsgstr \"Jakso\"\n\n#: lib/logitech_receiver/hidpp20.py:1052\nmsgid \"Boot\"\nmsgstr \"Käynnistys\"\n\n#: lib/logitech_receiver/hidpp20.py:1053\nmsgid \"Demo\"\nmsgstr \"Esittely\"\n\n#: lib/logitech_receiver/hidpp20.py:1055\nmsgid \"Breathe\"\nmsgstr \"Hengitys\"\n\n#: lib/logitech_receiver/hidpp20.py:1058\nmsgid \"Ripple\"\nmsgstr \"Väreily\"\n\n#: lib/logitech_receiver/hidpp20.py:1059\nmsgid \"Decomposition\"\nmsgstr \"Hajoaminen\"\n\n#: lib/logitech_receiver/hidpp20.py:1060\nmsgid \"Signature1\"\nmsgstr \"Allekirjoitus1\"\n\n#: lib/logitech_receiver/hidpp20.py:1061\nmsgid \"Signature2\"\nmsgstr \"Allekirjoitus2\"\n\n#: lib/logitech_receiver/hidpp20.py:1062\nmsgid \"CycleS\"\nmsgstr \"SykliS\"\n\n#: lib/logitech_receiver/hidpp20.py:1126\nmsgid \"Unknown Location\"\nmsgstr \"Tuntematon sijainti\"\n\n#: lib/logitech_receiver/hidpp20.py:1127\nmsgid \"Primary\"\nmsgstr \"Ensisijainen\"\n\n#: lib/logitech_receiver/hidpp20.py:1128\nmsgid \"Logo\"\nmsgstr \"Logo\"\n\n#: lib/logitech_receiver/hidpp20.py:1129\nmsgid \"Left Side\"\nmsgstr \"Vasen puoli\"\n\n#: lib/logitech_receiver/hidpp20.py:1130\nmsgid \"Right Side\"\nmsgstr \"Oikea puoli\"\n\n#: lib/logitech_receiver/hidpp20.py:1131\nmsgid \"Combined\"\nmsgstr \"Yhdistetty\"\n\n#: lib/logitech_receiver/hidpp20.py:1132\nmsgid \"Primary 1\"\nmsgstr \"Ensisijainen 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1133\nmsgid \"Primary 2\"\nmsgstr \"Ensisijainen 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1134\nmsgid \"Primary 3\"\nmsgstr \"Ensisijainen 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1135\nmsgid \"Primary 4\"\nmsgstr \"Ensisijainen 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1136\nmsgid \"Primary 5\"\nmsgstr \"Ensisijainen 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1137\nmsgid \"Primary 6\"\nmsgstr \"Ensisijainen 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"tyhjä\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"kriittinen\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"matala\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"keskiarvo\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"hyvä\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"täysi\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"tyhjenee\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"latautuu\"\n\n#: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700\nmsgid \"charging\"\nmsgstr \"lataa\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"ei latauksessa\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"lähes täysi\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"ladattu\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"hidas lataus\"\n\n#: lib/logitech_receiver/i18n.py:42\n#, fuzzy\nmsgid \"invalid battery\"\nmsgstr \"virheellinen akku\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"lämpötilasta johtuva virhe\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"virhe\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"vakio\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"nopea\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"hidas\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"laitteen aikakatkaisu\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"laite ei ole tuettu\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"liian monta laitetta\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"sarjan aikakatkaisu\"\n\n#: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555\nmsgid \"Firmware\"\nmsgstr \"Laiteohjelmisto\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"Alkulatausohjelma\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"Laitteisto\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"Muu\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"Vasen painike\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"Oikea painike\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"Keskipainike\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"Edellinen-painike\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"Seuraava-painike\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"Hiiren elepainike\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"Smart Shift\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"DPI-kytkin\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"Kallistus vasemmalle\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"Kallistus oikealle\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"Vasen napsautus\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"Oikea napsautus\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"Hiiren keskipainike\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"Hiiren edellinen-painike\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"Hiiren seuraava-painike\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"Elepainikkeen navigointi\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"Hiiren vieritys vasemmalle -painike\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"Hiiren vieritys oikealle -painike\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"painettu\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"vapautettu\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"connected\"\nmsgstr \"yhdistetty\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"disconnected\"\nmsgstr \"yhteys katkaistu\"\n\n#: lib/logitech_receiver/notifications.py:182\nmsgid \"unpaired\"\nmsgstr \"parittamaton\"\n\n#: lib/logitech_receiver/notifications.py:231\nmsgid \"powered on\"\nmsgstr \"virta päällä\"\n\n#: lib/logitech_receiver/notifications.py:283\nmsgid \"ADC measurement notification\"\nmsgstr \"ADC-mittausilmoitus\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:484\nmsgid \"pairing lock is closed\"\nmsgstr \"parituslukko on suljettu\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:484\nmsgid \"pairing lock is open\"\nmsgstr \"parituslukko on auki\"\n\n#: lib/logitech_receiver/notifications.py:447\nmsgid \"discovery lock is closed\"\nmsgstr \"etsintälukko on suljettu\"\n\n#: lib/logitech_receiver/notifications.py:447\nmsgid \"discovery lock is open\"\nmsgstr \"etsintälukko on auki\"\n\n#: lib/logitech_receiver/receiver.py:437\nmsgid \"No paired devices.\"\nmsgstr \"Ei paritettuja laitteita.\"\n\n#: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s paritettu laite.\"\nmsgstr[1] \"%(count)s paritettua laitetta.\"\n\n#: lib/logitech_receiver/settings.py:602\nmsgid \"register\"\nmsgstr \"rekisteri\"\n\n#: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654\nmsgid \"feature\"\nmsgstr \"ominaisuus\"\n\n#: lib/logitech_receiver/settings_templates.py:138\nmsgid \"Swap Fx function\"\nmsgstr \"Vaihda Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:141\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"Asetettu: F1..F12 näppäimet aktivoivat erityistoimintonsa ja \\n\"\n\"FN-näppäintä on painettava, jotta ne aktivoisivat normaalin\\n\"\n\"toimintonsa.\"\n\n#: lib/logitech_receiver/settings_templates.py:146\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"Ei asetettu: F1..F12 näppäimet aktivoivat tavallisen toimintonsa\\n\"\n\"ja FN-näppäintä on painettava, jotta ne aktivoisivat\\n\"\n\"erityistoimintonsa.\"\n\n#: lib/logitech_receiver/settings_templates.py:154\nmsgid \"Hand Detection\"\nmsgstr \"Käsien tunnistus\"\n\n#: lib/logitech_receiver/settings_templates.py:155\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"Käynnistä valaistus, kun kädet ovat näppämistön yläpuolella.\"\n\n#: lib/logitech_receiver/settings_templates.py:162\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"Vierityspyörän sulava vieritys\"\n\n#: lib/logitech_receiver/settings_templates.py:163\n#: lib/logitech_receiver/settings_templates.py:410\n#: lib/logitech_receiver/settings_templates.py:439\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"Korkean herkkyyden tila pystyvieritykseen hiiren rullalla.\"\n\n#: lib/logitech_receiver/settings_templates.py:170\nmsgid \"Side Scrolling\"\nmsgstr \"Sivuttaisvieritys\"\n\n#: lib/logitech_receiver/settings_templates.py:172\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"Pois päältä ollessaan, rullan painaminen sivuttain lähettää muokattuja\\n\"\n\"toimintoja normaalien sivuttaisvieritystoimintojen sijaan.\"\n\n#: lib/logitech_receiver/settings_templates.py:182\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"Herkkyys (DPI - vanhemmat hiiret)\"\n\n#: lib/logitech_receiver/settings_templates.py:183\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"Hiiren liikkeen herkkyys\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid \"Backlight Timed\"\nmsgstr \"Ajastettu taustavalo\"\n\n#: lib/logitech_receiver/settings_templates.py:257\n#: lib/logitech_receiver/settings_templates.py:397\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"Aseta näppäimistön valaistusaika.\"\n\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid \"Backlight\"\nmsgstr \"Taustavalo\"\n\n#: lib/logitech_receiver/settings_templates.py:269\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"\"\n\"Näppäimistön valaistustaso.  Tehdyt muutokset otetaan käyttöön vain \"\n\"manuaalisessa tilassa.\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid \"Automatic\"\nmsgstr \"Automaattinen\"\n\n#: lib/logitech_receiver/settings_templates.py:303\nmsgid \"Manual\"\nmsgstr \"Manuaalinen\"\n\n#: lib/logitech_receiver/settings_templates.py:305\nmsgid \"Enabled\"\nmsgstr \"Käytössä\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid \"Backlight Level\"\nmsgstr \"Taustavalon taso\"\n\n#: lib/logitech_receiver/settings_templates.py:312\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"Näppäimistön valaistustaso manuaalisessa tilassa.\"\n\n#: lib/logitech_receiver/settings_templates.py:369\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"Taustavalon viive, kädet poissa\"\n\n#: lib/logitech_receiver/settings_templates.py:370\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"Taustavalon viive sekunneissa, kun kädet ovat poissa näppäimistöltä.\"\n\n#: lib/logitech_receiver/settings_templates.py:378\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"Taustavalon viive, kädet lähellä\"\n\n#: lib/logitech_receiver/settings_templates.py:379\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"Taustavalon viive sekunneissa, kun kädet ovat näppäimistön lähellä.\"\n\n#: lib/logitech_receiver/settings_templates.py:387\nmsgid \"Backlight Delay Powered\"\nmsgstr \"Taustavalon viive kytkettynä\"\n\n#: lib/logitech_receiver/settings_templates.py:388\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"Taustavalon viive sekunneissa ulkoiseen virtaan kytkettynä.\"\n\n#: lib/logitech_receiver/settings_templates.py:396\nmsgid \"Backlight (Seconds)\"\nmsgstr \"Taustavalo (sekuntia)\"\n\n#: lib/logitech_receiver/settings_templates.py:408\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"Vierityspyörän korkea resoluutio\"\n\n#: lib/logitech_receiver/settings_templates.py:412\n#: lib/logitech_receiver/settings_templates.py:441\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"Aseta sivuuttamaan, jos vieritys on epänormaalin nopeaa tai hidasta\"\n\n#: lib/logitech_receiver/settings_templates.py:419\n#: lib/logitech_receiver/settings_templates.py:450\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"Vierityspyörän uudelleenohjaus\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Aseta vierityspyörä lähettämään LOWRES_WHEEL HID++ -ilmoituksia (jotka \"\n\"laukaisevat Solaar-sääntöjä mutta muuten ohitetaan).\"\n\n#: lib/logitech_receiver/settings_templates.py:428\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"Vierityspyörän suunta\"\n\n#: lib/logitech_receiver/settings_templates.py:429\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"Käännä vierityspyörän pystysuuntainen vierityssuunta.\"\n\n#: lib/logitech_receiver/settings_templates.py:437\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"Vierityspyörän resoluutio\"\n\n#: lib/logitech_receiver/settings_templates.py:452\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar\"\n\" rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Aseta vierityspyörä lähettämään HIRES_WHEEL HID++ -ilmoituksia (jotka \"\n\"laukaisevat Solaar-sääntöjä mutta muuten ohitetaan).\"\n\n#: lib/logitech_receiver/settings_templates.py:461\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"Herkkyys (osoittimen nopeus)\"\n\n#: lib/logitech_receiver/settings_templates.py:462\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"Hiiren nopeuskerroin (256 on tavallinen kerroin).\"\n\n#: lib/logitech_receiver/settings_templates.py:472\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"Peukalopyörän uudelleenohjaus\"\n\n#: lib/logitech_receiver/settings_templates.py:474\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Aseta peukalopyörä lähettämään THUMB_WHEEL HID++ -ilmoituksia (jotka \"\n\"laukaisevat Solaar-sääntöjä mutta muuten ohitetaan).\"\n\n#: lib/logitech_receiver/settings_templates.py:483\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"Peukalopyörän suunta\"\n\n#: lib/logitech_receiver/settings_templates.py:484\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"Käännä peukalopyörän vierityssuunta.\"\n\n#: lib/logitech_receiver/settings_templates.py:504\nmsgid \"Onboard Profiles\"\nmsgstr \"Laitteen omat profiilit\"\n\n#: lib/logitech_receiver/settings_templates.py:505\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"\"\n\"Ota käyttöön laitteen oma profiili, joka hallitsee päivitysnopeutta, \"\n\"herkkyyttä ja painiketoimintoja\"\n\n#: lib/logitech_receiver/settings_templates.py:549\n#: lib/logitech_receiver/settings_templates.py:582\nmsgid \"Report Rate\"\nmsgstr \"Päivitysnopeus\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\nmsgid \"Frequency of device movement reports\"\nmsgstr \"Laitteen liikeraporttien taajuus\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1421\n#: lib/logitech_receiver/settings_templates.py:1452\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"\"\n\"Voi edellyttää, että Laitteen omat profiilit -asetus on pois käytöstä \"\n\"ollakseen voimassa.\"\n\n#: lib/logitech_receiver/settings_templates.py:612\nmsgid \"Divert crown events\"\nmsgstr \"Uudelleenohjaa kruunun tapahtumat\"\n\n#: lib/logitech_receiver/settings_templates.py:613\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Aseta kruunu lähettämään CROWN HID++ -ilmoituksia (jotka laukaisevat Solaar-\"\n\"sääntöjä mutta muuten ohitetaan).\"\n\n#: lib/logitech_receiver/settings_templates.py:621\nmsgid \"Crown smooth scroll\"\nmsgstr \"Kruunun sulava vieritys\"\n\n#: lib/logitech_receiver/settings_templates.py:622\nmsgid \"Set crown smooth scroll\"\nmsgstr \"Aseta kruunun sulava vieritys\"\n\n#: lib/logitech_receiver/settings_templates.py:630\nmsgid \"Divert G and M Keys\"\nmsgstr \"Uudelleenohjaa G- ja M-näppäimet\"\n\n#: lib/logitech_receiver/settings_templates.py:631\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Aseta G- ja M-näppäimet lähettämään HID++ -ilmoituksia (jotka laukaisevat \"\n\"Solaar-sääntöjä mutta muuten ohitetaan).\"\n\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"Vierityspyörän pykäläinen asetus\"\n\n#: lib/logitech_receiver/settings_templates.py:646\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"\"\n\"Vaihda hiiren pyörää nopeusohjatun pykäläisen ja aina vapaasti pyörivän \"\n\"välillä.\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Freespinning\"\nmsgstr \"Vapaasti pyörivä\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Ratcheted\"\nmsgstr \"Pykäläinen\"\n\n#: lib/logitech_receiver/settings_templates.py:655\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"Vierityspyörän pykäläisen asetuksen nopeus\"\n\n#: lib/logitech_receiver/settings_templates.py:657\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"Käytä hiiren pyörän nopeutta vaihtaaksesi pykäläisen ja vapaasti pyörivän välillä.\\n\"\n\"Hiiren pyörä on aina pykäläinen nopeudella 50.\"\n\n#: lib/logitech_receiver/settings_templates.py:707\nmsgid \"Scroll Wheel Ratchet Torque\"\nmsgstr \"Vierityspyörän pykälän vääntömomentti\"\n\n#: lib/logitech_receiver/settings_templates.py:708\nmsgid \"Change the torque needed to overcome the ratchet.\"\nmsgstr \"Muuta pykälän ylittämiseen tarvittavaa vääntömomenttia.\"\n\n#: lib/logitech_receiver/settings_templates.py:743\nmsgid \"Key/Button Actions\"\nmsgstr \"Näppäin-/painiketoiminnot\"\n\n#: lib/logitech_receiver/settings_templates.py:745\nmsgid \"Change the action for the key or button.\"\nmsgstr \"Muuta näppäimen tai painikkeen toimintoa.\"\n\n#: lib/logitech_receiver/settings_templates.py:747\nmsgid \"Overridden by diversion.\"\nmsgstr \"Uudelleenohjauksen ohittama.\"\n\n#: lib/logitech_receiver/settings_templates.py:749\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in\"\n\" an unusable system.\"\nmsgstr \"\"\n\"Tärkeiden toimintojen (kuten hiiren vasemman painikkeen) muuttaminen voi \"\n\"johtaa käyttökelvottomaan järjestelmään.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid \"Key/Button Diversion\"\nmsgstr \"Näppäimen/painikkeen uudelleenohjaus\"\n\n#: lib/logitech_receiver/settings_templates.py:925\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse\"\n\" Gestures or Sliding DPI\"\nmsgstr \"\"\n\"Aseta näppäin tai painike lähettämään HID++ -ilmoituksia (Uudelleenohjattu) \"\n\"tai aloita hiirieleet tai liukuva DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Diverted\"\nmsgstr \"Uudelleenohjattu\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\nmsgid \"Mouse Gestures\"\nmsgstr \"Hiirieleet\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Regular\"\nmsgstr \"Säännöllinen\"\n\n#: lib/logitech_receiver/settings_templates.py:928\nmsgid \"Sliding DPI\"\nmsgstr \"Liukuva DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"Herkkyys (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:1123\nmsgid \"Sensitivity Switching\"\nmsgstr \"Herkkyyden vaihtaminen\"\n\n#: lib/logitech_receiver/settings_templates.py:1125\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\"Vaihda nykyinen herkkyys ja muistettu herkkyys, kun näppäintä tai painiketta painetaan.\\n\"\n\"Jos muistettua herkkyyttä ei ole, muista vain nykyinen herkkyys\"\n\n#: lib/logitech_receiver/settings_templates.py:1129\nmsgid \"Off\"\nmsgstr \"Pois\"\n\n#: lib/logitech_receiver/settings_templates.py:1160\nmsgid \"Disable keys\"\nmsgstr \"Poista näppäimiä käytöstä\"\n\n#: lib/logitech_receiver/settings_templates.py:1161\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"Poista tiettyjä näppäimistön näppäimiä käytöstä.\"\n\n#: lib/logitech_receiver/settings_templates.py:1164\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"Poistaa %s-näppäimen käytöstä.\"\n\n#: lib/logitech_receiver/settings_templates.py:1177\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid \"Set OS\"\nmsgstr \"Aseta käyttöjärjestelmä\"\n\n#: lib/logitech_receiver/settings_templates.py:1178\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid \"Change keys to match OS.\"\nmsgstr \"Muuta näppäimet vastaamaan käyttöjärjestelmää.\"\n\n#: lib/logitech_receiver/settings_templates.py:1247\nmsgid \"Change Host\"\nmsgstr \"Vaihda isäntälaitetta\"\n\n#: lib/logitech_receiver/settings_templates.py:1248\nmsgid \"Switch connection to a different host\"\nmsgstr \"Vaihda yhteys toiseen isäntälaitteeseen\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Performs a left click.\"\nmsgstr \"Suorittaa vasemman napsautuksen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Single tap\"\nmsgstr \"Yksi napautus\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Performs a right click.\"\nmsgstr \"Suorittaa oikean napsautuksen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Single tap with two fingers\"\nmsgstr \"Yksi napautus kahdella sormella\"\n\n#: lib/logitech_receiver/settings_templates.py:1274\nmsgid \"Single tap with three fingers\"\nmsgstr \"Yksi napautus kolmella sormella\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Double tap\"\nmsgstr \"Kaksoisnapautus\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Performs a double click.\"\nmsgstr \"Suorittaa kaksoisnapsautuksen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid \"Double tap with two fingers\"\nmsgstr \"Kaksoisnapautus kahdella sormella\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Double tap with three fingers\"\nmsgstr \"Kaksoisnapautus kolmella sormella\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"Raahaa kohteita vetämällä sormea kaksoisnapautuksen jälkeen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Tap and drag\"\nmsgstr \"Napauta ja raahaa\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"Napauta ja raahaa kahdella sormella\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"Raahaa kohteita vetämällä sormia kaksoisnapautuksen jälkeen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"Napauta ja raahaa kolmella sormella\"\n\n#: lib/logitech_receiver/settings_templates.py:1291\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"Estä napautus- ja reunaeleet\"\n\n#: lib/logitech_receiver/settings_templates.py:1292\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"Poistaa napautus- ja reunaeleet käytöstä (vastaa Fn+Vasen napsautus).\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\nmsgid \"Scroll with one finger\"\nmsgstr \"Vieritä yhdellä sormella\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scrolls.\"\nmsgstr \"Vierittää.\"\n\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scroll with two fingers\"\nmsgstr \"Vieritä kahdella sormella\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"Vieritä vaakasuunnassa kahdella sormella\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scrolls horizontally.\"\nmsgstr \"Vierittää vaakasuunnassa.\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"Vieritä pystysuunnassa kahdella sormella\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scrolls vertically.\"\nmsgstr \"Vierittää pystysuunnassa.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"Kääntää vierityssuunnan.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Natural scrolling\"\nmsgstr \"Luonnollinen vieritys\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"Ottaa peukalopyörän käyttöön.\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Thumbwheel\"\nmsgstr \"Peukalopyörä\"\n\n#: lib/logitech_receiver/settings_templates.py:1311\n#: lib/logitech_receiver/settings_templates.py:1315\nmsgid \"Swipe from the top edge\"\nmsgstr \"Pyyhkäise yläreunasta\"\n\n#: lib/logitech_receiver/settings_templates.py:1312\nmsgid \"Swipe from the left edge\"\nmsgstr \"Pyyhkäise vasemmasta reunasta\"\n\n#: lib/logitech_receiver/settings_templates.py:1313\nmsgid \"Swipe from the right edge\"\nmsgstr \"Pyyhkäise oikeasta reunasta\"\n\n#: lib/logitech_receiver/settings_templates.py:1314\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"Pyyhkäise alareunasta\"\n\n#: lib/logitech_receiver/settings_templates.py:1316\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"Pyyhkäise kahdella sormella vasemmasta reunasta\"\n\n#: lib/logitech_receiver/settings_templates.py:1317\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"Pyyhkäise kahdella sormella oikeasta reunasta\"\n\n#: lib/logitech_receiver/settings_templates.py:1318\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"Pyyhkäise kahdella sormella alareunasta\"\n\n#: lib/logitech_receiver/settings_templates.py:1319\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"Pyyhkäise kahdella sormella yläreunasta\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"Nipistä loitontaaksesi; levitä lähentääksesi.\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\nmsgid \"Zoom with two fingers.\"\nmsgstr \"Zoomaa kahdella sormella.\"\n\n#: lib/logitech_receiver/settings_templates.py:1321\nmsgid \"Pinch to zoom out.\"\nmsgstr \"Nipistä loitontaaksesi.\"\n\n#: lib/logitech_receiver/settings_templates.py:1322\nmsgid \"Spread to zoom in.\"\nmsgstr \"Levitä lähentääksesi.\"\n\n#: lib/logitech_receiver/settings_templates.py:1323\nmsgid \"Zoom with three fingers.\"\nmsgstr \"Zoomaa kolmella sormella.\"\n\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Zoom with two fingers\"\nmsgstr \"Zoomaa kahdella sormella\"\n\n#: lib/logitech_receiver/settings_templates.py:1342\nmsgid \"Pixel zone\"\nmsgstr \"Pikselialue\"\n\n#: lib/logitech_receiver/settings_templates.py:1343\nmsgid \"Ratio zone\"\nmsgstr \"Suhdealue\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Scale factor\"\nmsgstr \"Skaalauskerroin\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Sets the cursor speed.\"\nmsgstr \"Asettaa osoittimen nopeuden.\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left\"\nmsgstr \"Vasen\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left-most coordinate.\"\nmsgstr \"Vasemmanpuoleisin koordinaatti.\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom\"\nmsgstr \"Alareuna\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom coordinate.\"\nmsgstr \"Alakoordinaatti.\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width\"\nmsgstr \"Leveys\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width.\"\nmsgstr \"Leveys.\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height\"\nmsgstr \"Korkeus\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height.\"\nmsgstr \"Korkeus.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Cursor speed.\"\nmsgstr \"Osoittimen nopeus.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Scale\"\nmsgstr \"Skaala\"\n\n#: lib/logitech_receiver/settings_templates.py:1358\nmsgid \"Gestures\"\nmsgstr \"Eleet\"\n\n#: lib/logitech_receiver/settings_templates.py:1359\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"Säädä hiiren/kosketuslevyn toimintaa.\"\n\n#: lib/logitech_receiver/settings_templates.py:1375\nmsgid \"Gestures Diversion\"\nmsgstr \"Eleiden uudelleenohjaus\"\n\n#: lib/logitech_receiver/settings_templates.py:1376\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"Uudelleenohjaa hiiren/kosketuslevyn eleet.\"\n\n#: lib/logitech_receiver/settings_templates.py:1392\nmsgid \"Gesture params\"\nmsgstr \"Eleiden parametrit\"\n\n#: lib/logitech_receiver/settings_templates.py:1393\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"Muuta hiiren/kosketuslevyn numeerisia parametreja.\"\n\n#: lib/logitech_receiver/settings_templates.py:1417\nmsgid \"M-Key LEDs\"\nmsgstr \"M-näppäinten LEDit\"\n\n#: lib/logitech_receiver/settings_templates.py:1419\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"Hallitse M-näppäinten LEDejä.\"\n\n#: lib/logitech_receiver/settings_templates.py:1423\n#: lib/logitech_receiver/settings_templates.py:1454\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"Saattaa edellyttää G-näppäinten uudelleenohjausta toimiakseen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1429\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"Sytyttää %s-näppäimen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1448\nmsgid \"MR-Key LED\"\nmsgstr \"MR-näppäimen LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1450\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"Hallitse MR-näppäimen LEDiä.\"\n\n#: lib/logitech_receiver/settings_templates.py:1471\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"Pysyvä näppäin-/painikemääritys\"\n\n#: lib/logitech_receiver/settings_templates.py:1473\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"Muuta näppäimen tai painikkeen määritystä pysyvästi.\"\n\n#: lib/logitech_receiver/settings_templates.py:1475\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"\"\n\"Tärkeiden näppäinten tai painikkeiden (kuten hiiren vasemman painikkeen) \"\n\"muuttaminen voi johtaa käyttökelvottomaan järjestelmään.\"\n\n#: lib/logitech_receiver/settings_templates.py:1532\nmsgid \"Sidetone\"\nmsgstr \"Sivuääni\"\n\n#: lib/logitech_receiver/settings_templates.py:1533\nmsgid \"Set sidetone level.\"\nmsgstr \"Aseta sivuäänen taso.\"\n\n#: lib/logitech_receiver/settings_templates.py:1542\nmsgid \"Equalizer\"\nmsgstr \"Taajuuskorjain\"\n\n#: lib/logitech_receiver/settings_templates.py:1543\nmsgid \"Set equalizer levels.\"\nmsgstr \"Aseta taajuuskorjaimen tasot.\"\n\n#: lib/logitech_receiver/settings_templates.py:1565\nmsgid \"Hz\"\nmsgstr \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1571\nmsgid \"Power Management\"\nmsgstr \"Virranhallinta\"\n\n#: lib/logitech_receiver/settings_templates.py:1572\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"Virrankatkaisu minuuteissa (0 = ei koskaan).\"\n\n#: lib/logitech_receiver/settings_templates.py:1584\nmsgid \"Brightness Control\"\nmsgstr \"Kirkkauden säätö\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\nmsgid \"Control overall brightness\"\nmsgstr \"Hallitse yleistä kirkkautta\"\n\n#: lib/logitech_receiver/settings_templates.py:1628\n#: lib/logitech_receiver/settings_templates.py:1681\nmsgid \"LED Control\"\nmsgstr \"LED-hallinta\"\n\n#: lib/logitech_receiver/settings_templates.py:1629\n#: lib/logitech_receiver/settings_templates.py:1682\nmsgid \"Switch control of LED zones between device and Solaar\"\nmsgstr \"Vaihda LED-alueiden hallintaa laitteen ja Solaarin välillä\"\n\n#: lib/logitech_receiver/settings_templates.py:1644\n#: lib/logitech_receiver/settings_templates.py:1692\nmsgid \"LED Zone Effects\"\nmsgstr \"LED-alueiden efektit\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr \"LED-hallinta on asetettava Solaariin ollakseen voimassa.\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"Set effect for LED Zone\"\nmsgstr \"Aseta efekti LED-alueelle\"\n\n#: lib/logitech_receiver/settings_templates.py:1647\nmsgid \"Color\"\nmsgstr \"Väri\"\n\n#: lib/logitech_receiver/settings_templates.py:1648\nmsgid \"Speed\"\nmsgstr \"Nopeus\"\n\n#: lib/logitech_receiver/settings_templates.py:1649\nmsgid \"Period\"\nmsgstr \"Jakso\"\n\n#: lib/logitech_receiver/settings_templates.py:1650\nmsgid \"Intensity\"\nmsgstr \"Voimakkuus\"\n\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid \"Ramp\"\nmsgstr \"Nousu\"\n\n#: lib/logitech_receiver/settings_templates.py:1666\nmsgid \"LEDs\"\nmsgstr \"LEDit\"\n\n#: lib/logitech_receiver/settings_templates.py:1703\nmsgid \"Per-key Lighting\"\nmsgstr \"Näppäinkohtainen valaistus\"\n\n#: lib/logitech_receiver/settings_templates.py:1704\nmsgid \"Control per-key lighting.\"\nmsgstr \"Hallitse näppäinkohtaista valaistusta.\"\n\n#: lib/logitech_receiver/settings_templates.py:1786\nmsgid \"Force Sensing Buttons\"\nmsgstr \"Voimaa tunnistavat painikkeet\"\n\n#: lib/logitech_receiver/settings_templates.py:1787\nmsgid \"Change the force required to activate button.\"\nmsgstr \"Muuta painikkeen aktivointiin tarvittavaa voimaa.\"\n\n#: lib/logitech_receiver/settings_templates.py:1804\nmsgid \"Force Sensing Button\"\nmsgstr \"Voimaa tunnistava painike\"\n\n#: lib/logitech_receiver/settings_templates.py:1814\nmsgid \"Haptic Feedback Level\"\nmsgstr \"Haptisen palautteen taso\"\n\n#: lib/logitech_receiver/settings_templates.py:1815\nmsgid \"Change power of haptic feedback.  (Zero to turn off.)\"\nmsgstr \"Muuta haptisen palautteen voimakkuutta.  (Nolla poistaa käytöstä.)\"\n\n#: lib/logitech_receiver/settings_templates.py:1857\nmsgid \"Play Haptic Waveform\"\nmsgstr \"Toista haptinen aaltomuoto\"\n\n#: lib/logitech_receiver/settings_templates.py:1858\nmsgid \"Tell device to play a haptic waveform.\"\nmsgstr \"Käske laitetta toistamaan haptinen aaltomuoto.\"\n\n#: lib/solaar/ui/__init__.py:120\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"\"\n\"Toinen Solaar-prosessi on jo käynnissä, joten sen ikkuna tuodaan näkyviin\"\n\n#: lib/solaar/ui/about/model.py:36\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"Hallitsee Logitech-vastaanottimia,\\n\"\n\"näppäimistöjä, hiiriä ja piirtopöytiä.\"\n\n#: lib/solaar/ui/about/model.py:64\nmsgid \"Additional Programming\"\nmsgstr \"Lisäohjelmointi\"\n\n#: lib/solaar/ui/about/model.py:65\nmsgid \"GUI design\"\nmsgstr \"Käyttöliittymäsuunnittelu\"\n\n#: lib/solaar/ui/about/model.py:67\nmsgid \"Testing\"\nmsgstr \"Testaus\"\n\n#: lib/solaar/ui/about/model.py:75\n#, fuzzy\nmsgid \"Logitech documentation\"\nmsgstr \"Logitechin dokumentointi\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92\n#: lib/solaar/ui/window.py:208\nmsgid \"Unpair\"\nmsgstr \"Poista paritus\"\n\n#: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141\nmsgid \"Cancel\"\nmsgstr \"Peruuta\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Permissions error\"\nmsgstr \"Virheelliset käyttöoikeudet\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"\"\n\"Löydettiin Logitech-vastaanotin tai -laite (%s), mutta siihen ei ollut \"\n\"avaamisoikeutta.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"\"\n\"Jos asensit Solaarin juuri, kokeile irrottaa vastaanotin tai laite ja \"\n\"yhdistää se sitten uudelleen.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Cannot connect to device error\"\nmsgstr \"Virhe yhdistettäessä laitteeseen\"\n\n#: lib/solaar/ui/common.py:51\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"Löydettiin Logitech-vastaanotin tai -laite polusta %s, mutta ilmeni virhe \"\n\"yhdistettäessä siihen.\"\n\n#: lib/solaar/ui/common.py:53\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"\"\n\"Kokeile laitteen irrottamista ja yhdistämistä uudelleen tai sen \"\n\"sammuttamista ja käynnistämistä uudelleen.\"\n\n#: lib/solaar/ui/common.py:56\nmsgid \"Unpairing failed\"\nmsgstr \"Parituksen poisto epäonnistui\"\n\n#: lib/solaar/ui/common.py:58\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"%{device}n parituksen poisto epäonnistui %{receiver}sta.\"\n\n#: lib/solaar/ui/common.py:63\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"Vastaanotin palautti virheen ilman lisätietoja.\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Complete - ENTER to change\"\nmsgstr \"Valmis - paina ENTER muuttaaksesi\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Incomplete\"\nmsgstr \"Keskeneräinen\"\n\n#: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d arvo\"\nmsgstr[1] \"%d arvoa\"\n\n#: lib/solaar/ui/config_panel.py:642\nmsgid \"Changes allowed\"\nmsgstr \"Muutokset sallittu\"\n\n#: lib/solaar/ui/config_panel.py:643\nmsgid \"No changes allowed\"\nmsgstr \"Ei muutoksia sallittu\"\n\n#: lib/solaar/ui/config_panel.py:644\nmsgid \"Ignore this setting\"\nmsgstr \"Ohita tämä asetus\"\n\n#: lib/solaar/ui/config_panel.py:690\nmsgid \"Working\"\nmsgstr \"Työskentelee\"\n\n#: lib/solaar/ui/config_panel.py:693\nmsgid \"Read/write operation failed.\"\nmsgstr \"Luku/kirjoitus operaatio epäonnistui.\"\n\n#: lib/solaar/ui/desktop_notifications.py:112\nmsgid \"unspecified reason\"\nmsgstr \"määrittämätön syy\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"Built-in rules\"\nmsgstr \"Sisäänrakennetut säännöt\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"User-defined rules\"\nmsgstr \"Käyttäjän määrittämät säännöt\"\n\n#: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126\nmsgid \"Rule\"\nmsgstr \"Sääntö\"\n\n#: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382\n#: lib/solaar/ui/diversion_rules.py:509\nmsgid \"Sub-rule\"\nmsgstr \"Alisääntö\"\n\n#: lib/solaar/ui/diversion_rules.py:108\nmsgid \"[empty]\"\nmsgstr \"[tyhjä]\"\n\n#: lib/solaar/ui/diversion_rules.py:132\nmsgid \"Make changes permanent?\"\nmsgstr \"Tehdäänkö muutoksista pysyviä?\"\n\n#: lib/solaar/ui/diversion_rules.py:137\nmsgid \"Yes\"\nmsgstr \"Kyllä\"\n\n#: lib/solaar/ui/diversion_rules.py:139\nmsgid \"No\"\nmsgstr \"Ei\"\n\n#: lib/solaar/ui/diversion_rules.py:144\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"Jos valitset Ei, muutokset menetetään, kun Solaar suljetaan.\"\n\n#: lib/solaar/ui/diversion_rules.py:273\nmsgid \"Paste here\"\nmsgstr \"Liitä tähän\"\n\n#: lib/solaar/ui/diversion_rules.py:275\nmsgid \"Paste above\"\nmsgstr \"Liitä yläpuolelle\"\n\n#: lib/solaar/ui/diversion_rules.py:277\nmsgid \"Paste below\"\nmsgstr \"Liitä alapuolelle\"\n\n#: lib/solaar/ui/diversion_rules.py:283\nmsgid \"Paste rule here\"\nmsgstr \"Liitä sääntö tähän\"\n\n#: lib/solaar/ui/diversion_rules.py:285\nmsgid \"Paste rule above\"\nmsgstr \"Liitä sääntö yläpuolelle\"\n\n#: lib/solaar/ui/diversion_rules.py:287\nmsgid \"Paste rule below\"\nmsgstr \"Liitä sääntö alapuolelle\"\n\n#: lib/solaar/ui/diversion_rules.py:291\nmsgid \"Paste rule\"\nmsgstr \"Liitä sääntö\"\n\n#: lib/solaar/ui/diversion_rules.py:306\nmsgid \"Insert here\"\nmsgstr \"Lisää tähän\"\n\n#: lib/solaar/ui/diversion_rules.py:308\nmsgid \"Insert above\"\nmsgstr \"Lisää yläpuolelle\"\n\n#: lib/solaar/ui/diversion_rules.py:310\nmsgid \"Insert below\"\nmsgstr \"Lisää alapuolelle\"\n\n#: lib/solaar/ui/diversion_rules.py:316\nmsgid \"Insert new rule here\"\nmsgstr \"Lisää uusi sääntö tähän\"\n\n#: lib/solaar/ui/diversion_rules.py:318\nmsgid \"Insert new rule above\"\nmsgstr \"Lisää uusi sääntö yläpuolelle\"\n\n#: lib/solaar/ui/diversion_rules.py:320\nmsgid \"Insert new rule below\"\nmsgstr \"Lisää uusi sääntö alapuolelle\"\n\n#: lib/solaar/ui/diversion_rules.py:347\nmsgid \"Flatten\"\nmsgstr \"Litistä\"\n\n#: lib/solaar/ui/diversion_rules.py:380\nmsgid \"Insert\"\nmsgstr \"Lisää\"\n\n#: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511\n#: lib/solaar/ui/diversion_rules.py:1158\nmsgid \"Or\"\nmsgstr \"Tai\"\n\n#: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510\n#: lib/solaar/ui/diversion_rules.py:1144\nmsgid \"And\"\nmsgstr \"Ja\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid \"Condition\"\nmsgstr \"Ehto\"\n\n#: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154\nmsgid \"Feature\"\nmsgstr \"Ominaisuus\"\n\n#: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188\nmsgid \"Report\"\nmsgstr \"Raportti\"\n\n#: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69\nmsgid \"Process\"\nmsgstr \"Prosessi\"\n\n#: lib/solaar/ui/diversion_rules.py:391\nmsgid \"Mouse process\"\nmsgstr \"Hiiriprosessi\"\n\n#: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225\nmsgid \"Modifiers\"\nmsgstr \"Muuntajat\"\n\n#: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277\nmsgid \"Key\"\nmsgstr \"Näppäin\"\n\n#: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318\nmsgid \"KeyIsDown\"\nmsgstr \"Näppäin on painettu\"\n\n#: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432\nmsgid \"Active\"\nmsgstr \"Aktiivinen\"\n\n#: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390\n#: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487\nmsgid \"Device\"\nmsgstr \"Laite\"\n\n#: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467\nmsgid \"Host\"\nmsgstr \"Isäntä\"\n\n#: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506\nmsgid \"Setting\"\nmsgstr \"Asetus\"\n\n#: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333\n#: lib/solaar/ui/rule_conditions.py:382\nmsgid \"Test\"\nmsgstr \"Testi\"\n\n#: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507\nmsgid \"Test bytes\"\nmsgstr \"Testaa tavut\"\n\n#: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608\nmsgid \"Mouse Gesture\"\nmsgstr \"Hiiriele\"\n\n#: lib/solaar/ui/diversion_rules.py:405\nmsgid \"Action\"\nmsgstr \"Toiminto\"\n\n#: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138\nmsgid \"Key press\"\nmsgstr \"Näppäimen painallus\"\n\n#: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191\nmsgid \"Mouse scroll\"\nmsgstr \"Hiiren vieritys\"\n\n#: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256\nmsgid \"Mouse click\"\nmsgstr \"Hiiren napsautus\"\n\n#: lib/solaar/ui/diversion_rules.py:410\nmsgid \"Set\"\nmsgstr \"Aseta\"\n\n#: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328\nmsgid \"Execute\"\nmsgstr \"Suorita\"\n\n#: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189\nmsgid \"Later\"\nmsgstr \"Myöhemmin\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid \"Insert new rule\"\nmsgstr \"Lisää uusi sääntö\"\n\n#: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82\n#: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556\nmsgid \"Delete\"\nmsgstr \"Poista\"\n\n#: lib/solaar/ui/diversion_rules.py:483\nmsgid \"Negate\"\nmsgstr \"Käännä\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid \"Wrap with\"\nmsgstr \"Kääri\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid \"Cut\"\nmsgstr \"Leikkaa\"\n\n#: lib/solaar/ui/diversion_rules.py:553\nmsgid \"Paste\"\nmsgstr \"Liitä\"\n\n#: lib/solaar/ui/diversion_rules.py:559\nmsgid \"Copy\"\nmsgstr \"Kopioi\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Solaarin sääntöeditori\"\n\n#: lib/solaar/ui/diversion_rules.py:668\nmsgid \"Save changes\"\nmsgstr \"Tallenna muutokset\"\n\n#: lib/solaar/ui/diversion_rules.py:673\nmsgid \"Discard changes\"\nmsgstr \"Hylkää muutokset\"\n\n#: lib/solaar/ui/diversion_rules.py:1104\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"Tämä editori ei vielä tue valittua sääntökomponenttia.\"\n\n#: lib/solaar/ui/diversion_rules.py:1169\nmsgid \"\"\n\"Number of seconds to delay.  Delay between 0 and 1 is done with higher \"\n\"precision.\"\nmsgstr \"\"\n\"Viive sekunteina.  Viive 0:n ja 1:n välillä tehdään suuremmalla \"\n\"tarkkuudella.\"\n\n#: lib/solaar/ui/diversion_rules.py:1207\nmsgid \"Not\"\nmsgstr \"Ei\"\n\n#: lib/solaar/ui/diversion_rules.py:1238\nmsgid \"Toggle\"\nmsgstr \"Vaihda\"\n\n#: lib/solaar/ui/diversion_rules.py:1239\nmsgid \"True\"\nmsgstr \"Tosi\"\n\n#: lib/solaar/ui/diversion_rules.py:1240\nmsgid \"False\"\nmsgstr \"Epätosi\"\n\n#: lib/solaar/ui/diversion_rules.py:1253\nmsgid \"Unsupported setting\"\nmsgstr \"Ei tuettu asetus\"\n\n#: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415\n#: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748\n#: lib/solaar/ui/diversion_rules.py:1766\nmsgid \"Originating device\"\nmsgstr \"Alkuperäinen laite\"\n\n#: lib/solaar/ui/diversion_rules.py:1428\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"Laite on aktiivinen ja sen asetuksia voidaan muuttaa.\"\n\n#: lib/solaar/ui/diversion_rules.py:1437\nmsgid \"Device that originated the current notification.\"\nmsgstr \"Laite, josta nykyinen ilmoitus on peräisin.\"\n\n#: lib/solaar/ui/diversion_rules.py:1450\nmsgid \"Name of host computer.\"\nmsgstr \"Isäntätietokoneen nimi.\"\n\n#: lib/solaar/ui/diversion_rules.py:1520\nmsgid \"Value\"\nmsgstr \"Arvo\"\n\n#: lib/solaar/ui/diversion_rules.py:1529\nmsgid \"Item\"\nmsgstr \"Kohde\"\n\n#: lib/solaar/ui/diversion_rules.py:1808\nmsgid \"Change setting on device\"\nmsgstr \"Muuta asetusta laitteessa\"\n\n#: lib/solaar/ui/diversion_rules.py:1824\nmsgid \"Setting on device\"\nmsgstr \"Asetus laitteessa\"\n\n#: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: parita uusi laite\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Bolt-vastaanottimet ovat yhteensopivia vain Bolt-laitteiden kanssa.\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"\"\n\"Paina parituspainiketta tai -näppäintä, kunnes paritusvalo vilkkuu nopeasti.\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"\"\n\"Unifying-vastaanottimet ovat yhteensopivia vain Unifying-laitteiden kanssa.\"\n\n#: lib/solaar/ui/pair_window.py:53\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"\"\n\"Muut vastaanottimet ovat yhteensopivia vain joidenkin laitteiden kanssa.\"\n\n#: lib/solaar/ui/pair_window.py:55\nmsgid \"For most devices, turn on the device you want to pair.\"\nmsgstr \"Useimmissa laitteissa kytke päälle laite, jonka haluat parittaa.\"\n\n#: lib/solaar/ui/pair_window.py:56\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"Jos laite on jo päällä, sammuta se ja käynnistä uudelleen.\"\n\n#: lib/solaar/ui/pair_window.py:58\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"\"\n\"Laitetta ei saa olla paritettu lähellä olevaan päällä olevaan \"\n\"vastaanottimeen.\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid \"\"\n\"For devices with multiple channels, press, hold, and release the button for the channel you wish to pair\\n\"\n\"or use the channel switch button to select a channel and then press, hold, and release the channel switch button.\"\nmsgstr \"\"\n\"Jos laitteessa on useita kanavia, paina, pidä painettuna ja vapauta sen kanavan painike, jonka haluat parittaa\\n\"\n\"tai käytä kanavanvaihtopainiketta valitaksesi kanavan ja paina, pidä painettuna ja vapauta sitten kanavanvaihtopainike.\"\n\n#: lib/solaar/ui/pair_window.py:68\nmsgid \"The channel indicator light should be blinking rapidly.\"\nmsgstr \"Kanavan merkkivalon pitäisi vilkkua nopeasti.\"\n\n#: lib/solaar/ui/pair_window.py:72\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"Tässä vastaanottimessa on %d paritus jäljellä.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"Tässä vastaanottimessa on %d paritusta jäljellä.\"\n\n#: lib/solaar/ui/pair_window.py:78\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"Peruuttaminen tässä vaiheessa ei kuluta paritusta.\"\n\n#: lib/solaar/ui/pair_window.py:168\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"Anna pääsykoodi laitteella %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:171\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"Kirjoita %(passcode)s ja paina sitten enter-näppäintä.\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"left\"\nmsgstr \"vasen\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"right\"\nmsgstr \"oikea\"\n\n#: lib/solaar/ui/pair_window.py:178\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"Paina %(code)s\\n\"\n\"ja paina sitten vasenta ja oikeaa painiketta samanaikaisesti.\"\n\n#: lib/solaar/ui/pair_window.py:221\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"Langaton yhteys ei ole salattu\"\n\n#: lib/solaar/ui/pair_window.py:226\nmsgid \"Found a new device:\"\nmsgstr \"Löytyi uusi laite:\"\n\n#: lib/solaar/ui/pair_window.py:247\nmsgid \"Pairing failed\"\nmsgstr \"Paritus epäonnistui.\"\n\n#: lib/solaar/ui/pair_window.py:249\nmsgid \"\"\n\"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"\"\n\"Varmista, että laitteesi on kantaman sisällä ja siinä on riittävä lataus.\"\n\n#: lib/solaar/ui/pair_window.py:251\nmsgid \"\"\n\"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"\"\n\"Uusi laite tunnistettiin, mutta se ei ole yhteensopiva käytetyn \"\n\"vastaanottimen kanssa.\"\n\n#: lib/solaar/ui/pair_window.py:253\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"Enemmän paritettuja laitteita kuin vastaanotin tukee.\"\n\n#: lib/solaar/ui/pair_window.py:255\nmsgid \"No further details are available about the error.\"\nmsgstr \"Virheestä ei ole saatavilla enempää tietoja.\"\n\n#: lib/solaar/ui/rule_actions.py:54\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simuloi sointunäppäimen napsautusta, painallusta tai vapautusta.\\n\"\n\"Waylandissa vaatii kirjoitusoikeuden laitteeseen /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:60\nmsgid \"Add key\"\nmsgstr \"Lisää näppäin\"\n\n#: lib/solaar/ui/rule_actions.py:63\nmsgid \"Click\"\nmsgstr \"Napsautus\"\n\n#: lib/solaar/ui/rule_actions.py:66\nmsgid \"Depress\"\nmsgstr \"Paina\"\n\n#: lib/solaar/ui/rule_actions.py:69\nmsgid \"Release\"\nmsgstr \"Vapauta\"\n\n#: lib/solaar/ui/rule_actions.py:153\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simuloi hiiren vieritystä.\\n\"\n\"Waylandissa vaatii kirjoitusoikeuden laitteeseen /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:211\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simuloi hiiren napsautusta.\\n\"\n\"Waylandissa vaatii kirjoitusoikeuden laitteeseen /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:216\nmsgid \"Button\"\nmsgstr \"Painike\"\n\n#: lib/solaar/ui/rule_actions.py:218\nmsgid \"Action (and Count, if click)\"\nmsgstr \"Toiminto (ja määrä, jos napsautus)\"\n\n#: lib/solaar/ui/rule_actions.py:269\nmsgid \"Execute a command with arguments.\"\nmsgstr \"Suorita komento argumenteilla.\"\n\n#: lib/solaar/ui/rule_actions.py:273\nmsgid \"Add argument\"\nmsgstr \"Lisää argumentti\"\n\n#: lib/solaar/ui/rule_conditions.py:52\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"X11 aktiivinen prosessi. Vain X11-käyttöön.\"\n\n#: lib/solaar/ui/rule_conditions.py:82\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"X11 hiiriprosessi. Vain X11-käyttöön.\"\n\n#: lib/solaar/ui/rule_conditions.py:99\nmsgid \"MouseProcess\"\nmsgstr \"Hiiriprosessi\"\n\n#: lib/solaar/ui/rule_conditions.py:123\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"Säännönkäsittelyn laukaisevan ilmoituksen ominaisuuden nimi.\"\n\n#: lib/solaar/ui/rule_conditions.py:169\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"Säännönkäsittelyn laukaisevan ilmoituksen raporttinumero.\"\n\n#: lib/solaar/ui/rule_conditions.py:201\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"\"\n\"Aktiiviset näppäimistön muuntajat. Eivät ole aina saatavilla Waylandissa.\"\n\n#: lib/solaar/ui/rule_conditions.py:241\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and buttons.\"\nmsgstr \"\"\n\"Uudelleenohjattu näppäin tai painike painettu tai vapautettu.\\n\"\n\"Käytä näppäimen/painikkeen uudelleenohjaus- ja uudelleenohjaa G-näppäimet -asetuksia ohjataksesi näppäimiä ja painikkeita.\"\n\n#: lib/solaar/ui/rule_conditions.py:250\nmsgid \"Key down\"\nmsgstr \"Näppäin painettuna\"\n\n#: lib/solaar/ui/rule_conditions.py:253\nmsgid \"Key up\"\nmsgstr \"Näppäin vapautettuna\"\n\n#: lib/solaar/ui/rule_conditions.py:293\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and buttons.\"\nmsgstr \"\"\n\"Uudelleenohjattu näppäin tai painike on parhaillaan painettuna.\\n\"\n\"Käytä näppäimen/painikkeen uudelleenohjaus- ja uudelleenohjaa G-näppäimet -asetuksia ohjataksesi näppäimiä ja painikkeita.\"\n\n#: lib/solaar/ui/rule_conditions.py:331\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"Testaa ehto säännönkäsittelyn laukaisevassa ilmoituksessa.\"\n\n#: lib/solaar/ui/rule_conditions.py:335\nmsgid \"Parameter\"\nmsgstr \"Parametri\"\n\n#: lib/solaar/ui/rule_conditions.py:408\nmsgid \"begin (inclusive)\"\nmsgstr \"alku (sisältyy)\"\n\n#: lib/solaar/ui/rule_conditions.py:409\nmsgid \"end (exclusive)\"\nmsgstr \"loppu (ei sisälly)\"\n\n#: lib/solaar/ui/rule_conditions.py:417\nmsgid \"range\"\nmsgstr \"alue\"\n\n#: lib/solaar/ui/rule_conditions.py:420\nmsgid \"minimum\"\nmsgstr \"minimi\"\n\n#: lib/solaar/ui/rule_conditions.py:421\nmsgid \"maximum\"\nmsgstr \"maksimi\"\n\n#: lib/solaar/ui/rule_conditions.py:423\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"tavut %(0)d - %(1)d, väliltä %(2)d - %(3)d\"\n\n#: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427\nmsgid \"mask\"\nmsgstr \"maski\"\n\n#: lib/solaar/ui/rule_conditions.py:428\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"tavut %(0)d - %(1)d, maski %(2)d\"\n\n#: lib/solaar/ui/rule_conditions.py:437\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\"Bitti- tai aluetesti tavuille säännönkäsittelyn laukaisevassa \"\n\"ilmoitusviestissä.\"\n\n#: lib/solaar/ui/rule_conditions.py:447\nmsgid \"type\"\nmsgstr \"tyyppi\"\n\n#: lib/solaar/ui/rule_conditions.py:535\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse\"\n\" movements.\"\nmsgstr \"\"\n\"Hiiriele valinnaisella aloituspainikkeella, jota seuraa nolla tai useampi \"\n\"hiiriliike.\"\n\n#: lib/solaar/ui/rule_conditions.py:541\nmsgid \"Add movement\"\nmsgstr \"Lisää liike\"\n\n#: lib/solaar/ui/tray.py:55\nmsgid \"No supported device found\"\nmsgstr \"Ei löydetty tuettua laitetta\"\n\n#: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328\n#, python-format\nmsgid \"About %s\"\nmsgstr \"Tietoja %s\"\n\n#: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"Lopeta %s\"\n\n#: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281\nmsgid \"no receiver\"\nmsgstr \"ei vastaanotinta\"\n\n#: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299\n#: lib/solaar/ui/window.py:728\nmsgid \"offline\"\nmsgstr \"ei yhdistetty\"\n\n#: lib/solaar/ui/tray.py:297\nmsgid \"no status\"\nmsgstr \"ei tietoja\"\n\n#: lib/solaar/ui/window.py:110\nmsgid \"Scanning\"\nmsgstr \"Skannataan\"\n\n#: lib/solaar/ui/window.py:141\nmsgid \"Battery\"\nmsgstr \"Akku\"\n\n#: lib/solaar/ui/window.py:144\nmsgid \"Wireless Link\"\nmsgstr \"Langaton yhteys\"\n\n#: lib/solaar/ui/window.py:148\nmsgid \"Lighting\"\nmsgstr \"Valaistus\"\n\n#: lib/solaar/ui/window.py:182\nmsgid \"Show Technical Details\"\nmsgstr \"Näytä tekniset tiedot\"\n\n#: lib/solaar/ui/window.py:198\nmsgid \"Pair new device\"\nmsgstr \"Parita uusi laite\"\n\n#: lib/solaar/ui/window.py:216\nmsgid \"Select a device\"\nmsgstr \"Valitse laite\"\n\n#: lib/solaar/ui/window.py:331\nmsgid \"Rule Editor\"\nmsgstr \"Sääntöeditori\"\n\n#: lib/solaar/ui/window.py:522\nmsgid \"Path\"\nmsgstr \"Polku\"\n\n#: lib/solaar/ui/window.py:524\nmsgid \"USB ID\"\nmsgstr \"USB-tunnus\"\n\n#: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529\n#: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546\nmsgid \"Serial\"\nmsgstr \"Sarjanumero\"\n\n#: lib/solaar/ui/window.py:533\nmsgid \"Index\"\nmsgstr \"Järjestysnumero\"\n\n#: lib/solaar/ui/window.py:535\nmsgid \"Wireless PID\"\nmsgstr \"Langaton PID\"\n\n#: lib/solaar/ui/window.py:537\nmsgid \"Product ID\"\nmsgstr \"Tuotteen tunnistekoodi\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Protocol\"\nmsgstr \"Yhteyskäytäntö\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Unknown\"\nmsgstr \"Tuntematon\"\n\n#: lib/solaar/ui/window.py:541\nmsgid \"Polling rate\"\nmsgstr \"Päivitysnopeus\"\n\n#: lib/solaar/ui/window.py:548\nmsgid \"Unit ID\"\nmsgstr \"Yksikön tunnus\"\n\n#: lib/solaar/ui/window.py:559\nmsgid \"none\"\nmsgstr \"ei mitään\"\n\n#: lib/solaar/ui/window.py:560\nmsgid \"Notifications\"\nmsgstr \"Ilmoitukset\"\n\n#: lib/solaar/ui/window.py:604\nmsgid \"No device paired.\"\nmsgstr \"Ei paritettua laitetta.\"\n\n#: lib/solaar/ui/window.py:613\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"\"\n\"Enintään %(max_count)s laite voidaan parittaa tähän vastaanottimeen.\"\nmsgstr[1] \"\"\n\"Enintään %(max_count)s laitetta voidaan parittaa tähän vastaanottimeen.\"\n\n#: lib/solaar/ui/window.py:620\nmsgid \"Only one device can be paired to this receiver.\"\nmsgstr \"Vain yksi laite voidaan parittaa tähän vastaanottimeen.\"\n\n#: lib/solaar/ui/window.py:624\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"Tässä vastaanottimessa on %d paritus jäljellä.\"\nmsgstr[1] \"Tässä vastaanottimessa on %d paritusta jäljellä.\"\n\n#: lib/solaar/ui/window.py:681\nmsgid \"Battery Voltage\"\nmsgstr \"Akun jännite\"\n\n#: lib/solaar/ui/window.py:683\nmsgid \"Voltage reported by battery\"\nmsgstr \"Akun ilmoittama jännite\"\n\n#: lib/solaar/ui/window.py:685\nmsgid \"Battery Level\"\nmsgstr \"Akun taso\"\n\n#: lib/solaar/ui/window.py:687\nmsgid \"Approximate level reported by battery\"\nmsgstr \"Akun ilmoittama arvioitu taso\"\n\n#: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696\nmsgid \"next reported \"\nmsgstr \"seuraavaksi ilmoitettu \"\n\n#: lib/solaar/ui/window.py:697\nmsgid \" and next level to be reported.\"\nmsgstr \" ja seuraava ilmoitettava taso.\"\n\n#: lib/solaar/ui/window.py:702\nmsgid \"last known\"\nmsgstr \"viimeisin tunnettu\"\n\n#: lib/solaar/ui/window.py:713\nmsgid \"encrypted\"\nmsgstr \"salattu\"\n\n#: lib/solaar/ui/window.py:715\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"Langaton yhteys laitteen ja vastaanottimen välillä on salattu.\"\n\n#: lib/solaar/ui/window.py:717\nmsgid \"not encrypted\"\nmsgstr \"salaamaton\"\n\n#: lib/solaar/ui/window.py:721\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue for text-input devices.\"\nmsgstr \"\"\n\"Langaton yhteys tämän laitteen ja sen vastaanottimen välillä ei ole salattu.\\n\"\n\"Tämä on tietoturvaongelma osoitinlaitteille ja suuri tietoturvariski tekstinsyöttölaitteille.\"\n\n#: lib/solaar/ui/window.py:737\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d luksia\"\n\n#~ msgid \" paired devices.\"\n#~ msgstr \" paritettua laitetta\"\n\n#~ msgid \"1 paired device.\"\n#~ msgstr \"Yksi paritettu laite.\"\n\n#, python-format\n#~ msgid \"\"\n#~ \"Found a Logitech Receiver (%s), but did not have permission to open it.\"\n#~ msgstr \"\"\n#~ \"Logitechin vastaanotin (%s) löydettiin, mutta sitä ei ollut oikeutta avata.\"\n\n#~ msgid \"Found a new device\"\n#~ msgstr \"Löydetty uusi laite.\"\n\n#~ msgid \"\"\n#~ \"If the device is already turned on,\\n\"\n#~ \"turn if off and on again.\"\n#~ msgstr \"\"\n#~ \"Jos laite on jo päällä, sammuta se\\n\"\n#~ \"ja kytke virta uudelleen päälle.\"\n\n#~ msgid \"\"\n#~ \"If you've just installed Solaar, try removing the receiver and plugging it \"\n#~ \"back in.\"\n#~ msgstr \"\"\n#~ \"Jos olet juuri asentanut Solaarin, yritä vastaanottimen irroittamista ja \"\n#~ \"liittämistä uudelleen.\"\n\n#~ msgid \"No Logitech receiver found\"\n#~ msgstr \"Ei löydetty Logitechin vastaanottimia.\"\n\n#~ msgid \"No device paired\"\n#~ msgstr \"Ei paritettuja laitteita\"\n\n#~ msgid \"Only one device can be paired to this receiver\"\n#~ msgstr \"Vain yksi laite voidaan parittaa tähän vastaanottimeen\"\n\n#~ msgid \"\"\n#~ \"Shows status of devices connected\\n\"\n#~ \"through wireless Logitech receivers.\"\n#~ msgstr \"\"\n#~ \"Näyttää Logitechin langattoman \\n\"\n#~ \"vastaanottimen kautta liitettyjen\\n\"\n#~ \"laitteiden tilan.\"\n\n#~ msgid \"Smooth Scrolling\"\n#~ msgstr \"Sulava vieritys\"\n\n#, python-format\n#~ msgid \"The receiver only supports %d paired device(s).\"\n#~ msgstr \"Vastaanotin tukee vain %d liitettyä laitetta.\"\n\n#~ msgid \"The receiver was unplugged.\"\n#~ msgstr \"Vastaanotin irroitettiin.\"\n\n#~ msgid \"\"\n#~ \"The wireless link between this device and its receiver is not encrypted.\\n\"\n#~ \"\\n\"\n#~ \"For pointing devices (mice, trackballs, trackpads), this is a minor security issue.\\n\"\n#~ \"\\n\"\n#~ \"It is, however, a major security issue for text-input devices (keyboards, numpads),\\n\"\n#~ \"because typed text can be sniffed inconspicuously by 3rd parties within range.\"\n#~ msgstr \"\"\n#~ \"Langaton yhteys laitteen ja vastaanottimen välillä ei ole salattu.\\n\"\n#~ \"\\n\"\n#~ \"Osoitinlaitteita (hiiret, ohjainpallot, tasohiiret) käytettäessä se on pieni tietoturvallisuusriski.\\n\"\n#~ \"\\n\"\n#~ \"Kuitenkin, näppäimistöjen kanssa se on suuri tietoturvallisuusriski sillä kolmannet osapuolet\\n\"\n#~ \"voivat lukea huomaamattomasti kirjoitetun tekstin yhteyden kantaman sisällä.\"\n\n#~ msgid \"Turn on the device you want to pair.\"\n#~ msgstr \"Käynnistä laite, jonka haluat parittaa.\"\n\n#~ msgid \"USB id\"\n#~ msgstr \"USB-tunnus\"\n\n#~ msgid \"Up to %d devices can be paired to this receiver\"\n#~ msgstr \"Korkeintaan %d laitetta voidaan parittaa tähän vastaanottimeen\"\n\n#~ msgid \"closed\"\n#~ msgstr \"suljettu\"\n\n#~ msgid \"height\"\n#~ msgstr \"korkeus\"\n\n#~ msgid \"lux\"\n#~ msgstr \"luksia\"\n\n#~ msgid \"open\"\n#~ msgstr \"avoin\"\n\n#~ msgid \"pair new device\"\n#~ msgstr \"liitä uusi laite\"\n\n#~ msgid \"paired devices\"\n#~ msgstr \"paritettua laitetta\"\n\n#~ msgid \"pairing lock is \"\n#~ msgstr \"parituslukko on \"\n\n#~ msgid \"unknown\"\n#~ msgstr \"tuntematon\"\n\n#~ msgid \"width\"\n#~ msgstr \"leveys\"\n"
  },
  {
    "path": "po/fr.po",
    "content": "# French translations for solaar package.\n# Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2013.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 1.1.19\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-01-08 19:21+0100\\n\"\n\"PO-Revision-Date: 2026-01-08 19:38+0100\\n\"\n\"Last-Translator: David Geiger <david.david@mageialinux-online.org>\\n\"\n\"Language-Team: Language: fr\\n\"\n\"Language: fr\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1);\\n\"\n\"X-Generator: Poedit 3.8\\n\"\n\n#: lib/logitech_receiver/base_usb.py:52\nmsgid \"Bolt Receiver\"\nmsgstr \"Récepteur Bolt\"\n\n#: lib/logitech_receiver/base_usb.py:64\nmsgid \"Unifying Receiver\"\nmsgstr \"Récepteur Unifying\"\n\n#: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87\n#: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113\nmsgid \"Nano Receiver\"\nmsgstr \"Récepteur Nano\"\n\n#: lib/logitech_receiver/base_usb.py:125\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Récepteur Lightspeed\"\n\n#: lib/logitech_receiver/base_usb.py:136\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"Récepteur EX100 27 Mhz\"\n\n#: lib/logitech_receiver/common.py:649\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"Batterie : %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:652\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"Batterie : %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:1048\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid \"Disabled\"\nmsgstr \"Désactivé\"\n\n#: lib/logitech_receiver/hidpp20.py:1049\nmsgid \"Static\"\nmsgstr \"Statique\"\n\n#: lib/logitech_receiver/hidpp20.py:1050\nmsgid \"Pulse\"\nmsgstr \"Pulsation\"\n\n#: lib/logitech_receiver/hidpp20.py:1051\nmsgid \"Cycle\"\nmsgstr \"Cycle\"\n\n#: lib/logitech_receiver/hidpp20.py:1052\nmsgid \"Boot\"\nmsgstr \"Boot\"\n\n#: lib/logitech_receiver/hidpp20.py:1053\nmsgid \"Demo\"\nmsgstr \"Démo\"\n\n#: lib/logitech_receiver/hidpp20.py:1055\nmsgid \"Breathe\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1058\nmsgid \"Ripple\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1059\nmsgid \"Decomposition\"\nmsgstr \"Décomposition\"\n\n#: lib/logitech_receiver/hidpp20.py:1060\nmsgid \"Signature1\"\nmsgstr \"Signature 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1061\nmsgid \"Signature2\"\nmsgstr \"Signature 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1062\nmsgid \"CycleS\"\nmsgstr \"Cycle S\"\n\n#: lib/logitech_receiver/hidpp20.py:1126\nmsgid \"Unknown Location\"\nmsgstr \"Emplacement inconnu\"\n\n#: lib/logitech_receiver/hidpp20.py:1127\nmsgid \"Primary\"\nmsgstr \"Primaire\"\n\n#: lib/logitech_receiver/hidpp20.py:1128\nmsgid \"Logo\"\nmsgstr \"Logo\"\n\n#: lib/logitech_receiver/hidpp20.py:1129\nmsgid \"Left Side\"\nmsgstr \"Côté gauche\"\n\n#: lib/logitech_receiver/hidpp20.py:1130\nmsgid \"Right Side\"\nmsgstr \"Côté droit\"\n\n#: lib/logitech_receiver/hidpp20.py:1131\nmsgid \"Combined\"\nmsgstr \"Combiné\"\n\n#: lib/logitech_receiver/hidpp20.py:1132\nmsgid \"Primary 1\"\nmsgstr \"Primaire 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1133\nmsgid \"Primary 2\"\nmsgstr \"Primaire 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1134\nmsgid \"Primary 3\"\nmsgstr \"Primaire 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1135\nmsgid \"Primary 4\"\nmsgstr \"Primaire 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1136\nmsgid \"Primary 5\"\nmsgstr \"Primaire 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1137\nmsgid \"Primary 6\"\nmsgstr \"Primaire 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"vide\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"critique\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"faible\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"moyenne\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"bonne\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"pleine\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"En décharge\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"En charge\"\n\n#: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700\nmsgid \"charging\"\nmsgstr \"en charge\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"pas en charge\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"presque pleine\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"chargée\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"recharge lente\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"invalid battery\"\nmsgstr \"batterie invalide\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"erreur thermique\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"erreur\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"standard\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"rapide\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"lente\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"le périphérique ne répond pas\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"périphérique non pris en charge\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"trop de périphériques\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"délai dépassé\"\n\n#: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555\nmsgid \"Firmware\"\nmsgstr \"Micrologiciel\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"Chargeur d'amorçage\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"Matériel\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"Autre\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"Bouton gauche\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"Bouton droit\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"Bouton central\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"Bouton retour\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"Bouton avant\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"Bouton gestuel de la souris\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"Changement intelligent\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"Commutateur DPI\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"Inclinaison à gauche\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"Inclinaison à droite\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"Clic gauche\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"Clic droit\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"Bouton central de la souris\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"Bouton de retour de la souris\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"Bouton avant de la souris\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"Navigation par bouton de gestuelle\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"Bouton de défilement vers la gauche de la souris\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"Bouton de défilement vers la droite de la souris\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"pressé\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"relâché\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"connected\"\nmsgstr \"connecté\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"disconnected\"\nmsgstr \"déconnecté\"\n\n#: lib/logitech_receiver/notifications.py:182\nmsgid \"unpaired\"\nmsgstr \"non jumelé\"\n\n#: lib/logitech_receiver/notifications.py:231\nmsgid \"powered on\"\nmsgstr \"sous tension\"\n\n#: lib/logitech_receiver/notifications.py:283\nmsgid \"ADC measurement notification\"\nmsgstr \"Notification de mesure ADC\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:484\nmsgid \"pairing lock is closed\"\nmsgstr \"le verrou de jumelage est fermé\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:484\nmsgid \"pairing lock is open\"\nmsgstr \"le verrou de jumelage est ouvert\"\n\n#: lib/logitech_receiver/notifications.py:447\nmsgid \"discovery lock is closed\"\nmsgstr \"le verrou de détection est fermé\"\n\n#: lib/logitech_receiver/notifications.py:447\nmsgid \"discovery lock is open\"\nmsgstr \"le verrou de détection est ouvert\"\n\n#: lib/logitech_receiver/receiver.py:437\nmsgid \"No paired devices.\"\nmsgstr \"Aucun périphérique jumelé.\"\n\n#: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s périphérique jumelé.\"\nmsgstr[1] \"%(count)s périphériques jumelés.\"\n\n#: lib/logitech_receiver/settings.py:602\nmsgid \"register\"\nmsgstr \"registre\"\n\n#: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654\nmsgid \"feature\"\nmsgstr \"fonctionnalité\"\n\n#: lib/logitech_receiver/settings_templates.py:138\nmsgid \"Swap Fx function\"\nmsgstr \"Fonction Swap Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:141\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"Lorsque défini, les touches F1..F12 activeront leurs fonctions spéciales,\\n\"\n\"et vous devez maintenir la touche FN pour activer leurs fonctions standards.\"\n\n#: lib/logitech_receiver/settings_templates.py:146\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"Lorsque non défini, les touches F1..F12 activeront leurs fonctions \"\n\"standards,\\n\"\n\"et vous devez maintenir la touche FN pour activer leurs fonctions spéciales.\"\n\n#: lib/logitech_receiver/settings_templates.py:154\nmsgid \"Hand Detection\"\nmsgstr \"Détection manuelle\"\n\n#: lib/logitech_receiver/settings_templates.py:155\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"Allume l'éclairage lorsque les mains passent au-dessus du clavier.\"\n\n#: lib/logitech_receiver/settings_templates.py:162\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"Défilement fluide à la molette\"\n\n#: lib/logitech_receiver/settings_templates.py:163\n#: lib/logitech_receiver/settings_templates.py:410\n#: lib/logitech_receiver/settings_templates.py:439\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"Mode haute sensibilité pour défilement vertical avec la roulette.\"\n\n#: lib/logitech_receiver/settings_templates.py:170\nmsgid \"Side Scrolling\"\nmsgstr \"Défilement latéral\"\n\n#: lib/logitech_receiver/settings_templates.py:172\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"Lorsque désactivé, l'appui sur les côtés de la roulette envoie des \"\n\"évènements\\n\"\n\" de bouton personnalisés à la place des évènements standards de défilement \"\n\"latéral.\"\n\n#: lib/logitech_receiver/settings_templates.py:182\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"Sensibilité (DPI - souris plus anciennne)\"\n\n#: lib/logitech_receiver/settings_templates.py:183\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"Sensibilité du mouvement de la souris\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid \"Backlight Timed\"\nmsgstr \"Rétroéclairage chronométré\"\n\n#: lib/logitech_receiver/settings_templates.py:257\n#: lib/logitech_receiver/settings_templates.py:397\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"Définir le temps d'éclairage du clavier.\"\n\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid \"Backlight\"\nmsgstr \"Rétroéclairage\"\n\n#: lib/logitech_receiver/settings_templates.py:269\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"\"\n\"Niveau d'éclairage du clavier. Les modifications apportées ne sont \"\n\"appliquées qu'en mode manuel.\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid \"Automatic\"\nmsgstr \"Automatique\"\n\n#: lib/logitech_receiver/settings_templates.py:303\nmsgid \"Manual\"\nmsgstr \"Manuel\"\n\n#: lib/logitech_receiver/settings_templates.py:305\nmsgid \"Enabled\"\nmsgstr \"Activé\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid \"Backlight Level\"\nmsgstr \"Niveau de rétroéclairage\"\n\n#: lib/logitech_receiver/settings_templates.py:312\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"Niveau d'éclairage du clavier en mode manuel.\"\n\n#: lib/logitech_receiver/settings_templates.py:369\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"Délai de rétroéclairage sans les mains\"\n\n#: lib/logitech_receiver/settings_templates.py:370\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"\"\n\"Délai jusqu'à ce que le rétroéclairage s'éteigne avec les mains éloignées du \"\n\"clavier.\"\n\n#: lib/logitech_receiver/settings_templates.py:378\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"Délai de rétroéclairage avec les mains\"\n\n#: lib/logitech_receiver/settings_templates.py:379\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"\"\n\"Délai jusqu'à ce que le rétroéclairage s'éteigne avec les mains près du \"\n\"clavier.\"\n\n#: lib/logitech_receiver/settings_templates.py:387\nmsgid \"Backlight Delay Powered\"\nmsgstr \"Délai de rétroéclairage alimenté\"\n\n#: lib/logitech_receiver/settings_templates.py:388\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"\"\n\"Délai jusqu'à ce que le rétroéclairage s'éteigne avec une alimentation \"\n\"externe.\"\n\n#: lib/logitech_receiver/settings_templates.py:396\nmsgid \"Backlight (Seconds)\"\nmsgstr \"Rétroéclairage (Secondes)\"\n\n#: lib/logitech_receiver/settings_templates.py:408\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"Molette haute résolution\"\n\n#: lib/logitech_receiver/settings_templates.py:412\n#: lib/logitech_receiver/settings_templates.py:441\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"Définir pour ignorer si le défilement est anormalement rapide ou lent\"\n\n#: lib/logitech_receiver/settings_templates.py:419\n#: lib/logitech_receiver/settings_templates.py:450\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"Interception de la molette\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Active l'envoi par la molette de notifications LOWRES_WHEEL HID++ (ce qui \"\n\"déclenche les règles Solaar qui sont ignorées sinon).\"\n\n#: lib/logitech_receiver/settings_templates.py:428\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"Direction de la molette\"\n\n#: lib/logitech_receiver/settings_templates.py:429\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"Direction inversée pour le défilement vertical avec la molette.\"\n\n#: lib/logitech_receiver/settings_templates.py:437\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"Résolution de la molette\"\n\n#: lib/logitech_receiver/settings_templates.py:452\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Active l'envoi par la molette de notifications HIRES_WHEEL HID++ (ce qui \"\n\"déclenche les règles Solaar qui sont ignorées sinon).\"\n\n#: lib/logitech_receiver/settings_templates.py:461\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"Sensibilité (vitesse du pointeur)\"\n\n#: lib/logitech_receiver/settings_templates.py:462\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"\"\n\"Multiplicateur de vitesse pour la souris (256 est le multiplicateur normal).\"\n\n#: lib/logitech_receiver/settings_templates.py:472\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"Interception de la molette de pouce\"\n\n#: lib/logitech_receiver/settings_templates.py:474\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Active l'envoi par la molette de pouce de notifications THUMB_WHEEL HID++ \"\n\"(ce qui déclenche les règles Solaar qui sont ignorées sinon).\"\n\n#: lib/logitech_receiver/settings_templates.py:483\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"Direction de la molette de pouce\"\n\n#: lib/logitech_receiver/settings_templates.py:484\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"Inverser la direction du défilement de la molette de pouce.\"\n\n#: lib/logitech_receiver/settings_templates.py:504\nmsgid \"Onboard Profiles\"\nmsgstr \"Profils embarqués\"\n\n#: lib/logitech_receiver/settings_templates.py:505\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"\"\n\"Activer un profil intégré, qui contrôle le taux de rapport, la sensibilité \"\n\"et les actions des boutons\"\n\n#: lib/logitech_receiver/settings_templates.py:549\n#: lib/logitech_receiver/settings_templates.py:582\nmsgid \"Report Rate\"\nmsgstr \"Taux de rapport\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\nmsgid \"Frequency of device movement reports\"\nmsgstr \"Fréquence des rapports de mouvement des périphériques\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1421\n#: lib/logitech_receiver/settings_templates.py:1452\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"\"\n\"Peut nécessiter de désactiver les profils embarqués pour être effectif.\"\n\n#: lib/logitech_receiver/settings_templates.py:612\nmsgid \"Divert crown events\"\nmsgstr \"Définir les évènements de la couronne\"\n\n#: lib/logitech_receiver/settings_templates.py:613\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Active l'envoi par la couronne de notifications CROWN HID++ (ce qui \"\n\"déclenche les règles Solaar qui sont ignorées sinon).\"\n\n#: lib/logitech_receiver/settings_templates.py:621\nmsgid \"Crown smooth scroll\"\nmsgstr \"Défilement fluide de la couronne\"\n\n#: lib/logitech_receiver/settings_templates.py:622\nmsgid \"Set crown smooth scroll\"\nmsgstr \"Définir le défilement fluide de la couronne\"\n\n#: lib/logitech_receiver/settings_templates.py:630\nmsgid \"Divert G and M Keys\"\nmsgstr \"Interception des touches G et M\"\n\n#: lib/logitech_receiver/settings_templates.py:631\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Active l'envoi par les touches G et M de notifications HID++ (ce qui \"\n\"déclenche les règles Solaar qui sont ignorées sinon).\"\n\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"Molette mode cliquet\"\n\n#: lib/logitech_receiver/settings_templates.py:646\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"\"\n\"Basculez la molette de la souris entre le mode cliquet à vitesse contrôlée \"\n\"et toujours en roue libre.\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Freespinning\"\nmsgstr \"Roue libre\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Ratcheted\"\nmsgstr \"Cliquet\"\n\n#: lib/logitech_receiver/settings_templates.py:655\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"Vitesse de la molette mode cliquet\"\n\n#: lib/logitech_receiver/settings_templates.py:657\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"Utilisez la vitesse de la molette de la souris pour basculer entre le mode \"\n\"cliquet et le mode roue libre.\\n\"\n\"La molette est toujours en mode cliquet à 50.\"\n\n#: lib/logitech_receiver/settings_templates.py:707\nmsgid \"Scroll Wheel Ratchet Torque\"\nmsgstr \"Couple de la molette mode cliquet\"\n\n#: lib/logitech_receiver/settings_templates.py:708\nmsgid \"Change the torque needed to overcome the ratchet.\"\nmsgstr \"Modifiez le couple nécessaire pour vaincre le mode cliquet.\"\n\n#: lib/logitech_receiver/settings_templates.py:743\nmsgid \"Key/Button Actions\"\nmsgstr \"Actions des boutons\"\n\n#: lib/logitech_receiver/settings_templates.py:745\nmsgid \"Change the action for the key or button.\"\nmsgstr \"Modifiez l'action pour la touche ou pour le bouton.\"\n\n#: lib/logitech_receiver/settings_templates.py:747\nmsgid \"Overridden by diversion.\"\nmsgstr \"Remplacé par interception.\"\n\n#: lib/logitech_receiver/settings_templates.py:749\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"\"\n\"La modification d'importantes actions (comme le bouton gauche de la souris) \"\n\"pourrait rendre le système inutilisable.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid \"Key/Button Diversion\"\nmsgstr \"Interception des boutons/touches\"\n\n#: lib/logitech_receiver/settings_templates.py:925\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse \"\n\"Gestures or Sliding DPI\"\nmsgstr \"\"\n\"Active l'envoi par la touche ou le bouton de notifications HID++ \"\n\"(interception), ou une gestuelle de souris ou l'échelle de déplacement\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Diverted\"\nmsgstr \"Interception\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\nmsgid \"Mouse Gestures\"\nmsgstr \"Gestuelle à la souris\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Regular\"\nmsgstr \"Normal\"\n\n#: lib/logitech_receiver/settings_templates.py:928\nmsgid \"Sliding DPI\"\nmsgstr \"Amplification du déplacement\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"Sensibilité (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:1123\nmsgid \"Sensitivity Switching\"\nmsgstr \"Basculement de la sensibilité\"\n\n#: lib/logitech_receiver/settings_templates.py:1125\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key \"\n\"or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\"Bascule la sensibilité actuelle et la sensibilité enregistrée quand la \"\n\"touche ou le bouton sont appuyés.\\n\"\n\"S'il n'y aucune sensibilité enregistrée, rappelle uniquement la sensibilité \"\n\"courante\"\n\n#: lib/logitech_receiver/settings_templates.py:1129\nmsgid \"Off\"\nmsgstr \"Eteint\"\n\n#: lib/logitech_receiver/settings_templates.py:1160\nmsgid \"Disable keys\"\nmsgstr \"Désactiver les touches\"\n\n#: lib/logitech_receiver/settings_templates.py:1161\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"Désactiver des touches spécifiques du clavier.\"\n\n#: lib/logitech_receiver/settings_templates.py:1164\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"Désactive la touche %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1177\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid \"Set OS\"\nmsgstr \"Définir le système d'exploitation\"\n\n#: lib/logitech_receiver/settings_templates.py:1178\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid \"Change keys to match OS.\"\nmsgstr \"Modifier les touches pour correspondre au système d'exploitation.\"\n\n#: lib/logitech_receiver/settings_templates.py:1247\nmsgid \"Change Host\"\nmsgstr \"Changer d'hôte\"\n\n#: lib/logitech_receiver/settings_templates.py:1248\nmsgid \"Switch connection to a different host\"\nmsgstr \"Commuter la connexion vers un autre hôte\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Performs a left click.\"\nmsgstr \"Réalise un clic gauche.\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Single tap\"\nmsgstr \"Une tape simple\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Performs a right click.\"\nmsgstr \"Réalise un clic droit.\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Single tap with two fingers\"\nmsgstr \"Une tape simple avec deux doigts\"\n\n#: lib/logitech_receiver/settings_templates.py:1274\nmsgid \"Single tap with three fingers\"\nmsgstr \"Une tape simple avec trois doigts\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Double tap\"\nmsgstr \"Une double tape\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Performs a double click.\"\nmsgstr \"Réalise un double clic.\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid \"Double tap with two fingers\"\nmsgstr \"Une double tape avec deux doigts\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Double tap with three fingers\"\nmsgstr \"Une double tape avec trois doigts\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"Déplace des items en faisant glisser le doigt après la double tape.\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Tap and drag\"\nmsgstr \"Taper-glisser\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"Taper-glisser avec deux doigts\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"Déplace des items en faisant glisser les doigts après la double tape.\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"Taper-glisser avec trois doigts\"\n\n#: lib/logitech_receiver/settings_templates.py:1291\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"Supprimer les tapes et les gestes\"\n\n#: lib/logitech_receiver/settings_templates.py:1292\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"\"\n\"Désactive les tapes et les gestes de bords (équivaut à presser \"\n\"Fn+ClicGauche).\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\nmsgid \"Scroll with one finger\"\nmsgstr \"Défilement à un doigt\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scrolls.\"\nmsgstr \"Défilements.\"\n\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scroll with two fingers\"\nmsgstr \"Défilement à deux doigts\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"Défilement horizontal à deux doigts\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scrolls horizontally.\"\nmsgstr \"Défile horizontalement.\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"Défilement vertical à deux doigts\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scrolls vertically.\"\nmsgstr \"Défile verticalement.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"Inverse la direction de défilement.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Natural scrolling\"\nmsgstr \"Défilement naturel\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"Active la molette de pouce.\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Thumbwheel\"\nmsgstr \"Molette de pouce\"\n\n#: lib/logitech_receiver/settings_templates.py:1311\n#: lib/logitech_receiver/settings_templates.py:1315\nmsgid \"Swipe from the top edge\"\nmsgstr \"Glissement depuis le bord supérieur\"\n\n#: lib/logitech_receiver/settings_templates.py:1312\nmsgid \"Swipe from the left edge\"\nmsgstr \"Glissement depuis le bord gauche\"\n\n#: lib/logitech_receiver/settings_templates.py:1313\nmsgid \"Swipe from the right edge\"\nmsgstr \"Glissement depuis le bord droit\"\n\n#: lib/logitech_receiver/settings_templates.py:1314\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"Glissement depuis le bord inférieur\"\n\n#: lib/logitech_receiver/settings_templates.py:1316\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"Glissement à deux doigts depuis le bord gauche\"\n\n#: lib/logitech_receiver/settings_templates.py:1317\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"Glissement à deux doigts depuis le bord droit\"\n\n#: lib/logitech_receiver/settings_templates.py:1318\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"Glissement à deux doigts depuis le bord inférieur\"\n\n#: lib/logitech_receiver/settings_templates.py:1319\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"Glissement à deux doigts depuis le bord supérieur\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"Pincer pour réduire le zoom; écarter pour agrandir le zoom.\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\nmsgid \"Zoom with two fingers.\"\nmsgstr \"Zoom à deux doigts.\"\n\n#: lib/logitech_receiver/settings_templates.py:1321\nmsgid \"Pinch to zoom out.\"\nmsgstr \"Pincer pour réduire le zoom.\"\n\n#: lib/logitech_receiver/settings_templates.py:1322\nmsgid \"Spread to zoom in.\"\nmsgstr \"Écarter pour agrandir le zoom.\"\n\n#: lib/logitech_receiver/settings_templates.py:1323\nmsgid \"Zoom with three fingers.\"\nmsgstr \"Zoom à trois doigts.\"\n\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Zoom with two fingers\"\nmsgstr \"Zoom à deux doigts\"\n\n#: lib/logitech_receiver/settings_templates.py:1342\nmsgid \"Pixel zone\"\nmsgstr \"Zone de pixels\"\n\n#: lib/logitech_receiver/settings_templates.py:1343\nmsgid \"Ratio zone\"\nmsgstr \"Zone de rapport\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Scale factor\"\nmsgstr \"Facteur d’échelle\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Sets the cursor speed.\"\nmsgstr \"Définit la vitesse du curseur.\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left\"\nmsgstr \"Gauche\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left-most coordinate.\"\nmsgstr \"Coordonnée la plus à gauche.\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom\"\nmsgstr \"Bas\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom coordinate.\"\nmsgstr \"Coordonnée du bas.\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width\"\nmsgstr \"Largeur\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width.\"\nmsgstr \"Largeur.\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height\"\nmsgstr \"Hauteur\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height.\"\nmsgstr \"Hauteur.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Cursor speed.\"\nmsgstr \"Vitesse du curseur.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Scale\"\nmsgstr \"Échelle\"\n\n#: lib/logitech_receiver/settings_templates.py:1358\nmsgid \"Gestures\"\nmsgstr \"Gestes\"\n\n#: lib/logitech_receiver/settings_templates.py:1359\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"Personnaliser le comportement de la souris ou du pavé tactile.\"\n\n#: lib/logitech_receiver/settings_templates.py:1375\nmsgid \"Gestures Diversion\"\nmsgstr \"Interception de la gestuelle\"\n\n#: lib/logitech_receiver/settings_templates.py:1376\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"Interception de la gestuelle de la souris ou du pavé tactile.\"\n\n#: lib/logitech_receiver/settings_templates.py:1392\nmsgid \"Gesture params\"\nmsgstr \"Paramètres de la gestuelle\"\n\n#: lib/logitech_receiver/settings_templates.py:1393\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"Modifier les paramètres numérique de la souris ou du pavé tactile.\"\n\n#: lib/logitech_receiver/settings_templates.py:1417\nmsgid \"M-Key LEDs\"\nmsgstr \"LEDs de touche M\"\n\n#: lib/logitech_receiver/settings_templates.py:1419\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"Contrôler les LEDs de touche M.\"\n\n#: lib/logitech_receiver/settings_templates.py:1423\n#: lib/logitech_receiver/settings_templates.py:1454\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"\"\n\"Peut nécessiter que les touches G soient interceptées pour être effectif.\"\n\n#: lib/logitech_receiver/settings_templates.py:1429\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"Allume la touche %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1448\nmsgid \"MR-Key LED\"\nmsgstr \"LED de touche MR\"\n\n#: lib/logitech_receiver/settings_templates.py:1450\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"Contrôler la LED de touche MR.\"\n\n#: lib/logitech_receiver/settings_templates.py:1471\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"Mappage touche/bouton persistant\"\n\n#: lib/logitech_receiver/settings_templates.py:1473\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"Modifiez de manière permanente le mappage de la touche ou du bouton.\"\n\n#: lib/logitech_receiver/settings_templates.py:1475\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"\"\n\"La modification de touches ou de boutons importants (comme le bouton gauche \"\n\"de la souris) pourrait rendre le système inutilisable.\"\n\n#: lib/logitech_receiver/settings_templates.py:1532\nmsgid \"Sidetone\"\nmsgstr \"Tonalité latérale\"\n\n#: lib/logitech_receiver/settings_templates.py:1533\nmsgid \"Set sidetone level.\"\nmsgstr \"Régler le niveau de tonalité latérale.\"\n\n#: lib/logitech_receiver/settings_templates.py:1542\nmsgid \"Equalizer\"\nmsgstr \"Égaliseur\"\n\n#: lib/logitech_receiver/settings_templates.py:1543\nmsgid \"Set equalizer levels.\"\nmsgstr \"Définir les niveaux de l'égaliseur.\"\n\n#: lib/logitech_receiver/settings_templates.py:1565\nmsgid \"Hz\"\nmsgstr \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1571\nmsgid \"Power Management\"\nmsgstr \"Gestion de l'alimentation\"\n\n#: lib/logitech_receiver/settings_templates.py:1572\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"Éteindre en quelques minutes (0 pour jamais).\"\n\n#: lib/logitech_receiver/settings_templates.py:1584\nmsgid \"Brightness Control\"\nmsgstr \"Contrôle de la luminosité\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\nmsgid \"Control overall brightness\"\nmsgstr \"Contrôle de la luminosité globale\"\n\n#: lib/logitech_receiver/settings_templates.py:1628\n#: lib/logitech_receiver/settings_templates.py:1681\nmsgid \"LED Control\"\nmsgstr \"Contrôle de LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1629\n#: lib/logitech_receiver/settings_templates.py:1682\nmsgid \"Switch control of LED zones between device and Solaar\"\nmsgstr \"Basculer le contrôle des zones LED entre le périphérique et Solaar\"\n\n#: lib/logitech_receiver/settings_templates.py:1644\n#: lib/logitech_receiver/settings_templates.py:1692\nmsgid \"LED Zone Effects\"\nmsgstr \"Effet de zone LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr \"Le contrôle de LED doit être defini sur Solaar pour être effectif.\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"Set effect for LED Zone\"\nmsgstr \"Définir l'effet pour la zone LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1647\nmsgid \"Color\"\nmsgstr \"Couleur\"\n\n#: lib/logitech_receiver/settings_templates.py:1648\nmsgid \"Speed\"\nmsgstr \"Vitesse\"\n\n#: lib/logitech_receiver/settings_templates.py:1649\nmsgid \"Period\"\nmsgstr \"Période\"\n\n#: lib/logitech_receiver/settings_templates.py:1650\nmsgid \"Intensity\"\nmsgstr \"Intensité\"\n\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid \"Ramp\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1666\nmsgid \"LEDs\"\nmsgstr \"LEDs\"\n\n#: lib/logitech_receiver/settings_templates.py:1703\nmsgid \"Per-key Lighting\"\nmsgstr \"Éclairage par touche\"\n\n#: lib/logitech_receiver/settings_templates.py:1704\nmsgid \"Control per-key lighting.\"\nmsgstr \"Contrôler l’éclairage par touche.\"\n\n#: lib/logitech_receiver/settings_templates.py:1786\nmsgid \"Force Sensing Buttons\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1787\nmsgid \"Change the force required to activate button.\"\nmsgstr \"Modifier la force nécessaire pour activer le bouton.\"\n\n#: lib/logitech_receiver/settings_templates.py:1804\nmsgid \"Force Sensing Button\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1814\nmsgid \"Haptic Feeback Level\"\nmsgstr \"Niveau de retour haptique\"\n\n#: lib/logitech_receiver/settings_templates.py:1815\nmsgid \"Change power of haptic feedback.  (Zero to turn off.)\"\nmsgstr \"Modifiez l'intensité du retour haptique. (Zéro pour éteindre.)\"\n\n#: lib/logitech_receiver/settings_templates.py:1857\nmsgid \"Play Haptic Waveform\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1858\nmsgid \"Tell device to play a haptic waveform.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/__init__.py:120\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"\"\n\"Un autre processus Solaar est déjà en cours d'exécution, il suffit donc \"\n\"d'afficher sa fenêtre\"\n\n#: lib/solaar/ui/about/model.py:36\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"Gère les récepteurs, claviers,\\n\"\n\"souris et tablettes Logitech.\"\n\n#: lib/solaar/ui/about/model.py:63\nmsgid \"Additional Programming\"\nmsgstr \"Programmation supplémentaire\"\n\n#: lib/solaar/ui/about/model.py:64\nmsgid \"GUI design\"\nmsgstr \"Interface graphique\"\n\n#: lib/solaar/ui/about/model.py:66\nmsgid \"Testing\"\nmsgstr \"Testeur\"\n\n#: lib/solaar/ui/about/model.py:74\nmsgid \"Logitech documentation\"\nmsgstr \"Documentațion Logitech\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92\n#: lib/solaar/ui/window.py:208\nmsgid \"Unpair\"\nmsgstr \"Déconnecter\"\n\n#: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141\nmsgid \"Cancel\"\nmsgstr \"Annuler\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Permissions error\"\nmsgstr \"Erreur de permissions\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"\"\n\"Un récepteur ou un périphérique Logitech (%s) a été trouvé, mais sans \"\n\"l'autorisation de l'ouvrir.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"\"\n\"Si vous venez d'installer Solaar, essayez de déconnecter le récepteur ou le \"\n\"périphérique, puis de le reconnecter.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Cannot connect to device error\"\nmsgstr \"Impossible de se connecter au périphérique\"\n\n#: lib/solaar/ui/common.py:51\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"Un récepteur ou un périphérique Logitech a été trouvé à %s, mais une erreur \"\n\"s'est produite lors de la connexion.\"\n\n#: lib/solaar/ui/common.py:53\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"\"\n\"Essayez de déconnecter le périphérique, puis de le reconnecter ou de \"\n\"l'éteindre puis de le rallumer.\"\n\n#: lib/solaar/ui/common.py:56\nmsgid \"Unpairing failed\"\nmsgstr \"La déconnexion a échouée\"\n\n#: lib/solaar/ui/common.py:58\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"Impossible de dissocier %{device} de %{receiver}.\"\n\n#: lib/solaar/ui/common.py:63\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"Le récepteur a retourné une erreur, sans plus de détails.\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Complete - ENTER to change\"\nmsgstr \"Complet - ENTRER pour modifier\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Incomplete\"\nmsgstr \"Incomplet\"\n\n#: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"valeur %d\"\nmsgstr[1] \"valeurs %d\"\n\n#: lib/solaar/ui/config_panel.py:642\nmsgid \"Changes allowed\"\nmsgstr \"Modifications autorisées\"\n\n#: lib/solaar/ui/config_panel.py:643\nmsgid \"No changes allowed\"\nmsgstr \"Aucune modification autorisée\"\n\n#: lib/solaar/ui/config_panel.py:644\nmsgid \"Ignore this setting\"\nmsgstr \"Ignorer ce réglage\"\n\n#: lib/solaar/ui/config_panel.py:690\nmsgid \"Working\"\nmsgstr \"En fonctionnement\"\n\n#: lib/solaar/ui/config_panel.py:693\nmsgid \"Read/write operation failed.\"\nmsgstr \"Les opérations de lecture/écriture ont échouée.\"\n\n#: lib/solaar/ui/desktop_notifications.py:112\nmsgid \"unspecified reason\"\nmsgstr \"raison non précisée\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"Built-in rules\"\nmsgstr \"Règles pré-définies\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"User-defined rules\"\nmsgstr \"Règles définies par l'utilisateur\"\n\n#: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126\nmsgid \"Rule\"\nmsgstr \"Règle\"\n\n#: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382\n#: lib/solaar/ui/diversion_rules.py:509\nmsgid \"Sub-rule\"\nmsgstr \"Sous-règle\"\n\n#: lib/solaar/ui/diversion_rules.py:108\nmsgid \"[empty]\"\nmsgstr \"[vide]\"\n\n#: lib/solaar/ui/diversion_rules.py:132\nmsgid \"Make changes permanent?\"\nmsgstr \"Rendre les modifications permanentes ?\"\n\n#: lib/solaar/ui/diversion_rules.py:137\nmsgid \"Yes\"\nmsgstr \"Oui\"\n\n#: lib/solaar/ui/diversion_rules.py:139\nmsgid \"No\"\nmsgstr \"Non\"\n\n#: lib/solaar/ui/diversion_rules.py:144\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"\"\n\"Si vous choisissez Non, les changements seront perdus à la fermeture de \"\n\"Solaar.\"\n\n#: lib/solaar/ui/diversion_rules.py:273\nmsgid \"Paste here\"\nmsgstr \"Coller ici\"\n\n#: lib/solaar/ui/diversion_rules.py:275\nmsgid \"Paste above\"\nmsgstr \"Coller ci-dessus\"\n\n#: lib/solaar/ui/diversion_rules.py:277\nmsgid \"Paste below\"\nmsgstr \"Coller ci-dessous\"\n\n#: lib/solaar/ui/diversion_rules.py:283\nmsgid \"Paste rule here\"\nmsgstr \"Coller la règle ici\"\n\n#: lib/solaar/ui/diversion_rules.py:285\nmsgid \"Paste rule above\"\nmsgstr \"Coller la règle ci-dessus\"\n\n#: lib/solaar/ui/diversion_rules.py:287\nmsgid \"Paste rule below\"\nmsgstr \"Coller la règle ci-dessous\"\n\n#: lib/solaar/ui/diversion_rules.py:291\nmsgid \"Paste rule\"\nmsgstr \"Coller la règle\"\n\n#: lib/solaar/ui/diversion_rules.py:306\nmsgid \"Insert here\"\nmsgstr \"Insérer ici\"\n\n#: lib/solaar/ui/diversion_rules.py:308\nmsgid \"Insert above\"\nmsgstr \"Insérer ci-dessus\"\n\n#: lib/solaar/ui/diversion_rules.py:310\nmsgid \"Insert below\"\nmsgstr \"Insérer ci-dessous\"\n\n#: lib/solaar/ui/diversion_rules.py:316\nmsgid \"Insert new rule here\"\nmsgstr \"Insérer une nouvelle règle ici\"\n\n#: lib/solaar/ui/diversion_rules.py:318\nmsgid \"Insert new rule above\"\nmsgstr \"Insérer une nouvelle règle ci-dessus\"\n\n#: lib/solaar/ui/diversion_rules.py:320\nmsgid \"Insert new rule below\"\nmsgstr \"Insérer une nouvelle règle ci-dessous\"\n\n#: lib/solaar/ui/diversion_rules.py:347\nmsgid \"Flatten\"\nmsgstr \"Aplanir\"\n\n#: lib/solaar/ui/diversion_rules.py:380\nmsgid \"Insert\"\nmsgstr \"Insérer\"\n\n#: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511\n#: lib/solaar/ui/diversion_rules.py:1158\nmsgid \"Or\"\nmsgstr \"Ou\"\n\n#: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510\n#: lib/solaar/ui/diversion_rules.py:1144\nmsgid \"And\"\nmsgstr \"Et\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid \"Condition\"\nmsgstr \"Condition\"\n\n#: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154\nmsgid \"Feature\"\nmsgstr \"Fonctionnalité\"\n\n#: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188\nmsgid \"Report\"\nmsgstr \"Rapport\"\n\n#: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69\nmsgid \"Process\"\nmsgstr \"Processus\"\n\n#: lib/solaar/ui/diversion_rules.py:391\nmsgid \"Mouse process\"\nmsgstr \"Processus de la souris\"\n\n#: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225\nmsgid \"Modifiers\"\nmsgstr \"Modificateurs\"\n\n#: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277\nmsgid \"Key\"\nmsgstr \"Touche\"\n\n#: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318\nmsgid \"KeyIsDown\"\nmsgstr \"\"\n\n#: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432\nmsgid \"Active\"\nmsgstr \"Actif\"\n\n#: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390\n#: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487\nmsgid \"Device\"\nmsgstr \"Périphérique\"\n\n#: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467\nmsgid \"Host\"\nmsgstr \"Hôte\"\n\n#: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506\nmsgid \"Setting\"\nmsgstr \"Réglage\"\n\n#: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333\n#: lib/solaar/ui/rule_conditions.py:382\nmsgid \"Test\"\nmsgstr \"Test\"\n\n#: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507\nmsgid \"Test bytes\"\nmsgstr \"Octets de test\"\n\n#: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608\nmsgid \"Mouse Gesture\"\nmsgstr \"Geste à la souris\"\n\n#: lib/solaar/ui/diversion_rules.py:405\nmsgid \"Action\"\nmsgstr \"Action\"\n\n#: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138\nmsgid \"Key press\"\nmsgstr \"Appui de touche\"\n\n#: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191\nmsgid \"Mouse scroll\"\nmsgstr \"Défilement de la souris\"\n\n#: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256\nmsgid \"Mouse click\"\nmsgstr \"Clic de la souris\"\n\n#: lib/solaar/ui/diversion_rules.py:410\nmsgid \"Set\"\nmsgstr \"Définir\"\n\n#: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328\nmsgid \"Execute\"\nmsgstr \"Exécuter\"\n\n#: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189\nmsgid \"Later\"\nmsgstr \"Plus tard\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid \"Insert new rule\"\nmsgstr \"Insérer nouvelle règle\"\n\n#: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82\n#: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556\nmsgid \"Delete\"\nmsgstr \"Effacer\"\n\n#: lib/solaar/ui/diversion_rules.py:483\nmsgid \"Negate\"\nmsgstr \"Nier\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid \"Wrap with\"\nmsgstr \"Entoure\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid \"Cut\"\nmsgstr \"Couper\"\n\n#: lib/solaar/ui/diversion_rules.py:553\nmsgid \"Paste\"\nmsgstr \"Coller\"\n\n#: lib/solaar/ui/diversion_rules.py:559\nmsgid \"Copy\"\nmsgstr \"Copier\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Éditeur de règle Solaar\"\n\n#: lib/solaar/ui/diversion_rules.py:668\nmsgid \"Save changes\"\nmsgstr \"Sauvegarder les modifications\"\n\n#: lib/solaar/ui/diversion_rules.py:673\nmsgid \"Discard changes\"\nmsgstr \"Annuler les modifications\"\n\n#: lib/solaar/ui/diversion_rules.py:1104\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"Cet éditeur ne gère pas encore le composant de règle sélectionné.\"\n\n#: lib/solaar/ui/diversion_rules.py:1169\nmsgid \"\"\n\"Number of seconds to delay.  Delay between 0 and 1 is done with higher \"\n\"precision.\"\nmsgstr \"\"\n\"Nombre de secondes de report. Le délai entre 0 et 1 est effectué avec une \"\n\"plus grande précision.\"\n\n#: lib/solaar/ui/diversion_rules.py:1207\nmsgid \"Not\"\nmsgstr \"Non\"\n\n#: lib/solaar/ui/diversion_rules.py:1238\nmsgid \"Toggle\"\nmsgstr \"Basculer\"\n\n#: lib/solaar/ui/diversion_rules.py:1239\nmsgid \"True\"\nmsgstr \"Vrai\"\n\n#: lib/solaar/ui/diversion_rules.py:1240\nmsgid \"False\"\nmsgstr \"Faux\"\n\n#: lib/solaar/ui/diversion_rules.py:1253\nmsgid \"Unsupported setting\"\nmsgstr \"Réglage non pris en charge\"\n\n#: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415\n#: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748\n#: lib/solaar/ui/diversion_rules.py:1766\nmsgid \"Originating device\"\nmsgstr \"Périphérique d'origine\"\n\n#: lib/solaar/ui/diversion_rules.py:1428\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"Le périphérique est actif et ses paramètres peuvent être modifiés.\"\n\n#: lib/solaar/ui/diversion_rules.py:1437\nmsgid \"Device that originated the current notification.\"\nmsgstr \"Périphérique à l’origine de la notification actuelle.\"\n\n#: lib/solaar/ui/diversion_rules.py:1450\nmsgid \"Name of host computer.\"\nmsgstr \"Nom de l'ordinateur hôte.\"\n\n#: lib/solaar/ui/diversion_rules.py:1520\nmsgid \"Value\"\nmsgstr \"Valeur\"\n\n#: lib/solaar/ui/diversion_rules.py:1529\nmsgid \"Item\"\nmsgstr \"Item\"\n\n#: lib/solaar/ui/diversion_rules.py:1808\nmsgid \"Change setting on device\"\nmsgstr \"Modifier le réglage sur le périphérique\"\n\n#: lib/solaar/ui/diversion_rules.py:1824\nmsgid \"Setting on device\"\nmsgstr \"Réglage sur le périphérique\"\n\n#: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s : jumele le nouveau périphérique\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"\"\n\"Les récepteurs Bolt ne sont compatibles qu'avec des périphériques Bolt.\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"\"\n\"Appuyez sur un bouton ou une touche d'appairage jusqu'à ce que le voyant \"\n\"clignote rapidement.\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"\"\n\"Les récepteurs Unifying ne sont compatibles qu'avec des périphériques \"\n\"Unifying.\"\n\n#: lib/solaar/ui/pair_window.py:53\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"\"\n\"Les autres récepteurs sont uniquement compatibles avec quelques \"\n\"périphériques.\"\n\n#: lib/solaar/ui/pair_window.py:55\nmsgid \"For most devices, turn on the device you want to pair.\"\nmsgstr \"\"\n\"Pour la plupart des périphériques, allumez le périphérique que vous \"\n\"souhaitez jumeler.\"\n\n#: lib/solaar/ui/pair_window.py:56\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"\"\n\"Si le périphérique est déjà allumé, éteignez-le et rallumez-le à nouveau.\"\n\n#: lib/solaar/ui/pair_window.py:58\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"\"\n\"Le périphérique doit être jumelé avec un récepteur de proximité allumé.\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid \"\"\n\"For devices with multiple channels, press, hold, and release the button for \"\n\"the channel you wish to pair\\n\"\n\"or use the channel switch button to select a channel and then press, hold, \"\n\"and release the channel switch button.\"\nmsgstr \"\"\n\"Pour les périphériques disposant de plusieurs canaux, appuyez sur le bouton \"\n\"du canal que vous souhaitez appairer, maintenez-le enfoncé, puis relâchez-\"\n\"le.\\n\"\n\"\\n\"\n\"Ou utilisez le bouton de changement de canal pour sélectionner un canal, \"\n\"puis appuyez sur le bouton de changement de canal, maintenez-le enfoncé, \"\n\"puis relâchez-le.\"\n\n#: lib/solaar/ui/pair_window.py:68\nmsgid \"The channel indicator light should be blinking rapidly.\"\nmsgstr \"Le voyant indicateur du canal doit clignoter rapidement.\"\n\n#: lib/solaar/ui/pair_window.py:72\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"Ce récepteur a %d jumelage restant.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"Ce récepteur a %d jumelages restants.\"\n\n#: lib/solaar/ui/pair_window.py:78\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"L'annulation à ce stade n'utilisera pas de jumelage.\"\n\n#: lib/solaar/ui/pair_window.py:168\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"Entrer le mot de passe sur %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:171\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"Taper %(passcode)s puis appuyez sur la touche Entrée.\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"left\"\nmsgstr \"gauche\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"right\"\nmsgstr \"droit\"\n\n#: lib/solaar/ui/pair_window.py:178\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"Appuyez %(code)s\\n\"\n\"puis appuyez simultanément sur les boutons gauche et droit.\"\n\n#: lib/solaar/ui/pair_window.py:221\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"La connexion sans fil n'est pas chiffrée\"\n\n#: lib/solaar/ui/pair_window.py:226\nmsgid \"Found a new device:\"\nmsgstr \"Nouveau périphérique disponible :\"\n\n#: lib/solaar/ui/pair_window.py:247\nmsgid \"Pairing failed\"\nmsgstr \"Le jumelage a échoué\"\n\n#: lib/solaar/ui/pair_window.py:249\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"\"\n\"Assurez-vous que votre périphérique soit à portée, et que sa batterie soit \"\n\"suffisamment chargée.\"\n\n#: lib/solaar/ui/pair_window.py:251\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"\"\n\"Un nouveau périphérique a été détecté, mais il n'est pas compatible avec ce \"\n\"récepteur.\"\n\n#: lib/solaar/ui/pair_window.py:253\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"\"\n\"Il y a plus de périphériques jumelés que le récepteur ne peut en supporter.\"\n\n#: lib/solaar/ui/pair_window.py:255\nmsgid \"No further details are available about the error.\"\nmsgstr \"Aucun autre détail n'est disponible à propos de l'erreur.\"\n\n#: lib/solaar/ui/rule_actions.py:54\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simule un clic combiné ou une pression ou un relâchement.\\n\"\n\"Sous Wayland cela nécessite un accès en écriture au périphérique /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:60\nmsgid \"Add key\"\nmsgstr \"Ajouter une touche\"\n\n#: lib/solaar/ui/rule_actions.py:63\nmsgid \"Click\"\nmsgstr \"Clic\"\n\n#: lib/solaar/ui/rule_actions.py:66\nmsgid \"Depress\"\nmsgstr \"Appuyer\"\n\n#: lib/solaar/ui/rule_actions.py:69\nmsgid \"Release\"\nmsgstr \"Relâcher\"\n\n#: lib/solaar/ui/rule_actions.py:153\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simule un défilement de souris.\\n\"\n\"Sous Wayland cela nécessite un accès en écriture au périphérique /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:211\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simule un clic de souris.\\n\"\n\"Sous Wayland cela nécessite un accès en écriture au périphérique /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:216\nmsgid \"Button\"\nmsgstr \"Bouton\"\n\n#: lib/solaar/ui/rule_actions.py:218\nmsgid \"Action (and Count, if click)\"\nmsgstr \"Action (et nombre, en cas de clic)\"\n\n#: lib/solaar/ui/rule_actions.py:269\nmsgid \"Execute a command with arguments.\"\nmsgstr \"Exécuter une commande avec paramètres.\"\n\n#: lib/solaar/ui/rule_actions.py:273\nmsgid \"Add argument\"\nmsgstr \"Ajouter un paramètre\"\n\n#: lib/solaar/ui/rule_conditions.py:52\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"Processus actif X11. Pour une utilisation dans X11 uniquement.\"\n\n#: lib/solaar/ui/rule_conditions.py:82\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"Processus de la souris X11. Pour une utilisation dans X11 uniquement.\"\n\n#: lib/solaar/ui/rule_conditions.py:99\nmsgid \"MouseProcess\"\nmsgstr \"Processus de la souris\"\n\n#: lib/solaar/ui/rule_conditions.py:123\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"\"\n\"Nom de la fonction de notification déclenchant le traitement de la règle.\"\n\n#: lib/solaar/ui/rule_conditions.py:169\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"\"\n\"Indique le nombre de notifications déclenchant le traitement de la règle.\"\n\n#: lib/solaar/ui/rule_conditions.py:201\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"Modificateurs de clavier actifs. Pas toujours disponible sous Wayland.\"\n\n#: lib/solaar/ui/rule_conditions.py:241\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Interception de touche ou bouton appuyé ou relâché.\\n\"\n\"Utiliser l'interception de touche/bouton et les paramètres Interception des \"\n\"touches G pour intercepter les touches et les boutons.\"\n\n#: lib/solaar/ui/rule_conditions.py:250\nmsgid \"Key down\"\nmsgstr \"Enfoncement de touche\"\n\n#: lib/solaar/ui/rule_conditions.py:253\nmsgid \"Key up\"\nmsgstr \"Relâchement de touche\"\n\n#: lib/solaar/ui/rule_conditions.py:293\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"La touche/le bouton intercepté est actuellement enfoncé.\\n\"\n\"Utiliser l'interception de touche/bouton et les paramètres Interception des \"\n\"touches G pour intercepter les touches et les boutons.\"\n\n#: lib/solaar/ui/rule_conditions.py:331\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"\"\n\"Condition de test déclenchant le traitement de la règle en cas de \"\n\"notification.\"\n\n#: lib/solaar/ui/rule_conditions.py:335\nmsgid \"Parameter\"\nmsgstr \"Paramètre\"\n\n#: lib/solaar/ui/rule_conditions.py:408\nmsgid \"begin (inclusive)\"\nmsgstr \"début (inclusif)\"\n\n#: lib/solaar/ui/rule_conditions.py:409\nmsgid \"end (exclusive)\"\nmsgstr \"fin (exclusif)\"\n\n#: lib/solaar/ui/rule_conditions.py:417\nmsgid \"range\"\nmsgstr \"plage\"\n\n#: lib/solaar/ui/rule_conditions.py:420\nmsgid \"minimum\"\nmsgstr \"minimum\"\n\n#: lib/solaar/ui/rule_conditions.py:421\nmsgid \"maximum\"\nmsgstr \"maximum\"\n\n#: lib/solaar/ui/rule_conditions.py:423\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"octets %(0)d à %(1)d, allant de %(2)d à %(3)d\"\n\n#: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427\nmsgid \"mask\"\nmsgstr \"masque\"\n\n#: lib/solaar/ui/rule_conditions.py:428\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"octets %(0)d à %(1)d, masque %(2)d\"\n\n#: lib/solaar/ui/rule_conditions.py:437\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\"Bit ou plage d'octets dans un message de notification déclenchant le \"\n\"traitement d'une règle.\"\n\n#: lib/solaar/ui/rule_conditions.py:447\nmsgid \"type\"\nmsgstr \"type\"\n\n#: lib/solaar/ui/rule_conditions.py:535\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"\"\n\"Geste de la souris avec bouton d'initialisation optionnel suivi ou non par \"\n\"des déplacements de souris.\"\n\n#: lib/solaar/ui/rule_conditions.py:541\nmsgid \"Add movement\"\nmsgstr \"Ajouter un mouvement\"\n\n#: lib/solaar/ui/tray.py:55\nmsgid \"No supported device found\"\nmsgstr \"Aucun périphérique pris en charge trouvé\"\n\n#: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328\n#, python-format\nmsgid \"About %s\"\nmsgstr \"À propos de %s\"\n\n#: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"Quitter %s\"\n\n#: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281\nmsgid \"no receiver\"\nmsgstr \"aucun récepteur\"\n\n#: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299\n#: lib/solaar/ui/window.py:728\nmsgid \"offline\"\nmsgstr \"non connecté\"\n\n#: lib/solaar/ui/tray.py:297\nmsgid \"no status\"\nmsgstr \"aucun statut\"\n\n#: lib/solaar/ui/window.py:110\nmsgid \"Scanning\"\nmsgstr \"Balayage\"\n\n#: lib/solaar/ui/window.py:141\nmsgid \"Battery\"\nmsgstr \"Batterie\"\n\n#: lib/solaar/ui/window.py:144\nmsgid \"Wireless Link\"\nmsgstr \"Connexion sans fil\"\n\n#: lib/solaar/ui/window.py:148\nmsgid \"Lighting\"\nmsgstr \"Éclairage\"\n\n#: lib/solaar/ui/window.py:182\nmsgid \"Show Technical Details\"\nmsgstr \"Afficher les détails techniques\"\n\n#: lib/solaar/ui/window.py:198\nmsgid \"Pair new device\"\nmsgstr \"Jumeler un nouveau périphérique\"\n\n#: lib/solaar/ui/window.py:216\nmsgid \"Select a device\"\nmsgstr \"Sélectionner un périphérique\"\n\n#: lib/solaar/ui/window.py:331\nmsgid \"Rule Editor\"\nmsgstr \"Éditeur de règles\"\n\n#: lib/solaar/ui/window.py:522\nmsgid \"Path\"\nmsgstr \"Chemin\"\n\n#: lib/solaar/ui/window.py:524\nmsgid \"USB ID\"\nmsgstr \"ID USB\"\n\n#: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529\n#: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546\nmsgid \"Serial\"\nmsgstr \"Numéro de série\"\n\n#: lib/solaar/ui/window.py:533\nmsgid \"Index\"\nmsgstr \"Index\"\n\n#: lib/solaar/ui/window.py:535\nmsgid \"Wireless PID\"\nmsgstr \"PID sans fil\"\n\n#: lib/solaar/ui/window.py:537\nmsgid \"Product ID\"\nmsgstr \"Identifiant produit\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Protocol\"\nmsgstr \"Protocole\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Unknown\"\nmsgstr \"Inconnu\"\n\n#: lib/solaar/ui/window.py:541\nmsgid \"Polling rate\"\nmsgstr \"Taux de scrutation\"\n\n#: lib/solaar/ui/window.py:548\nmsgid \"Unit ID\"\nmsgstr \"ID d'unité\"\n\n#: lib/solaar/ui/window.py:559\nmsgid \"none\"\nmsgstr \"aucun\"\n\n#: lib/solaar/ui/window.py:560\nmsgid \"Notifications\"\nmsgstr \"Notifications\"\n\n#: lib/solaar/ui/window.py:604\nmsgid \"No device paired.\"\nmsgstr \"Aucun périphérique jumelé.\"\n\n#: lib/solaar/ui/window.py:613\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"Jusqu'à %(max_count)s périphérique peut être jumelé à ce récepteur.\"\nmsgstr[1] \"\"\n\"Jusqu'à %(max_count)s périphériques peuvent être jumelés à ce récepteur.\"\n\n#: lib/solaar/ui/window.py:620\nmsgid \"Only one device can be paired to this receiver.\"\nmsgstr \"Un seul périphérique peut être jumelé à ce récepteur.\"\n\n#: lib/solaar/ui/window.py:624\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"Ce récepteur a %d jumelage restant.\"\nmsgstr[1] \"Ce récepteur a %d jumelages restants.\"\n\n#: lib/solaar/ui/window.py:681\nmsgid \"Battery Voltage\"\nmsgstr \"Tension de la batterie\"\n\n#: lib/solaar/ui/window.py:683\nmsgid \"Voltage reported by battery\"\nmsgstr \"Tension indiquée par la batterie\"\n\n#: lib/solaar/ui/window.py:685\nmsgid \"Battery Level\"\nmsgstr \"Niveau de la batterie\"\n\n#: lib/solaar/ui/window.py:687\nmsgid \"Approximate level reported by battery\"\nmsgstr \"Niveau approximatif indiqué par la batterie\"\n\n#: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696\nmsgid \"next reported \"\nmsgstr \"prochain rapport \"\n\n#: lib/solaar/ui/window.py:697\nmsgid \" and next level to be reported.\"\nmsgstr \" et prochain niveau à rapporter.\"\n\n#: lib/solaar/ui/window.py:702\nmsgid \"last known\"\nmsgstr \"dernière valeur connue\"\n\n#: lib/solaar/ui/window.py:713\nmsgid \"encrypted\"\nmsgstr \"chiffrée\"\n\n#: lib/solaar/ui/window.py:715\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"\"\n\"La connexion sans fil entre ce périphérique et son récepteur est chiffrée.\"\n\n#: lib/solaar/ui/window.py:717\nmsgid \"not encrypted\"\nmsgstr \"non chiffrée\"\n\n#: lib/solaar/ui/window.py:721\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"La connexion sans fil entre ce périphérique et son récepteur n'est pas \"\n\"chiffrée.\\n\"\n\"Ceci est un problème de sécurité pour les dispositifs de pointage, et un \"\n\"problème majeur pour les périphériques de saisie de texte.\"\n\n#: lib/solaar/ui/window.py:737\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d lux\"\n\n#, python-format\n#~ msgid \"%(rate)d ms (%(rate_hz)dHz)\"\n#~ msgstr \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#, python-format\n#~ msgid \"Battery: %(level)s\"\n#~ msgstr \"Batterie : %(level)s\"\n\n#, python-format\n#~ msgid \"Battery: %(percent)d%%\"\n#~ msgstr \"Batterie : %(percent)d%%\"\n\n#~ msgid \"Count and Action\"\n#~ msgstr \"Nombre et action\"\n\n#~ msgid \"Divert G Keys\"\n#~ msgstr \"Définir les touches G\"\n\n#~ msgid \"\"\n#~ \"Enable onboard profiles, which often control report rate and keyboard \"\n#~ \"lighting\"\n#~ msgstr \"\"\n#~ \"Active les profils embarqués, qui contrôlent souvent le taux de rapport \"\n#~ \"et l'éclairage du clavier\"\n\n#~ msgid \"Frequency of device polling, in milliseconds\"\n#~ msgstr \"Fréquence de scrutation du périphérique, en millisecondes\"\n\n#, python-format\n#~ msgid \"Lighting: %(level)s lux\"\n#~ msgstr \"Éclairage : %(level)s lux\"\n\n#~ msgid \"\"\n#~ \"Make G keys send GKEY HID++ notifications (which trigger Solaar rules but \"\n#~ \"are otherwise ignored).\"\n#~ msgstr \"\"\n#~ \"Active l'envoi par les touches G de notifications GKEY HID++ (ce qui \"\n#~ \"déclenche les règles Solaar qui sont ignorées sinon).\"\n\n#~ msgid \"May also make M keys and MR key send HID++ notifications\"\n#~ msgstr \"\"\n#~ \"Peut aussi permettre que les touches M et la touche MR envoient des \"\n#~ \"notifications HID++\"\n\n#~ msgid \"Number of seconds to delay.\"\n#~ msgstr \"Nombre de secondes de report.\"\n\n#~ msgid \"Polling Rate (ms)\"\n#~ msgstr \"Taux de scrutation (ms)\"\n\n#~ msgid \"Turn illumination on or off on keyboard.\"\n#~ msgstr \"Activez ou désactivez l'éclairage sur le clavier.\"\n\n#~ msgid \"Turn on the device you want to pair.\"\n#~ msgstr \"Allumez le périphérique que vous souhaitez jumeler.\"\n\n#~ msgid \"You may have to first turn the device off and on again.\"\n#~ msgstr \"Vous devriez tout d' abord éteindre le périphérique et le rallumer.\"\n"
  },
  {
    "path": "po/hr.po",
    "content": "# Croatian translations for solaar package\n# Copyright (C) YEAR THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# gogo <trebelnik2@gmail.com>, 2014.\n#\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 1.0.1\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n        \"PO-Revision-Date: 2022-10-28 10:37+0200\\n\"\n        \"Last-Translator: gogo <trebelnik2@gmail.com>\\n\"\n        \"Language-Team: Croatian <hr@hr.org>\\n\"\n        \"Language: hr\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 \"\n        \"&& n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\\n\"\n        \"X-Generator: Poedit 3.0.1\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid   \"Bolt Receiver\"\nmsgstr  \"Bolt prijemnik\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid   \"Unifying Receiver\"\nmsgstr  \"Unifying prijemnik\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid   \"Nano Receiver\"\nmsgstr  \"Nano prijemnik\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"Lightspeed prijemnik\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"EX100 prijemnik 27 Mhz\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"empty\"\nmsgstr  \"prazna\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"critical\"\nmsgstr  \"kritično\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"low\"\nmsgstr  \"slaba\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"average\"\nmsgstr  \"prosječna\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid   \"good\"\nmsgstr  \"dobra\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"full\"\nmsgstr  \"napunjena\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"discharging\"\nmsgstr  \"pražnjenje\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"recharging\"\nmsgstr  \"punjenje\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid   \"charging\"\nmsgstr  \"punjenje\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"not charging\"\nmsgstr  \"ne puni se\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"almost full\"\nmsgstr  \"uskoro puno\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"charged\"\nmsgstr  \"napunjena\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"slow recharge\"\nmsgstr  \"sporo punjenje\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"invalid battery\"\nmsgstr  \"neispravna baterija\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"thermal error\"\nmsgstr  \"toplinska greška\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"error\"\nmsgstr  \"greška\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid   \"standard\"\nmsgstr  \"standardno\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"fast\"\nmsgstr  \"brzo\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"slow\"\nmsgstr  \"sporo\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid   \"device timeout\"\nmsgstr  \"istek čekanja uređaja\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid   \"device not supported\"\nmsgstr  \"uređaj nije podržan\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"too many devices\"\nmsgstr  \"previše uređaja\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"sequence timeout\"\nmsgstr  \"redoslijed isteka vremena\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid   \"Firmware\"\nmsgstr  \"Firmver\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Bootloader\"\nmsgstr  \"Učitač pokretanja\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Hardware\"\nmsgstr  \"Hardver\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Other\"\nmsgstr  \"Ostalo\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Left Button\"\nmsgstr  \"Lijeva tipka\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"Right Button\"\nmsgstr  \"Desna tipka\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Middle Button\"\nmsgstr  \"Srednja tipka\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Back Button\"\nmsgstr  \"Tipka za natrag\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Forward Button\"\nmsgstr  \"Tipka za naprijed\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"Tipka gesta miša\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Smart Shift\"\nmsgstr  \"Pametan pomak\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"DPI Switch\"\nmsgstr  \"DPI prebacivač\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Left Tilt\"\nmsgstr  \"Lijevi nagib\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Right Tilt\"\nmsgstr  \"Desni nagib\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Left Click\"\nmsgstr  \"Lijevi klik\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Right Click\"\nmsgstr  \"Desni klik\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"Srednja tipka miša\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"Mouse Back Button\"\nmsgstr  \"Tipka miša za natrag\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"Tipka miša za naprijed\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"Tipka navigacije gesta\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"Lijeva tipka pomicanja miša\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"Desna tipka pomicanja miša\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid   \"pressed\"\nmsgstr  \"pritisak\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid   \"released\"\nmsgstr  \"otpuštanje\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is closed\"\nmsgstr  \"uparivanje je zatvoreno\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is open\"\nmsgstr  \"uparivanje je otvoreno\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is closed\"\nmsgstr  \"otkrivanje je zatvoreno\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is open\"\nmsgstr  \"otkrivanje je otvoreno\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid   \"connected\"\nmsgstr  \"povezano\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid   \"disconnected\"\nmsgstr  \"nije povezano\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid   \"unpaired\"\nmsgstr  \"neupareno\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid   \"powered on\"\nmsgstr  \"uključen\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid   \"register\"\nmsgstr  \"registar\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid   \"feature\"\nmsgstr  \"značajka\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid   \"Swap Fx function\"\nmsgstr  \"Zamijeni Fx funkciju\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"Kada je omogućeno, tipke F1..F12 će aktivirati svoje dodatne \"\n        \"funkcije,\\n\"\n        \"a za aktivaciju njihovih osnovnih funkcija morate držati FN tipku.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"Kada nije omogućeno, tipke F1..F12 će aktivirati svoje osnovne \"\n        \"funkcije,\\n\"\n        \"a za aktivaciju njihovih dodatnih funkcija morate držati FN tipku.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid   \"Hand Detection\"\nmsgstr  \"Otkrivanje ruku\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"Uključite osvjetljenje kada ruke lebde nad tipkovnicom.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"Glatko pomicanje kotačićem\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"Visokoosjetljivi način okomitog pomicanja kotačićem.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid   \"Side Scrolling\"\nmsgstr  \"Bočno pomicanje kotačićem\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"Kad je onemogućeno, guranje kotačića ustranu šalje prilagođeni \"\n        \"događaj tipke\\n\"\n        \"umjesto uobičajanog događaja bočnog pomicanja.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"Osjetljivost (DPI - stariji miševi)\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"Osjetljivost pomicanja miša\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid   \"Backlight\"\nmsgstr  \"Osvjetljenje\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"Postavite vrijeme osvjetljenja tipkovnice.\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid   \"Turn illumination on or off on keyboard.\"\nmsgstr  \"Uključite ili isključite osvjetljenje tipkovnice.\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"Visokoosjetljivi način pomicanja kotačićem\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"Postavite na zanemareno ako je pomicanje prebrzo ili presporo\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"Preusmjeravanje pomicanja kotačića\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"Neka kotačić pomicanja šalje LOWRES_WHEEL HID++ obavijesti (što \"\n        \"pokreće Solaar pravila, u suprotnome ih zanemaruje).\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"Smjer pomicanja kotačića\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"Obrnuti smjer za okomito pomicanje kotačićem.\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"Osjetljivost pomicanja kotačićem\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"Neka kotačić pomicanja šalje HIRES_WHEEL HID++ obavijesti (što \"\n        \"pokreće Solaar pravila, u suprotnome ih zanemaruje).\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"Osjetljivost (Brzina pokazivača)\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"Množitelj brzine za miš (256 je normalan množitelj).\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"Preusmjeravanje pomicanja kotačića palca\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"Neka kotačić palca šalje THUMB_WHEEL HID++ obavijesti (što pokreće \"\n        \"Solaar pravila, u suprotnome ih zanemaruje).\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"Smjer pomicanja kotačića palca\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"Obrnuti smjer pomicanja kotačića palca.\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid   \"Onboard Profiles\"\nmsgstr  \"Onboard profili\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid   \"Enable onboard profiles, which often control report rate and \"\n        \"keyboard lighting\"\nmsgstr  \"Omogućite onboard profile, koji najčešće upravljaju brzinom \"\n        \"pozivanja i osvjetljenjem tipkovnice\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid   \"Polling Rate (ms)\"\nmsgstr  \"Brzina pozivanja (ms)\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid   \"Frequency of device polling, in milliseconds\"\nmsgstr  \"Učestalost pozivanja uređaja, u milisekundama\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"Možda je potrebno postaviti Onboard profile na 'Onemogućeno' kako bi \"\n        \"bili učinkoviti.\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid   \"Divert crown events\"\nmsgstr  \"Preusmjeri crown događaje\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Neka crown šalje CROWN HID++ obavijesti (što pokreće Solaar pravila, \"\n        \"u suprotnome ih zanemaruje).\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"Crown glatko pomicanje\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"Postavite Crown glatko pomicanje\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid   \"Divert G Keys\"\nmsgstr  \"Preusmjeri G tipke\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid   \"Make G keys send GKEY HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Neka G tipke šalju GKEY HID++ obavijesti (što pokreće Solaar \"\n        \"pravila, u suprotnome ih zanemaruje).\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid   \"May also make M keys and MR key send HID++ notifications\"\nmsgstr  \"Neka isto M tipke i MR tipka šalje HID++ obavijesti\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"Ustavljanje pomicanja kotačića\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"Prebaci kotačić miša između ustavljačkog brzinom upravljanog načina \"\n        \"i slobodnog načina vrtnje kotačića.\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Freespinning\"\nmsgstr  \"Slobodna vrtnja\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Ratcheted\"\nmsgstr  \"Ustavljanje\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"Brzina ustavljanja pomicanja kotačića\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"Koristite brzinu kotačića miša za prebacivanje između ustavljačkog i \"\n        \"slobodnog načina vrtnje kotačića.\\n\"\n        \"Kotačić miša je uvijek ustavljen pri 50.\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid   \"Key/Button Actions\"\nmsgstr  \"Radnje tipki\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"Promijeni radnju za tipku.\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"Preusmjereno skretanjem.\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"Promjena bitnih radnji (poput lijeve tipke miša) može prouzrokovati \"\n        \"nestabilnosti u sustavu.\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"Preusmjeravanje tipki\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"Neka tipka ili šalje HID++ obavijesti (preusmjerene) ili pokreće \"\n        \"gete mišem ili klizni DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Diverted\"\nmsgstr  \"Preusmjerno\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid   \"Mouse Gestures\"\nmsgstr  \"Geste miša\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Regular\"\nmsgstr  \"Normalna\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid   \"Sliding DPI\"\nmsgstr  \"Klizni DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"Osjetljivost (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"Prebacivanje osjetljivosti\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"Prebacivanje trenutne osjetljivosti i zapamćene osjetljivosti kada \"\n        \"se tipka pritisne.\\n\"\n        \"Ako ne postoji zapamćena osjetljivost, zapamti trenutnu osjetljivost\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid   \"Off\"\nmsgstr  \"Isključeno\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid   \"Disable keys\"\nmsgstr  \"Onemogući tipke\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"Onemogući određene tipke tipkovnice.\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"Onemogućuje %s tipku.\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid   \"Set OS\"\nmsgstr  \"Postavi OS\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"Promijeni tipke tako da se podudaraju sa OS-om.\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid   \"Change Host\"\nmsgstr  \"Promijeni računalo\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"Prebaci povezivanje na drugo računalo\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Performs a left click.\"\nmsgstr  \"Izvodi lijevi klik.\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Single tap\"\nmsgstr  \"Jednostruki dodir\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Performs a right click.\"\nmsgstr  \"Izvodi desni klik.\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"Jednostruki dodir s dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"Jednostruki dodir s tri prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Double tap\"\nmsgstr  \"Dvostruki dodir\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Performs a double click.\"\nmsgstr  \"Izvodi dvostruki klik.\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"Dvostruki dodir s dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"Dvostruki dodir s tri prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"Povlačite stavke povlačenjem prsta nakon dvostrukog dodira.\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Tap and drag\"\nmsgstr  \"Dodirni i povuci\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"Povlačite stavke povlačenjem prsta nakon dvostrukog dodira.\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"Dodirni i povuci s dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"Dodirni i povuci s tri prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"Onemogućuje dodir i rubne geste (ekvivalent pritiska na Fn+Lijevi \"\n        \"klik)\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"Onemogući dodir i rubne geste\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid   \"Scroll with one finger\"\nmsgstr  \"Pomicanje s jednim prstom\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scrolls.\"\nmsgstr  \"Pomicanje.\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"Pomicanje s dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"Vodoravno pomicanje s dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"Vodoravno pomicanje.\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"Okomito pomicanje s dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"Okomito pomicanje.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"Obrnite smjer pomicanja.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Natural scrolling\"\nmsgstr  \"Prirodno pomicanje\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"Omogućite kotačić palca.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Thumbwheel\"\nmsgstr  \"Kotačić palca\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"Prijeđite prstom od gornjeg ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"Prijeđite prstom od lijevog ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"Prijeđite prstom od desnog ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"Prijeđite prstom od donjeg ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"Prijeđite s dva prsta od lijevog ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"Prijeđite s dva prsta od desnog ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"Prijeđite s dva prsta od donjeg ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"Prijeđite s dva prsta od gornjeg ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"Skupite prste za smanjivanje; raširite prste za uvećanje.\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"Uvećanje/Smanjenje s dva prsta.\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"Skupite prste za smanjivanje.\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"Raširite prste za uvećanje.\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"Uvećanje/Smanjenje s tri prsta.\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"Uvećanje/Smanjenje s dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid   \"Pixel zone\"\nmsgstr  \"Zona piksela\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid   \"Ratio zone\"\nmsgstr  \"Zona omjera\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Scale factor\"\nmsgstr  \"Faktor veličine\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"Postavlja brzinu pokazivača.\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left\"\nmsgstr  \"Lijevo\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"Najčešća lijeva koordinata.\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom\"\nmsgstr  \"Dno\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"Koordinata na dnu.\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width\"\nmsgstr  \"Širina\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width.\"\nmsgstr  \"Širina.\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height\"\nmsgstr  \"Visina\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height.\"\nmsgstr  \"Visina.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Cursor speed.\"\nmsgstr  \"Brzina pokazivača.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Scale\"\nmsgstr  \"Prilagodba veličine\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid   \"Gestures\"\nmsgstr  \"Geste\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"Prilagodite ponašanje miša/touchpada.\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid   \"Gestures Diversion\"\nmsgstr  \"Preusmjeravanje gesta\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"Preusmjerite ponašanje miša/touchpada.\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid   \"Gesture params\"\nmsgstr  \"Parametri gesta\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"Promijenite brojčane parametre miša/touchpada.\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid   \"M-Key LEDs\"\nmsgstr  \"LED osvjetljenje M-tipke\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"Upravljajte LED osvjetljenjem M-tipke.\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"Možda je potrebno preusmjeravanje G tipka kako bi bile učinkovite.\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"Osvijetli %s tipku.\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid   \"MR-Key LED\"\nmsgstr  \"LED osvjetljenje MR-tipke\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"Upravljajte LED osvjetljenjem MR-tipke.\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"Trajno mapiranje tipka\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"Trajno promijenite mapiranje za tipku.\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"Promjena bitnih tipka (poput lijeve tipke miša) može prouzrokovati \"\n        \"nestabilnosti u sustavu.\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Sidetone\"\nmsgstr  \"Bočni ton\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid   \"Set sidetone level.\"\nmsgstr  \"Postavi razinu bočnog tona.\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid   \"Equalizer\"\nmsgstr  \"Ekvalizator\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"Postavi razine ekvilizatora.\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid   \"Hz\"\nmsgstr  \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid   \"Power Management\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid   \"No paired devices.\"\nmsgstr  \"Nema uparenih uređaja.\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"%(count)s upareni uređaj.\"\nmsgstr[1]       \"%(count)s uparena uređaja.\"\nmsgstr[2]       \"%(count)s uparenih uređaj.\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid   \"Battery: %(level)s\"\nmsgstr  \"Baterija: %(level)s\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid   \"Battery: %(percent)d%%\"\nmsgstr  \"Baterija: %(percent)d%%\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid   \"Lighting: %(level)s lux\"\nmsgstr  \"Osvjetljenje: %(level)s lux\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"Baterija: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"Baterija: %(percent)d%% (%(status)s)\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid   \"Permissions error\"\nmsgstr  \"Greška dozvole\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"Nemoguće povezivanje s uređajem, greška\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"Pronađen je Logitech prijemnik ili uređaj na %s, ali je naišao na \"\n        \"grešku pri povezivanju.\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid   \"Unpairing failed\"\nmsgstr  \"Uparivanje neuspjelo\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"Neuspjelo uparivanje %{device} s %{receiver}.\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"Došlo je do greške kod prijemnika, bez više pojedinosti.\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"Drugi Solaar proces je već pokrenut stoga samo prikaži njegov prozor\"\n\n#: lib/solaar/ui/about.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"Upravljajte Logitechovim prijemnicima,\\n\"\n        \"tipkovnicama, miševima, i tabletima.\"\n\n#: lib/solaar/ui/about.py:44\nmsgid   \"Additional Programming\"\nmsgstr  \"Dodatno programiranje\"\n\n#: lib/solaar/ui/about.py:45\nmsgid   \"GUI design\"\nmsgstr  \"GUI dizajn\"\n\n#: lib/solaar/ui/about.py:47\nmsgid   \"Testing\"\nmsgstr  \"Testiranje\"\n\n#: lib/solaar/ui/about.py:54\nmsgid   \"Logitech documentation\"\nmsgstr  \"Logitech dokumentacija\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid   \"Unpair\"\nmsgstr  \"Odpari\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid   \"Cancel\"\nmsgstr  \"Odustani\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"Potpuno - ENTER za promjenu\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Incomplete\"\nmsgstr  \"Nepotpuno\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"%d vrijednost\"\nmsgstr[1]       \"%d vrijednosti\"\nmsgstr[2]       \"%d vrijednosti\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid   \"Changes allowed\"\nmsgstr  \"Promjene su dopuštene\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid   \"No changes allowed\"\nmsgstr  \"Promjene nisu dopuštene\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid   \"Ignore this setting\"\nmsgstr  \"Zanemari ovu postavku\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid   \"Working\"\nmsgstr  \"Izvodi se\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"Radnja čitanja/pisanja neuspjela.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"Built-in rules\"\nmsgstr  \"Ugrađena pravila\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"User-defined rules\"\nmsgstr  \"Korisnički određena pravila\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid   \"Rule\"\nmsgstr  \"Pravilo\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid   \"Sub-rule\"\nmsgstr  \"Podpravilo\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid   \"[empty]\"\nmsgstr  \"[prazno]\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"Solaar uređivač pravila\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Make changes permanent?\"\nmsgstr  \"Učini promjene trajnima?\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid   \"Yes\"\nmsgstr  \"Da\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid   \"No\"\nmsgstr  \"Ne\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"Ako odaberete 'Ne', promjene će biti izgubljene kada se Solaar \"\n        \"zatvori.\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid   \"Save changes\"\nmsgstr  \"Spremi promjene\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid   \"Discard changes\"\nmsgstr  \"Odbaci promjene\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid   \"Insert here\"\nmsgstr  \"Umetni ovdje\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid   \"Insert above\"\nmsgstr  \"Umetni iznad\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid   \"Insert below\"\nmsgstr  \"Umetni ispod\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid   \"Insert new rule here\"\nmsgstr  \"Umetni novo pravilo ovdje\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid   \"Insert new rule above\"\nmsgstr  \"Umetni novo pravilo iznad\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Insert new rule below\"\nmsgstr  \"Umetni novo pravilo ispod\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid   \"Paste here\"\nmsgstr  \"Zalijepi ovdje\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid   \"Paste above\"\nmsgstr  \"Zalijepi iznad\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid   \"Paste below\"\nmsgstr  \"Zalijepi ispod\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid   \"Paste rule here\"\nmsgstr  \"Zalijepi pravilo ovdje\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid   \"Paste rule above\"\nmsgstr  \"Zalijepi pravilo iznad\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Paste rule below\"\nmsgstr  \"Zalijepi pravilo ispod\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid   \"Paste rule\"\nmsgstr  \"Zalijepi pravilo\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid   \"Flatten\"\nmsgstr  \"Poravnaj\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Insert\"\nmsgstr  \"Umetni\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Or\"\nmsgstr  \"Ili\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid   \"And\"\nmsgstr  \"I\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid   \"Condition\"\nmsgstr  \"Stanje\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid   \"Feature\"\nmsgstr  \"Značajka\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid   \"Report\"\nmsgstr  \"Prijavak\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid   \"Process\"\nmsgstr  \"Proces\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid   \"Mouse process\"\nmsgstr  \"Proces miša\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid   \"Modifiers\"\nmsgstr  \"Tipkovnički izmjenjivači\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid   \"Key\"\nmsgstr  \"Ključ\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid   \"KeyIsDown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid   \"Active\"\nmsgstr  \"Aktivan\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid   \"Device\"\nmsgstr  \"Uređaj\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid   \"Setting\"\nmsgstr  \"Postavka\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid   \"Test\"\nmsgstr  \"Test\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid   \"Test bytes\"\nmsgstr  \"Testni bajtovi\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid   \"Mouse Gesture\"\nmsgstr  \"Gesta miša\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid   \"Action\"\nmsgstr  \"Radnja\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid   \"Key press\"\nmsgstr  \"Pritisak tipke\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid   \"Mouse scroll\"\nmsgstr  \"Pomicanje kotačića\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid   \"Mouse click\"\nmsgstr  \"Klik kotačića\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Set\"\nmsgstr  \"Postavka\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid   \"Execute\"\nmsgstr  \"Pokretanje\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Later\"\nmsgstr  \"Odgoda\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Insert new rule\"\nmsgstr  \"Umetni novo pravilo\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid   \"Delete\"\nmsgstr  \"Obriši\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid   \"Negate\"\nmsgstr  \"Negacija\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid   \"Wrap with\"\nmsgstr  \"Umetni iznad\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid   \"Cut\"\nmsgstr  \"Izreži\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid   \"Paste\"\nmsgstr  \"Zalijepi\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid   \"Copy\"\nmsgstr  \"Kopiraj\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"Ovaj uređivač još ne podržava komponentu odabira pravila.\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid   \"Number of seconds to delay.\"\nmsgstr  \"Broj sekundi odgode.\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid   \"Not\"\nmsgstr  \"Ne\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"X11 aktivni proces. Samo za korištenje u X11.\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"X11 proces miša. Samo za korištenje u X11.\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid   \"MouseProcess\"\nmsgstr  \"Proces miša\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"Naziv značajke obrade pravila za pokretanje obavijesti.\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"Prijavi broj obrade pravila za pokretanje obavijesti.\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"Aktivni tipkovnički izmjenjivači. Nije uvijek dostupno u Waylandu.\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid   \"Key down\"\nmsgstr  \"Tipka za dolje\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid   \"Key up\"\nmsgstr  \"Tipka za gore\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"Uvjet testiranja za obradu pravila pokretanja obavijesti.\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid   \"Parameter\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid   \"begin (inclusive)\"\nmsgstr  \"početak (uključiv)\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid   \"end (exclusive)\"\nmsgstr  \"završetak (isključiv)\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid   \"range\"\nmsgstr  \"raspon\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid   \"minimum\"\nmsgstr  \"minimum\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid   \"maximum\"\nmsgstr  \"maksimum\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"bajtovi %(0)d do %(1)d, u rasponu od %(2)d do %(3)d\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid   \"mask\"\nmsgstr  \"maska\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"bajtovi %(0)d to %(1)d, maska %(2)d\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"Test bita ili raspona na bajtovima u poruci obavijesti koja pokreće \"\n        \"obradu pravila.\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid   \"type\"\nmsgstr  \"vrsta\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"Geste mišem s neobaveznom tipkom pokretanja nakon kojeg slijedi nula \"\n        \"ili više pokreta mišem.\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid   \"Add movement\"\nmsgstr  \"Dodaj pokret\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"Simuliraj klik tipke s akordima ili pritisnite ili pustite.\\n\"\n        \"Na Waylandu je potrebna dozvola pisanje u /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid   \"Add key\"\nmsgstr  \"Dodaj tipku\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid   \"Click\"\nmsgstr  \"Klik\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid   \"Depress\"\nmsgstr  \"Pritisak\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid   \"Release\"\nmsgstr  \"Otpuštanje\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"Simuliraj pomicanje kotačića miša.\\n\"\n        \"Na Waylandu je potrebna dozvola pisanje u /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"Simuliraj klik miša.\\n\"\n        \"Na Waylandu je potrebna dozvola pisanje u /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid   \"Button\"\nmsgstr  \"Tipka\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid   \"Count and Action\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"Pokreni naredbu s argumentima.\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid   \"Add argument\"\nmsgstr  \"Dodaj argument\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"Toggle\"\nmsgstr  \"Uklj/Isklj\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"True\"\nmsgstr  \"Istina\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid   \"False\"\nmsgstr  \"Laž\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid   \"Unsupported setting\"\nmsgstr  \"Nepodržana postavka\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid   \"Originating device\"\nmsgstr  \"Izvorni uređaj\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"Uređaj je aktivan i njegove postavke se mogu promijeniti.\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid   \"Name of host computer.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid   \"Value\"\nmsgstr  \"Vrijednost\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid   \"Item\"\nmsgstr  \"Stavka\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid   \"Change setting on device\"\nmsgstr  \"Promjena postavke na uređaju\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid   \"Setting on device\"\nmsgstr  \"Postavka na uređaju\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid   \"offline\"\nmsgstr  \"nespojivo\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"%(receiver_name)s: upari novi uređaj\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"Upišite lozinku na %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"Upišite %(passcode)s i zatim pritisnite Enter tipku.\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"left\"\nmsgstr  \"lijevo\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"right\"\nmsgstr  \"desno\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"Pritisnite %(code)s\\n\"\n        \"i zatim istovremeno pritisnite lijevu i desnu tipku.\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid   \"Pairing failed\"\nmsgstr  \"Neuspjelo uparivanje\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"Pobrinite se da je vaš uređaj u dometu bežičnog povezivanja i da je \"\n        \"dovoljno napunjen.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"Novi uređaj je otkriven, ali nije kompatibilan s ovim uređajem.\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"Postoji više uparenih uređaja nego što prijemnik podržava.\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"Nema dostupnih više pojedinosti o ovoj grešci.\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid   \"Found a new device:\"\nmsgstr  \"Novi uređaj je pronađen:\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"Bežično povezivanje nije šifrirano\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"Pritisnite tipku uparivanja sve dok svjetlo uparivanja ne počne brzo \"\n        \"treptati.\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid   \"You may have to first turn the device off and on again.\"\nmsgstr  \"Možda trebate prvo isključiti uređaj pa ponovno uključiti.\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid   \"Turn on the device you want to pair.\"\nmsgstr  \"Uključite uređaj koji želite upariti.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"Ako je uređaj već uključen, isključite ga i ponovno uključite.\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\\n\"\n        \"\\n\"\n        \"Ovaj prijemnik ima još %d preostalo uparivanje.\"\nmsgstr[1]       \"\\n\"\n        \"\\n\"\n        \"Ovaj prijemnik ima još %d preostala uparivanja.\"\nmsgstr[2]       \"\\n\"\n        \"\\n\"\n        \"Ovaj prijemnik ima još %d preostalih uparivanja.\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\\n\"\n        \"Prekidanje u ovom trenutku neće izvršiti uparivanje.\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid   \"No supported device found\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"O %su\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"Zatvori %s\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid   \"no receiver\"\nmsgstr  \"nema prijemnika\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid   \"no status\"\nmsgstr  \"bez stanja\"\n\n#: lib/solaar/ui/window.py:96\nmsgid   \"Scanning\"\nmsgstr  \"Pretraživanje\"\n\n#: lib/solaar/ui/window.py:129\nmsgid   \"Battery\"\nmsgstr  \"Baterija\"\n\n#: lib/solaar/ui/window.py:132\nmsgid   \"Wireless Link\"\nmsgstr  \"Bežično povezivanje\"\n\n#: lib/solaar/ui/window.py:136\nmsgid   \"Lighting\"\nmsgstr  \"Osvjetljenje\"\n\n#: lib/solaar/ui/window.py:170\nmsgid   \"Show Technical Details\"\nmsgstr  \"Prikaži tehničke pojedinosti\"\n\n#: lib/solaar/ui/window.py:186\nmsgid   \"Pair new device\"\nmsgstr  \"Upari novi uređaj\"\n\n#: lib/solaar/ui/window.py:205\nmsgid   \"Select a device\"\nmsgstr  \"Odaberi uređaj\"\n\n#: lib/solaar/ui/window.py:322\nmsgid   \"Rule Editor\"\nmsgstr  \"Uređivač pravila\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Path\"\nmsgstr  \"Putanja\"\n\n#: lib/solaar/ui/window.py:536\nmsgid   \"USB ID\"\nmsgstr  \"USB ID\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid   \"Serial\"\nmsgstr  \"Serijski broj\"\n\n#: lib/solaar/ui/window.py:545\nmsgid   \"Index\"\nmsgstr  \"Indeks\"\n\n#: lib/solaar/ui/window.py:547\nmsgid   \"Wireless PID\"\nmsgstr  \"PID bežične mreže\"\n\n#: lib/solaar/ui/window.py:549\nmsgid   \"Product ID\"\nmsgstr  \"ID proizvoda\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Protocol\"\nmsgstr  \"Protokol\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Unknown\"\nmsgstr  \"Nepoznato\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid   \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr  \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#: lib/solaar/ui/window.py:554\nmsgid   \"Polling rate\"\nmsgstr  \"Cikličko osvježavanje\"\n\n#: lib/solaar/ui/window.py:565\nmsgid   \"Unit ID\"\nmsgstr  \"ID jedinice\"\n\n#: lib/solaar/ui/window.py:576\nmsgid   \"none\"\nmsgstr  \"nepoznato\"\n\n#: lib/solaar/ui/window.py:577\nmsgid   \"Notifications\"\nmsgstr  \"Obavijesti\"\n\n#: lib/solaar/ui/window.py:621\nmsgid   \"No device paired.\"\nmsgstr  \"Nema uparenih uređaja.\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"Najviše %(max_count)s uređaj može biti uparen s ovim \"\n        \"prijemnikom.\"\nmsgstr[1]       \"Najviše %(max_count)s uređaja može biti upareno s ovim \"\n        \"prijemnikom.\"\nmsgstr[2]       \"Najviše %(max_count)s uređaja može biti upareno s ovim \"\n        \"prijemnikom.\"\n\n#: lib/solaar/ui/window.py:634\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"Samo jedan uređaj može biti uparen s ovim prijemnikom.\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"Ovaj prijemnik ima još %d preostalo uparivanje.\"\nmsgstr[1]       \"Ovaj prijemnik ima još %d preostala uparivanja.\"\nmsgstr[2]       \"Ovaj prijemnik ima još %d preostalih uparivanja.\"\n\n#: lib/solaar/ui/window.py:692\nmsgid   \"Battery Voltage\"\nmsgstr  \"Napon baterije\"\n\n#: lib/solaar/ui/window.py:694\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"Napon prijavljen od strane baterije\"\n\n#: lib/solaar/ui/window.py:696\nmsgid   \"Battery Level\"\nmsgstr  \"Razina baterije\"\n\n#: lib/solaar/ui/window.py:698\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"Približna razina prijavljena od strane baterije\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid   \"next reported \"\nmsgstr  \"sljedeće poznato \"\n\n#: lib/solaar/ui/window.py:708\nmsgid   \" and next level to be reported.\"\nmsgstr  \" i sljedeća razina za prijaviti.\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"last known\"\nmsgstr  \"posljednje poznato\"\n\n#: lib/solaar/ui/window.py:724\nmsgid   \"encrypted\"\nmsgstr  \"šifrirano\"\n\n#: lib/solaar/ui/window.py:726\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"Bežično povezivanje između ovog uređaja i njegovog prijemnika je \"\n        \"šifrirano.\"\n\n#: lib/solaar/ui/window.py:728\nmsgid   \"not encrypted\"\nmsgstr  \"nije šifrirano\"\n\n#: lib/solaar/ui/window.py:732\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"Bežično povezivanje između ovog uređaja i njegovog prijemnika nije \"\n        \"šifrirano.\\n\"\n        \"Ovo je sigurnosni problem za pokazivačke uređaje i veliki sigurnosni \"\n        \"problem za uređaje za unos teksta.\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"%(light_level)d lux\"\n\n#~ msgid        \" paired devices.\"\n#~ msgstr       \" uparena uređaja.\"\n\n#~ msgid        \"%(battery_level)s\"\n#~ msgstr       \"%(battery_level)s\"\n\n#~ msgid        \"%(battery_percent)d%%\"\n#~ msgstr       \"%(battery_percent)d%%\"\n\n#~ msgid        \"1 paired device.\"\n#~ msgstr       \"1 upareni uređaj.\"\n\n#~ msgid        \"Actions\"\n#~ msgstr       \"Radnje\"\n\n#~ msgid        \"Add action\"\n#~ msgstr       \"Dodaj radnju\"\n\n#~ msgid        \"Adjust the DPI by sliding the mouse horizontally while \"\n#~      \"holding the button down.\"\n#~ msgstr       \"Prilagodite DPI pomicanjem miša vodoravno držeći pritisnutu \"\n#~      \"tipku.\"\n\n#~ msgid        \"Automatically switch the mouse wheel between ratchet and \"\n#~      \"freespin mode.\\n\"\n#~      \"The mouse wheel is always free at 0, and always locked at 50\"\n#~ msgstr       \"Automatski prebaci kotačić miša između ustavljačkog i \"\n#~      \"slobodnog načina vrtnje kotačića.\\n\"\n#~      \"Kotačić miša je uvijek slobodan pri 0 i uvijek zaključan pri 50\"\n\n#~ msgid        \"Automatically switch the mouse wheel between ratchet and \"\n#~      \"freespin mode.\\n\"\n#~      \"The mouse wheel is always free at 0, and always ratcheted at 50\"\n#~ msgstr       \"Automatski prebaci kotačić miša između ustavljačkog i \"\n#~      \"slobodnog načina vrtnje kotačića.\\n\"\n#~      \"Kotačić miša je uvijek slobodan pri 0 i uvijek zaključan pri 50\"\n\n#~ msgid        \"Battery information unknown.\"\n#~ msgstr       \"Informacije baterije nepoznate.\"\n\n#~ msgid        \"Count\"\n#~ msgstr       \"Brojač\"\n\n#~ msgid        \"DPI Sliding Adjustment\"\n#~ msgstr       \"Prilagodba DPI pomicanjem\"\n\n#~ msgid        \"Diverted key or button depressed or released.\\n\"\n#~      \"Use the Key/Button Diversion setting to divert keys and buttons.\"\n#~ msgstr       \"Preusmjerena tipka pritisnuta ili otpuštena.\\n\"\n#~      \"Koristite postavku Preusmjeravanje tipke za preusmjeravanje tipki.\"\n\n#~ msgid        \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr       \"Učinkovito isključuje pomicanje palcem u Linuxu.\"\n\n#~ msgid        \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr       \"Učinkovito isključuje pomicanje kotačića u Linuxu.\"\n\n#~ msgid        \"For more information see the Solaar installation directions\\n\"\n#~      \"at https://pwr-solaar.github.io/Solaar/installation\"\n#~ msgstr       \"Za više informacija pogledajte upute Solaar instalacije\\n\"\n#~      \"na https://pwr-solaar.github.io/Solaar/installation\"\n\n#, python-format\n#~ msgid        \"Found a Logitech Receiver (%s), but did not have permission \"\n#~      \"to open it.\"\n#~ msgstr       \"Pronađen je (%s) Logitech Receiver, ali nemate ovlasti za \"\n#~      \"otvoriti ga.\"\n\n#~ msgid        \"HID++ Scrolling\"\n#~ msgstr       \"HID++ Scrolling\"\n\n#~ msgid        \"HID++ Thumb Scrolling\"\n#~ msgstr       \"HID++ pomicanje palcem\"\n\n#~ msgid        \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr       \"HID++ način rada za okomito pomicanje kotačića palca.\"\n\n#~ msgid        \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr       \"HID++ način rada za okomito pomicanje kotačića.\"\n\n#~ msgid        \"High Resolution Scrolling\"\n#~ msgstr       \"Pomicanje kotačićem visoke razlučivosti\"\n\n#~ msgid        \"High Resolution Wheel Invert\"\n#~ msgstr       \"Obrnuto pomicanje kotačićem visoke razlučivosti\"\n\n#~ msgid        \"High-sensitivity wheel invert direction for vertical scroll.\"\n#~ msgstr       \"Obrnuti visoko osjetljivi smjer kotačića za okomito \"\n#~      \"pomicanje.\"\n\n#~ msgid        \"If the device is already turned on,\\n\"\n#~      \"turn if off and on again.\"\n#~ msgstr       \"Ako je uređaj već uključen,\\n\"\n#~      \"isključite ga i ponovno uključite.\"\n\n#~ msgid        \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr       \"Ako je uređaj već uključen, isključite ga i ponovno \"\n#~      \"uključite.\"\n\n#~ msgid        \"If you've just installed Solaar, try removing the receiver \"\n#~      \"and plugging it back in.\"\n#~ msgstr       \"Ako ste upravo instalirali Solaar, pokušajte odspojiti \"\n#~      \"prijemnik i ponovno ga spojiti.\"\n\n#~ msgid        \"Invert thumb scroll direction.\"\n#~ msgstr       \"Obrnuti smjer pomicanja kotačića palca.\"\n\n#~ msgid        \"Make the key or button send HID++ notifications (which \"\n#~      \"trigger Solaar rules but are otherwise ignored).\"\n#~ msgstr       \"Neka tipka šalje HID++ obavijesti (što pokreće Solaar \"\n#~      \"pravila, u suprotnome ih zanemaruje).\"\n\n#~ msgid        \"No Logitech device found\"\n#~ msgstr       \"Nema pronađenih Logitechovih uređaja\"\n\n#~ msgid        \"Scroll Wheel Rachet\"\n#~ msgstr       \"Ustavljanje pomicanja kotačića\"\n\n#~ msgid        \"Send a gesture by sliding the mouse while holding the button \"\n#~      \"down.\"\n#~ msgstr       \"Prilagodite geste pomicanjem miša držeći pritisnutu tipku.\"\n\n#~ msgid        \"Shows status of devices connected\\n\"\n#~      \"through wireless Logitech receivers.\"\n#~ msgstr       \"Prikazuje stanje uređaja povezanih\\n\"\n#~      \"putem Logitech bežičnih prijemnika.\"\n\n#~ msgid        \"Solaar depends on a udev file that is not present\"\n#~ msgstr       \"Solaar ovisi o udev datoteci koja nije prisutna\"\n\n#~ msgid        \"The receiver only supports %d paired device(s).\"\n#~ msgstr       \"Prijemnik samo podržava %d upareni uređaj(e).\"\n\n#~ msgid        \"The receiver was unplugged.\"\n#~ msgstr       \"Prijemnik je odspojen.\"\n\n#~ msgid        \"The wireless link between this device and its receiver is \"\n#~      \"not encrypted.\\n\"\n#~      \"\\n\"\n#~      \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~      \"security issue.\\n\"\n#~      \"\\n\"\n#~      \"It is, however, a major security issue for text-input devices \"\n#~      \"(keyboards, numpads),\\n\"\n#~      \"because typed text can be sniffed inconspicuously by 3rd parties \"\n#~      \"within range.\"\n#~ msgstr       \"Bežično povezivanje između ovog uređaja i njegovog \"\n#~      \"prijemnika nije šifrirano.\\n\"\n#~      \"\\n\"\n#~      \"Za uređaje s pokazivačem (miš, trackballs, trackpads), to je manji \"\n#~      \"sigurnosni problem.\\n\"\n#~      \"\\n\"\n#~      \"A za uređaje za unos teksta, je veći sigurnosni problem (tipkovnice, \"\n#~      \"numpads),\\n\"\n#~      \"zato jer upisani tekst može biti neprimjentno nadziran u dometu \"\n#~      \"treće strane.\"\n\n#~ msgid        \"Thumb Scroll Invert\"\n#~ msgstr       \"Obrnuto pomicanje kotačića palca\"\n\n#~ msgid        \"Try removing the device and plugging it back in or turning \"\n#~      \"it off and then on.\"\n#~ msgstr       \"Pokušajte uređaj ukloniti pa ponovno priključiti s računalom \"\n#~      \"ili ga isključiti pa ponovno uključiti.\"\n\n#~ msgid        \"USB id\"\n#~ msgstr       \"USB id\"\n\n#~ msgid        \"Wheel Resolution\"\n#~ msgstr       \"Pomicanje kotačićem\"\n\n#~ msgid        \"closed\"\n#~ msgstr       \"završeno\"\n\n#~ msgid        \"lux\"\n#~ msgstr       \"lux\"\n\n#~ msgid        \"next \"\n#~ msgstr       \"sljedeće \"\n\n#~ msgid        \"open\"\n#~ msgstr       \"pokrenuto\"\n\n#~ msgid        \"paired devices\"\n#~ msgstr       \"upareni uređaji\"\n\n#~ msgid        \"unknown\"\n#~ msgstr       \"nepoznato\"\n"
  },
  {
    "path": "po/id.po",
    "content": "# Indonesian translations for solaar package.\n# Copyright (C) 2024 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Ferdina kusumah <ferdina.kusumah@gmail.com>, 2024.\n#\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 1.1.11\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2024-03-14 13:11+0700\\n\"\n        \"PO-Revision-Date: 2024-03-14 09:00+0700\\n\"\n        \"Last-Translator: Ferdina Kusumah <ferdina.kusumah@gmail.com>\\n\"\n        \"Language-Team: none\\n\"\n        \"Language: id\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=1; plural=0;\\n\"\n        \"X-Generator: Poedit 3.0\\n\"\n\n#: lib/logitech_receiver/base_usb.py:45\nmsgid   \"Bolt Receiver\"\nmsgstr  \"Reseptor bolt\"\n\n#: lib/logitech_receiver/base_usb.py:58\nmsgid   \"Unifying Receiver\"\nmsgstr  \"Reseptor unifying\"\n\n#: lib/logitech_receiver/base_usb.py:70 lib/logitech_receiver/base_usb.py:83\n#: lib/logitech_receiver/base_usb.py:97 lib/logitech_receiver/base_usb.py:111\n#: lib/logitech_receiver/base_usb.py:125\nmsgid   \"Nano Receiver\"\nmsgstr  \"Reseptor nano\"\n\n#: lib/logitech_receiver/base_usb.py:138\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"Reseptor lightspeed\"\n\n#: lib/logitech_receiver/base_usb.py:149\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"Reseptor EX100 27 Mhz\"\n\n#: lib/logitech_receiver/common.py:604\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"Baterai: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:606\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"Baterai: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:926\n#: lib/logitech_receiver/settings_templates.py:291\nmsgid   \"Disabled\"\nmsgstr  \"Dinonaktifkan\"\n\n#: lib/logitech_receiver/hidpp20.py:927\nmsgid   \"Static\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:928\nmsgid   \"Pulse\"\nmsgstr  \"Pulsa\"\n\n#: lib/logitech_receiver/hidpp20.py:929\nmsgid   \"Cycle\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:930\nmsgid   \"Boot\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:931\nmsgid   \"Demo\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:932\nmsgid   \"Breathe\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:933\nmsgid   \"Ripple\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:994\nmsgid   \"Unknown Location\"\nmsgstr  \"Lokasi tidak ditemukan\"\n\n#: lib/logitech_receiver/hidpp20.py:995\nmsgid   \"Primary\"\nmsgstr  \"Utama\"\n\n#: lib/logitech_receiver/hidpp20.py:996\nmsgid   \"Logo\"\nmsgstr  \"Logo\"\n\n#: lib/logitech_receiver/hidpp20.py:997\nmsgid   \"Left Side\"\nmsgstr  \"Sisi kiri\"\n\n#: lib/logitech_receiver/hidpp20.py:998\nmsgid   \"Right Side\"\nmsgstr  \"Sisi kanan\"\n\n#: lib/logitech_receiver/hidpp20.py:999\nmsgid   \"Combined\"\nmsgstr  \"Kombinasi\"\n\n#: lib/logitech_receiver/hidpp20.py:1000\nmsgid   \"Primary 1\"\nmsgstr  \"Utama 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1001\nmsgid   \"Primary 2\"\nmsgstr  \"Utama 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1002\nmsgid   \"Primary 3\"\nmsgstr  \"Utama 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1003\nmsgid   \"Primary 4\"\nmsgstr  \"Utama 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1004\nmsgid   \"Primary 5\"\nmsgstr  \"Utama 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1005\nmsgid   \"Primary 6\"\nmsgstr  \"Utama 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid   \"empty\"\nmsgstr  \"habis\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid   \"critical\"\nmsgstr  \"hampir habis\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"low\"\nmsgstr  \"rendah\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"average\"\nmsgstr  \"setengah\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"good\"\nmsgstr  \"baik\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"full\"\nmsgstr  \"penuh\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"discharging\"\nmsgstr  \"pemakaian\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid   \"recharging\"\nmsgstr  \"pengisian ulang\"\n\n#: lib/logitech_receiver/i18n.py:37\nmsgid   \"charging\"\nmsgstr  \"pengisian daya\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"not charging\"\nmsgstr  \"tidak mengisi daya\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"almost full\"\nmsgstr  \"hampir penuh\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid   \"charged\"\nmsgstr  \"mengisi\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"slow recharge\"\nmsgstr  \"pengisian lambat\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"invalid battery\"\nmsgstr  \"baterai tidak valid\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"thermal error\"\nmsgstr  \"kesalahan termal\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"error\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"standard\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"fast\"\nmsgstr  \"cepat\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"slow\"\nmsgstr  \"lambat\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"device timeout\"\nmsgstr  \"batas waktu perangkat habis\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"device not supported\"\nmsgstr  \"perangkat tidak didukung\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid   \"too many devices\"\nmsgstr  \"terlalu banyak perangkat\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid   \"sequence timeout\"\nmsgstr  \"batas waktu urutan habis\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid   \"Firmware\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"Bootloader\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"Hardware\"\nmsgstr  \"Perangkat keras\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid   \"Other\"\nmsgstr  \"Lainnya\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid   \"Left Button\"\nmsgstr  \"Tombol Kiri\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Right Button\"\nmsgstr  \"Tombol Kanan\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Middle Button\"\nmsgstr  \"Tombol Tengah\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Back Button\"\nmsgstr  \"Tombol kembali\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid   \"Forward Button\"\nmsgstr  \"Tombol Depan\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"Tombol Gerakan Mouse\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Smart Shift\"\nmsgstr  \"Pergeseran Cerdas\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"DPI Switch\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Left Tilt\"\nmsgstr  \"Kemiringan Kiri\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Right Tilt\"\nmsgstr  \"Kemiringan Kanan\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Left Click\"\nmsgstr  \"Klik Kiri\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Right Click\"\nmsgstr  \"Klik Kanan\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"Tombol Tengah Mouse\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"Mouse Back Button\"\nmsgstr  \"Tombol Kembali Mouse\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"Tombol Depan Mouse\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"Navigasi Tombol Gerakan\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"Tombol Gulir Kiri Mouse\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"Tombol Gulir Kanan Mouse\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"pressed\"\nmsgstr  \"ditekan\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"released\"\nmsgstr  \"dilepaskan\"\n\n#: lib/logitech_receiver/notifications.py:63\n#: lib/logitech_receiver/notifications.py:115\nmsgid   \"pairing lock is closed\"\nmsgstr  \"kunci penyandingan ditutup\"\n\n#: lib/logitech_receiver/notifications.py:63\n#: lib/logitech_receiver/notifications.py:115\nmsgid   \"pairing lock is open\"\nmsgstr  \"kunci penyandingan terbuka\"\n\n#: lib/logitech_receiver/notifications.py:80\nmsgid   \"discovery lock is closed\"\nmsgstr  \"kunci penemuan ditutup\"\n\n#: lib/logitech_receiver/notifications.py:80\nmsgid   \"discovery lock is open\"\nmsgstr  \"kunci penemuan terbuka\"\n\n#: lib/logitech_receiver/notifications.py:207\nmsgid   \"connected\"\nmsgstr  \"terhubung\"\n\n#: lib/logitech_receiver/notifications.py:207\nmsgid   \"disconnected\"\nmsgstr  \"terputus\"\n\n#: lib/logitech_receiver/notifications.py:233\nmsgid   \"unpaired\"\nmsgstr  \"tidak berpasangan\"\n\n#: lib/logitech_receiver/notifications.py:280\nmsgid   \"powered on\"\nmsgstr  \"dihidupkan\"\n\n#: lib/logitech_receiver/receiver.py:345\nmsgid   \"No paired devices.\"\nmsgstr  \"Tidak ada perangkat yang dipasangkan\"\n\n#: lib/logitech_receiver/receiver.py:347 lib/solaar/ui/window.py:630\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"%(count)s perangkat yang dipasangkan.\"\n\n#: lib/logitech_receiver/settings.py:617\nmsgid   \"register\"\nmsgstr  \"daftar\"\n\n#: lib/logitech_receiver/settings.py:631 lib/logitech_receiver/settings.py:658\nmsgid   \"feature\"\nmsgstr  \"fitur\"\n\n#: lib/logitech_receiver/settings_templates.py:144\nmsgid   \"Swap Fx function\"\nmsgstr  \"Tukar fungsi Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:147\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"Jika disetel, tombol F1..F12 akan mengaktifkan fungsi khususnya,\\n\"\n        \"dan Anda harus menahan tombol FN untuk mengaktifkan fungsi \"\n        \"standarnya.\"\n\n#: lib/logitech_receiver/settings_templates.py:152\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"Jika tidak disetel, tombol F1..F12 akan mengaktifkan fungsi \"\n        \"standarnya,\\n\"\n        \"dan Anda harus menahan tombol FN untuk mengaktifkan fungsi khususnya.\"\n\n#: lib/logitech_receiver/settings_templates.py:160\nmsgid   \"Hand Detection\"\nmsgstr  \"Deteksi Tangan\"\n\n#: lib/logitech_receiver/settings_templates.py:161\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"Nyalakan penerangan saat tangan melayang di atas keyboard.\"\n\n#: lib/logitech_receiver/settings_templates.py:168\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"Roda Gulir Pengguliran Halus\"\n\n#: lib/logitech_receiver/settings_templates.py:169\n#: lib/logitech_receiver/settings_templates.py:402\n#: lib/logitech_receiver/settings_templates.py:431\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"Mode sensitivitas tinggi untuk gulir vertikal dengan roda.\"\n\n#: lib/logitech_receiver/settings_templates.py:176\nmsgid   \"Side Scrolling\"\nmsgstr  \"Menggulir Sisi\"\n\n#: lib/logitech_receiver/settings_templates.py:178\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"Saat dinonaktifkan, mendorong roda ke samping akan mengirimkan \"\n        \"tombol khususacara\\n\"\n        \"bukannya acara side-scrolling standar.\"\n\n#: lib/logitech_receiver/settings_templates.py:188\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"Sensitivitas (DPI - older mouse)\"\n\n#: lib/logitech_receiver/settings_templates.py:189\n#: lib/logitech_receiver/settings_templates.py:958\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"Sensitivitas gerakan mouse\"\n\n#: lib/logitech_receiver/settings_templates.py:249\n#: lib/logitech_receiver/settings_templates.py:261\n#: lib/logitech_receiver/settings_templates.py:388\nmsgid   \"Backlight\"\nmsgstr  \"Lampu latar\"\n\n#: lib/logitech_receiver/settings_templates.py:250\n#: lib/logitech_receiver/settings_templates.py:389\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"Atur waktu penerangan untuk keyboard.\"\n\n#: lib/logitech_receiver/settings_templates.py:262\nmsgid   \"Illumination level on keyboard.  Changes made are only applied in \"\n        \"Manual mode.\"\nmsgstr  \"Tingkat penerangan pada keyboard. Perubahan yang dilakukan hanya \"\n        \"diterapkan di Mode manual.\"\n\n#: lib/logitech_receiver/settings_templates.py:293\nmsgid   \"Automatic\"\nmsgstr  \"Otomatis\"\n\n#: lib/logitech_receiver/settings_templates.py:295\nmsgid   \"Manual\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:297\nmsgid   \"Enabled\"\nmsgstr  \"Difungsikan\"\n\n#: lib/logitech_receiver/settings_templates.py:303\nmsgid   \"Backlight Level\"\nmsgstr  \"Tingkat Lampu Latar\"\n\n#: lib/logitech_receiver/settings_templates.py:304\nmsgid   \"Illumination level on keyboard when in Manual mode.\"\nmsgstr  \"Tingkat penerangan pada keyboard saat dalam mode Manual.\"\n\n#: lib/logitech_receiver/settings_templates.py:361\nmsgid   \"Backlight Delay Hands Out\"\nmsgstr  \"Penundaan Lampu Latar Hands Out\"\n\n#: lib/logitech_receiver/settings_templates.py:362\nmsgid   \"Delay in seconds until backlight fades out with hands away from \"\n        \"keyboard.\"\nmsgstr  \"Tunda dalam hitungan detik hingga cahaya latar memudar dengan tangan \"\n        \"menjauhipapan ketik.\"\n\n#: lib/logitech_receiver/settings_templates.py:370\nmsgid   \"Backlight Delay Hands In\"\nmsgstr  \"Penundaan Lampu Latar Masuk\"\n\n#: lib/logitech_receiver/settings_templates.py:371\nmsgid   \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr  \"Tunda dalam hitungan detik hingga lampu latar memudar dengan tangan \"\n        \"di dekat keyboard.\"\n\n#: lib/logitech_receiver/settings_templates.py:379\nmsgid   \"Backlight Delay Powered\"\nmsgstr  \"Penundaan Lampu Latar Didukung\"\n\n#: lib/logitech_receiver/settings_templates.py:380\nmsgid   \"Delay in seconds until backlight fades out with external power.\"\nmsgstr  \"Penundaan dalam hitungan detik hingga lampu latar memudar dengan \"\n        \"daya eksternal.\"\n\n#: lib/logitech_receiver/settings_templates.py:400\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"Resolusi Tinggi Scroll Wheel\"\n\n#: lib/logitech_receiver/settings_templates.py:404\n#: lib/logitech_receiver/settings_templates.py:433\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"Setel ke abaikan jika pengguliran terlalu cepat atau lambat\"\n\n#: lib/logitech_receiver/settings_templates.py:411\n#: lib/logitech_receiver/settings_templates.py:442\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"Pengalihan Scroll Wheel\"\n\n#: lib/logitech_receiver/settings_templates.py:413\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"Buat roda gulir mengirimkan notifikasi LOWRES_WHEEL HID++ (yang mana \"\n        \"memicu aturan Solaar tetapi sebaliknya diabaikan).\"\n\n#: lib/logitech_receiver/settings_templates.py:420\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"Arah Scroll Wheel\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"Balikkan arah untuk gulir vertikal scroll with wheel.\"\n\n#: lib/logitech_receiver/settings_templates.py:429\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"Resolusi Scroll Wheel\"\n\n#: lib/logitech_receiver/settings_templates.py:444\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"Buat roda gulir mengirimkan notifikasi HIRES_WHEEL HID++ (yang mana \"\n        \"memicu aturan Solaar tetapi sebaliknya diabaikan).\"\n\n#: lib/logitech_receiver/settings_templates.py:453\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"Sensitivitas (Kecepatan Pointer)\"\n\n#: lib/logitech_receiver/settings_templates.py:454\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"Pengganda kecepatan untuk mouse (256 adalah pengganda normal).\"\n\n#: lib/logitech_receiver/settings_templates.py:464\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"Pengalihan Roda Jempol\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"Buat roda jempol mengirimkan notifikasi THUMB_WHEEL HID++ (yang \"\n        \"memicuPeraturan Solar tetapi sebaliknya diabaikan).\"\n\n#: lib/logitech_receiver/settings_templates.py:475\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"Arah Roda Ibu Jari\"\n\n#: lib/logitech_receiver/settings_templates.py:476\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"Balikkan arah gulir roda ibu jari.\"\n\n#: lib/logitech_receiver/settings_templates.py:496\nmsgid   \"Onboard Profiles\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:497\nmsgid   \"Enable an onboard profile, which controls report rate, sensitivity, \"\n        \"and button actions\"\nmsgstr  \"Aktifkan profil onboard, yang mengontrol kecepatan laporan, \"\n        \"sensitivitas, dan tindakan tombol\"\n\n#: lib/logitech_receiver/settings_templates.py:541\n#: lib/logitech_receiver/settings_templates.py:581\nmsgid   \"Report Rate\"\nmsgstr  \"Tingkat Laporan\"\n\n#: lib/logitech_receiver/settings_templates.py:543\n#: lib/logitech_receiver/settings_templates.py:583\nmsgid   \"Frequency of device movement reports\"\nmsgstr  \"Frekuensi laporan pergerakan perangkat\"\n\n#: lib/logitech_receiver/settings_templates.py:543\n#: lib/logitech_receiver/settings_templates.py:583\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1326\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"Mungkin perlu Profil Onboard diatur ke Nonaktifkan agar efektif.\"\n\n#: lib/logitech_receiver/settings_templates.py:623\nmsgid   \"Divert crown events\"\nmsgstr  \"Alihkan acara mahkota\"\n\n#: lib/logitech_receiver/settings_templates.py:624\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Buat mahkota mengirimkan notifikasi CROWN HID++ (yang memicu \"\n        \"Solaarperaturan tetapi sebaliknya diabaikan).\"\n\n#: lib/logitech_receiver/settings_templates.py:632\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"Gulir halus mahkota\"\n\n#: lib/logitech_receiver/settings_templates.py:633\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"Setel mahkota gulir halus\"\n\n#: lib/logitech_receiver/settings_templates.py:641\nmsgid   \"Divert G and M Keys\"\nmsgstr  \"Alihkan Tombol G dan M\"\n\n#: lib/logitech_receiver/settings_templates.py:642\nmsgid   \"Make G and M keys send HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Buat kunci G dan M mengirimkan notifikasi HID++ (yang memicu \"\n        \"Solaarperaturan tetapi sebaliknya diabaikan).\"\n\n#: lib/logitech_receiver/settings_templates.py:656\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"Roda Gulir Bergerigi\"\n\n#: lib/logitech_receiver/settings_templates.py:657\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"Ganti roda mouse antara ratcheting yang dikontrol kecepatan dan \"\n        \"selalu berputar bebas.\"\n\n#: lib/logitech_receiver/settings_templates.py:659\nmsgid   \"Freespinning\"\nmsgstr  \"Putar bebas\"\n\n#: lib/logitech_receiver/settings_templates.py:659\nmsgid   \"Ratcheted\"\nmsgstr  \"Digeser\"\n\n#: lib/logitech_receiver/settings_templates.py:666\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"Kecepatan Ratchet Roda Gulir\"\n\n#: lib/logitech_receiver/settings_templates.py:668\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"Gunakan kecepatan roda mouse untuk beralih antara ratcheted dan \"\n        \"berputar bebas.\\n\"\n        \"Roda tikus selalu diputar pada kecepatan 50.\"\n\n#: lib/logitech_receiver/settings_templates.py:717\nmsgid   \"Key/Button Actions\"\nmsgstr  \"Tindakan Kunci/Tombol\"\n\n#: lib/logitech_receiver/settings_templates.py:719\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"Ubah tindakan untuk kunci atau tombol tersebut.\"\n\n#: lib/logitech_receiver/settings_templates.py:721\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"Ditimpa oleh pengalihan.\"\n\n#: lib/logitech_receiver/settings_templates.py:723\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"Mengubah tindakan penting (misalnya tombol kiri mouse) dapat \"\n        \"menghasilkan sistem yang tidak dapat digunakan.\"\n\n#: lib/logitech_receiver/settings_templates.py:886\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"Pengalihan Kunci/Tombol\"\n\n#: lib/logitech_receiver/settings_templates.py:887\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"Buat kunci atau tombol mengirimkan notifikasi HID++ (Dialihkan) \"\n        \"ataumemulai Gerakan Mouse atau DPI Geser\"\n\n#: lib/logitech_receiver/settings_templates.py:890\n#: lib/logitech_receiver/settings_templates.py:891\n#: lib/logitech_receiver/settings_templates.py:892\nmsgid   \"Diverted\"\nmsgstr  \"Dialihkan\"\n\n#: lib/logitech_receiver/settings_templates.py:890\n#: lib/logitech_receiver/settings_templates.py:891\nmsgid   \"Mouse Gestures\"\nmsgstr  \"Gerakan Mouse\"\n\n#: lib/logitech_receiver/settings_templates.py:890\n#: lib/logitech_receiver/settings_templates.py:891\n#: lib/logitech_receiver/settings_templates.py:892\nmsgid   \"Regular\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:890\nmsgid   \"Sliding DPI\"\nmsgstr  \"DPI geser\"\n\n#: lib/logitech_receiver/settings_templates.py:957\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"Sensitivitas (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:997\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"Peralihan Sensitivitas\"\n\n#: lib/logitech_receiver/settings_templates.py:999\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"Ganti sensitivitas saat ini dan sensitivitas yang diingat ketika \"\n        \"tombol atau tombol ditekan.\\n\"\n        \"Jika tidak ada kepekaan yang diingat, ingat saja arusnyakepekaan\"\n\n#: lib/logitech_receiver/settings_templates.py:1003\nmsgid   \"Off\"\nmsgstr  \"Mati\"\n\n#: lib/logitech_receiver/settings_templates.py:1034\nmsgid   \"Disable keys\"\nmsgstr  \"Nonaktifkan kunci\"\n\n#: lib/logitech_receiver/settings_templates.py:1035\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"Nonaktifkan tombol keyboard tertentu.\"\n\n#: lib/logitech_receiver/settings_templates.py:1038\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"Menonaktifkan kunci %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1051\n#: lib/logitech_receiver/settings_templates.py:1108\nmsgid   \"Set OS\"\nmsgstr  \"Atur OS\"\n\n#: lib/logitech_receiver/settings_templates.py:1052\n#: lib/logitech_receiver/settings_templates.py:1109\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"Ubah kunci agar sesuai dengan OS.\"\n\n#: lib/logitech_receiver/settings_templates.py:1121\nmsgid   \"Change Host\"\nmsgstr  \"Ganti Host\"\n\n#: lib/logitech_receiver/settings_templates.py:1122\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"Alihkan koneksi ke host lain\"\n\n#: lib/logitech_receiver/settings_templates.py:1146\nmsgid   \"Performs a left click.\"\nmsgstr  \"Melakukan klik kiri.\"\n\n#: lib/logitech_receiver/settings_templates.py:1146\nmsgid   \"Single tap\"\nmsgstr  \"Ketuk sekali\"\n\n#: lib/logitech_receiver/settings_templates.py:1147\nmsgid   \"Performs a right click.\"\nmsgstr  \"Melakukan klik kanan.\"\n\n#: lib/logitech_receiver/settings_templates.py:1147\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"Ketuk satu kali dengan dua jari\"\n\n#: lib/logitech_receiver/settings_templates.py:1148\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"Ketuk satu kali dengan tiga jari\"\n\n#: lib/logitech_receiver/settings_templates.py:1152\nmsgid   \"Double tap\"\nmsgstr  \"Ketuk dua kali\"\n\n#: lib/logitech_receiver/settings_templates.py:1152\nmsgid   \"Performs a double click.\"\nmsgstr  \"Melakukan klik dua kali.\"\n\n#: lib/logitech_receiver/settings_templates.py:1153\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"Ketuk dua kali dengan dua jari\"\n\n#: lib/logitech_receiver/settings_templates.py:1154\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"Ketuk dua kali dengan tiga jari\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"Menyeret item dengan menyeret jari setelah mengetuk dua kali.\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Tap and drag\"\nmsgstr  \"Ketuk dan seret\"\n\n#: lib/logitech_receiver/settings_templates.py:1159\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"Ketuk dan seret dengan dua jari\"\n\n#: lib/logitech_receiver/settings_templates.py:1160\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"Menyeret item dengan menyeret jari setelah mengetuk dua kali.\"\n\n#: lib/logitech_receiver/settings_templates.py:1162\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"Ketuk dan seret dengan tiga jari\"\n\n#: lib/logitech_receiver/settings_templates.py:1165\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"Menekan gerakan ketuk dan tepi\"\n\n#: lib/logitech_receiver/settings_templates.py:1166\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"Menonaktifkan gerakan ketuk dan tepi (setara dengan menekan Fn+Klik \"\n        \"Kiri).\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid   \"Scroll with one finger\"\nmsgstr  \"Gulir dengan satu jari\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\n#: lib/logitech_receiver/settings_templates.py:1169\n#: lib/logitech_receiver/settings_templates.py:1172\nmsgid   \"Scrolls.\"\nmsgstr  \"Penggulir\"\n\n#: lib/logitech_receiver/settings_templates.py:1169\n#: lib/logitech_receiver/settings_templates.py:1172\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"Gulir dengan dua jari\"\n\n#: lib/logitech_receiver/settings_templates.py:1170\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"Gulir secara horizontal dengan dua jari\"\n\n#: lib/logitech_receiver/settings_templates.py:1170\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"Menggulir secara horizontal.\"\n\n#: lib/logitech_receiver/settings_templates.py:1171\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"Gulir secara vertikal dengan dua jari\"\n\n#: lib/logitech_receiver/settings_templates.py:1171\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"Gulir secara vertikal.\"\n\n#: lib/logitech_receiver/settings_templates.py:1173\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"Membalikkan arah pengguliran.\"\n\n#: lib/logitech_receiver/settings_templates.py:1173\nmsgid   \"Natural scrolling\"\nmsgstr  \"Pengguliran alami\"\n\n#: lib/logitech_receiver/settings_templates.py:1174\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"Mengaktifkan roda jempol.\"\n\n#: lib/logitech_receiver/settings_templates.py:1174\nmsgid   \"Thumbwheel\"\nmsgstr  \"Roda jempol\"\n\n#: lib/logitech_receiver/settings_templates.py:1185\n#: lib/logitech_receiver/settings_templates.py:1189\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"Geser dari tepi atas\"\n\n#: lib/logitech_receiver/settings_templates.py:1186\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"Geser dari tepi kiri\"\n\n#: lib/logitech_receiver/settings_templates.py:1187\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"Geser dari tepi kanan\"\n\n#: lib/logitech_receiver/settings_templates.py:1188\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"Geser dari tepi bawah\"\n\n#: lib/logitech_receiver/settings_templates.py:1190\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"Geser dua jari dari tepi kiri\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"Geser dua jari dari tepi kanan\"\n\n#: lib/logitech_receiver/settings_templates.py:1192\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"Geser dua jari dari tepi bawah\"\n\n#: lib/logitech_receiver/settings_templates.py:1193\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"Geser dua jari dari tepi atas\"\n\n#: lib/logitech_receiver/settings_templates.py:1194\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"Jepit untuk memperkecil; sebarkan untuk memperbesar.\"\n\n#: lib/logitech_receiver/settings_templates.py:1194\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"Perbesar dengan dua jari.\"\n\n#: lib/logitech_receiver/settings_templates.py:1195\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"Jepit untuk memperkecil.\"\n\n#: lib/logitech_receiver/settings_templates.py:1196\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"Sebarkan untuk memperbesar.\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"Perbesar dengan tiga jari.\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"Zoom dengan dua jari\"\n\n#: lib/logitech_receiver/settings_templates.py:1216\nmsgid   \"Pixel zone\"\nmsgstr  \"Zona piksel\"\n\n#: lib/logitech_receiver/settings_templates.py:1217\nmsgid   \"Ratio zone\"\nmsgstr  \"Zona rasio\"\n\n#: lib/logitech_receiver/settings_templates.py:1218\nmsgid   \"Scale factor\"\nmsgstr  \"Faktor skala\"\n\n#: lib/logitech_receiver/settings_templates.py:1218\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"Mengatur kecepatan kursor.\"\n\n#: lib/logitech_receiver/settings_templates.py:1222\nmsgid   \"Left\"\nmsgstr  \"Kiri\"\n\n#: lib/logitech_receiver/settings_templates.py:1222\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"Koordinat paling kiri.\"\n\n#: lib/logitech_receiver/settings_templates.py:1223\nmsgid   \"Bottom\"\nmsgstr  \"Dasar\"\n\n#: lib/logitech_receiver/settings_templates.py:1223\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"Koordinat bawah.\"\n\n#: lib/logitech_receiver/settings_templates.py:1224\nmsgid   \"Width\"\nmsgstr  \"Lebar\"\n\n#: lib/logitech_receiver/settings_templates.py:1224\nmsgid   \"Width.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1225\nmsgid   \"Height\"\nmsgstr  \"Tinggi\"\n\n#: lib/logitech_receiver/settings_templates.py:1225\nmsgid   \"Height.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1226\nmsgid   \"Cursor speed.\"\nmsgstr  \"Kecepatan kursor.\"\n\n#: lib/logitech_receiver/settings_templates.py:1226\nmsgid   \"Scale\"\nmsgstr  \"Skala\"\n\n#: lib/logitech_receiver/settings_templates.py:1232\nmsgid   \"Gestures\"\nmsgstr  \"Gestur\"\n\n#: lib/logitech_receiver/settings_templates.py:1233\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"Sesuaikan perilaku mouse/touchpad.\"\n\n#: lib/logitech_receiver/settings_templates.py:1249\nmsgid   \"Gestures Diversion\"\nmsgstr  \"Pengalihan Gerakan\"\n\n#: lib/logitech_receiver/settings_templates.py:1250\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"Alihkan gerakan mouse/touchpad.\"\n\n#: lib/logitech_receiver/settings_templates.py:1266\nmsgid   \"Gesture params\"\nmsgstr  \"Param isyarat\"\n\n#: lib/logitech_receiver/settings_templates.py:1267\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"Ubah parameter numerik mouse/touchpad.\"\n\n#: lib/logitech_receiver/settings_templates.py:1291\nmsgid   \"M-Key LEDs\"\nmsgstr  \"LED M-Key\"\n\n#: lib/logitech_receiver/settings_templates.py:1293\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"Kontrol LED M-Key.\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\n#: lib/logitech_receiver/settings_templates.py:1328\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"Mungkin perlu tombol G dialihkan agar efektif.\"\n\n#: lib/logitech_receiver/settings_templates.py:1303\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"Nyalakan tombol %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1322\nmsgid   \"MR-Key LED\"\nmsgstr  \"LED Kunci MR\"\n\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"Kontrol LED MR-Key.\"\n\n#: lib/logitech_receiver/settings_templates.py:1345\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"Pemetaan Kunci/Tombol Persisten\"\n\n#: lib/logitech_receiver/settings_templates.py:1347\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"Ubah pemetaan kunci atau tombol secara permanen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"Mengganti tombol atau tombol penting (misalnya untuk mouse sebelah \"\n        \"kiritombol) dapat mengakibatkan sistem tidak dapat digunakan.\"\n\n#: lib/logitech_receiver/settings_templates.py:1406\nmsgid   \"Sidetone\"\nmsgstr  \"Nada samping\"\n\n#: lib/logitech_receiver/settings_templates.py:1407\nmsgid   \"Set sidetone level.\"\nmsgstr  \"Setel level nada samping.\"\n\n#: lib/logitech_receiver/settings_templates.py:1416\nmsgid   \"Equalizer\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1417\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"Tetapkan level equalizer.\"\n\n#: lib/logitech_receiver/settings_templates.py:1439\nmsgid   \"Hz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1445\nmsgid   \"Power Management\"\nmsgstr  \"Manajemen daya\"\n\n#: lib/logitech_receiver/settings_templates.py:1446\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"Matikan dalam hitungan menit (0 untuk tidak pernah).\"\n\n#: lib/logitech_receiver/settings_templates.py:1457\nmsgid   \"LED Control\"\nmsgstr  \"Kontrol LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1458\nmsgid   \"Switch control of LEDs between device and Solaar\"\nmsgstr  \"Ganti kontrol LED antara perangkat dan Solar\"\n\n#: lib/logitech_receiver/settings_templates.py:1473\nmsgid   \"LED Zone Effects\"\nmsgstr  \"Efek Zona LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1474\nmsgid   \"Set effect for LED Zone\"\nmsgstr  \"Atur efek untuk Zona LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1477\nmsgid   \"Speed\"\nmsgstr  \"Kecepatan\"\n\n#: lib/logitech_receiver/settings_templates.py:1478\nmsgid   \"Period\"\nmsgstr  \"Periode\"\n\n#: lib/logitech_receiver/settings_templates.py:1479\nmsgid   \"Intensity\"\nmsgstr  \"Intensitas\"\n\n#: lib/logitech_receiver/settings_templates.py:1480\nmsgid   \"Ramp\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1494\nmsgid   \"LEDs\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:112\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"Proses Solaar lain sudah berjalan jadi buka saja jendelanya\"\n\n#: lib/solaar/ui/about.py:38\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"Mengelola receiver Logitech,\\n\"\n        \"keyboard, mouse, dan tablet.\"\n\n#: lib/solaar/ui/about.py:46\nmsgid   \"Additional Programming\"\nmsgstr  \"Pemrograman Tambahan\"\n\n#: lib/solaar/ui/about.py:47\nmsgid   \"GUI design\"\nmsgstr  \"desain GUI\"\n\n#: lib/solaar/ui/about.py:49\nmsgid   \"Testing\"\nmsgstr  \"Pengujian\"\n\n#: lib/solaar/ui/about.py:57\nmsgid   \"Logitech documentation\"\nmsgstr  \"Dokumentasi Logitech\"\n\n#: lib/solaar/ui/action.py:83 lib/solaar/ui/action.py:87\n#: lib/solaar/ui/window.py:199\nmsgid   \"Unpair\"\nmsgstr  \"Lepaskan pasangan\"\n\n#: lib/solaar/ui/action.py:86 lib/solaar/ui/diversion_rules.py:104\nmsgid   \"Cancel\"\nmsgstr  \"Membatalkan\"\n\n#: lib/solaar/ui/common.py:35\nmsgid   \"Permissions error\"\nmsgstr  \"Kesalahan izin\"\n\n#: lib/solaar/ui/common.py:37\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"Menemukan receiver atau perangkat Logitech (%s), namun tidak \"\n        \"memiliki izin untuk membukanya.\"\n\n#: lib/solaar/ui/common.py:39\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"Kalau baru install Solaar, coba cabut receivernya atauperangkat dan \"\n        \"kemudian menyambungkannya kembali.\"\n\n#: lib/solaar/ui/common.py:42\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"Tidak dapat terhubung ke perangkat kesalahan\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"Menemukan receiver atau perangkat Logitech di %s, namun mengalami \"\n        \"kesalahanmenghubungkannya.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"Coba putuskan sambungan perangkat lalu sambungkan kembali atau \"\n        \"putarmati lalu hidupkan.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid   \"Unpairing failed\"\nmsgstr  \"Pembatalan pasangan gagal\"\n\n#: lib/solaar/ui/common.py:51\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"Gagal melepaskan pasangan %{device} dari %{receiver}.\"\n\n#: lib/solaar/ui/common.py:53\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"Penerima mengembalikan kesalahan, tanpa rincian lebih lanjut.\"\n\n#: lib/solaar/ui/config_panel.py:231\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"Selesai - ENTER untuk mengubah\"\n\n#: lib/solaar/ui/config_panel.py:231\nmsgid   \"Incomplete\"\nmsgstr  \"Tidak lengkap\"\n\n#: lib/solaar/ui/config_panel.py:476 lib/solaar/ui/config_panel.py:529\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"%d nilai\"\n\n#: lib/solaar/ui/config_panel.py:612\nmsgid   \"Changes allowed\"\nmsgstr  \"Perubahan diperbolehkan\"\n\n#: lib/solaar/ui/config_panel.py:613\nmsgid   \"No changes allowed\"\nmsgstr  \"Tidak ada perubahan yang diizinkan\"\n\n#: lib/solaar/ui/config_panel.py:614\nmsgid   \"Ignore this setting\"\nmsgstr  \"Abaikan pengaturan ini\"\n\n#: lib/solaar/ui/config_panel.py:659\nmsgid   \"Working\"\nmsgstr  \"Bekerja\"\n\n#: lib/solaar/ui/config_panel.py:662\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"Operasi baca/tulis gagal.\"\n\n#: lib/solaar/ui/diversion_rules.py:66\nmsgid   \"Built-in rules\"\nmsgstr  \"Aturan bawaan\"\n\n#: lib/solaar/ui/diversion_rules.py:66\nmsgid   \"User-defined rules\"\nmsgstr  \"Aturan yang ditentukan pengguna\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:1089\nmsgid   \"Rule\"\nmsgstr  \"Aturan\"\n\n#: lib/solaar/ui/diversion_rules.py:69 lib/solaar/ui/diversion_rules.py:538\n#: lib/solaar/ui/diversion_rules.py:665\nmsgid   \"Sub-rule\"\nmsgstr  \"Sub-aturan\"\n\n#: lib/solaar/ui/diversion_rules.py:71\nmsgid   \"[empty]\"\nmsgstr  \"[kosong]\"\n\n#: lib/solaar/ui/diversion_rules.py:95\nmsgid   \"Make changes permanent?\"\nmsgstr  \"Membuat perubahan permanen?\"\n\n#: lib/solaar/ui/diversion_rules.py:100\nmsgid   \"Yes\"\nmsgstr  \"Ya\"\n\n#: lib/solaar/ui/diversion_rules.py:102\nmsgid   \"No\"\nmsgstr  \"Tidak\"\n\n#: lib/solaar/ui/diversion_rules.py:107\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"Jika Anda memilih Tidak, perubahan akan hilang saat Solaar ditutup.\"\n\n#: lib/solaar/ui/diversion_rules.py:138\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"Editor Aturan Surya\"\n\n#: lib/solaar/ui/diversion_rules.py:231\nmsgid   \"Save changes\"\nmsgstr  \"Simpan perubahan\"\n\n#: lib/solaar/ui/diversion_rules.py:236\nmsgid   \"Discard changes\"\nmsgstr  \"Membuang perubahan\"\n\n#: lib/solaar/ui/diversion_rules.py:397\nmsgid   \"Insert here\"\nmsgstr  \"Masukkan di sini\"\n\n#: lib/solaar/ui/diversion_rules.py:399\nmsgid   \"Insert above\"\nmsgstr  \"Masukkan di atas\"\n\n#: lib/solaar/ui/diversion_rules.py:401\nmsgid   \"Insert below\"\nmsgstr  \"Masuk di bawah\"\n\n#: lib/solaar/ui/diversion_rules.py:407\nmsgid   \"Insert new rule here\"\nmsgstr  \"Masukkan aturan baru di sini\"\n\n#: lib/solaar/ui/diversion_rules.py:409\nmsgid   \"Insert new rule above\"\nmsgstr  \"Masukkan aturan baru di atas\"\n\n#: lib/solaar/ui/diversion_rules.py:411\nmsgid   \"Insert new rule below\"\nmsgstr  \"Masukkan aturan baru di bawah\"\n\n#: lib/solaar/ui/diversion_rules.py:456\nmsgid   \"Paste here\"\nmsgstr  \"Tempel di sini\"\n\n#: lib/solaar/ui/diversion_rules.py:458\nmsgid   \"Paste above\"\nmsgstr  \"Tempel di atas\"\n\n#: lib/solaar/ui/diversion_rules.py:460\nmsgid   \"Paste below\"\nmsgstr  \"Tempel di bawah\"\n\n#: lib/solaar/ui/diversion_rules.py:466\nmsgid   \"Paste rule here\"\nmsgstr  \"Tempel aturan di sini\"\n\n#: lib/solaar/ui/diversion_rules.py:468\nmsgid   \"Paste rule above\"\nmsgstr  \"Tempel aturan di atas\"\n\n#: lib/solaar/ui/diversion_rules.py:470\nmsgid   \"Paste rule below\"\nmsgstr  \"Tempel aturan di bawah\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid   \"Paste rule\"\nmsgstr  \"Tempel aturan\"\n\n#: lib/solaar/ui/diversion_rules.py:503\nmsgid   \"Flatten\"\nmsgstr  \"Meratakan\"\n\n#: lib/solaar/ui/diversion_rules.py:536\nmsgid   \"Insert\"\nmsgstr  \"Menyisipkan\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:667\n#: lib/solaar/ui/diversion_rules.py:1129\nmsgid   \"Or\"\nmsgstr  \"Atau\"\n\n#: lib/solaar/ui/diversion_rules.py:540 lib/solaar/ui/diversion_rules.py:666\n#: lib/solaar/ui/diversion_rules.py:1115\nmsgid   \"And\"\nmsgstr  \"Dan\"\n\n#: lib/solaar/ui/diversion_rules.py:542\nmsgid   \"Condition\"\nmsgstr  \"Kondisi\"\n\n#: lib/solaar/ui/diversion_rules.py:544 lib/solaar/ui/diversion_rules.py:1290\nmsgid   \"Feature\"\nmsgstr  \"Fitur\"\n\n#: lib/solaar/ui/diversion_rules.py:545 lib/solaar/ui/diversion_rules.py:1325\nmsgid   \"Report\"\nmsgstr  \"Laporan\"\n\n#: lib/solaar/ui/diversion_rules.py:546 lib/solaar/ui/diversion_rules.py:1204\nmsgid   \"Process\"\nmsgstr  \"Proses\"\n\n#: lib/solaar/ui/diversion_rules.py:547\nmsgid   \"Mouse process\"\nmsgstr  \"Proses tikus\"\n\n#: lib/solaar/ui/diversion_rules.py:548 lib/solaar/ui/diversion_rules.py:1362\nmsgid   \"Modifiers\"\nmsgstr  \"Pengubah\"\n\n#: lib/solaar/ui/diversion_rules.py:549 lib/solaar/ui/diversion_rules.py:1414\nmsgid   \"Key\"\nmsgstr  \"Kunci\"\n\n#: lib/solaar/ui/diversion_rules.py:550 lib/solaar/ui/diversion_rules.py:1455\nmsgid   \"KeyIsDown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:551 lib/solaar/ui/diversion_rules.py:2260\nmsgid   \"Active\"\nmsgstr  \"Aktif\"\n\n#: lib/solaar/ui/diversion_rules.py:552 lib/solaar/ui/diversion_rules.py:2217\n#: lib/solaar/ui/diversion_rules.py:2269 lib/solaar/ui/diversion_rules.py:2319\nmsgid   \"Device\"\nmsgstr  \"Perangkat\"\n\n#: lib/solaar/ui/diversion_rules.py:553 lib/solaar/ui/diversion_rules.py:2295\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:554 lib/solaar/ui/diversion_rules.py:2337\nmsgid   \"Setting\"\nmsgstr  \"Pengaturan\"\n\n#: lib/solaar/ui/diversion_rules.py:555 lib/solaar/ui/diversion_rules.py:1470\n#: lib/solaar/ui/diversion_rules.py:1519\nmsgid   \"Test\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:556 lib/solaar/ui/diversion_rules.py:1633\nmsgid   \"Test bytes\"\nmsgstr  \"Uji byte\"\n\n#: lib/solaar/ui/diversion_rules.py:557 lib/solaar/ui/diversion_rules.py:1734\nmsgid   \"Mouse Gesture\"\nmsgstr  \"Gerakan Mouse\"\n\n#: lib/solaar/ui/diversion_rules.py:561\nmsgid   \"Action\"\nmsgstr  \"Aksi\"\n\n#: lib/solaar/ui/diversion_rules.py:563 lib/solaar/ui/diversion_rules.py:1844\nmsgid   \"Key press\"\nmsgstr  \"Tekan tombol\"\n\n#: lib/solaar/ui/diversion_rules.py:564 lib/solaar/ui/diversion_rules.py:1895\nmsgid   \"Mouse scroll\"\nmsgstr  \"Gulir mouse\"\n\n#: lib/solaar/ui/diversion_rules.py:565 lib/solaar/ui/diversion_rules.py:1956\nmsgid   \"Mouse click\"\nmsgstr  \"Klik mouse\"\n\n#: lib/solaar/ui/diversion_rules.py:566\nmsgid   \"Set\"\nmsgstr  \"Mengatur\"\n\n#: lib/solaar/ui/diversion_rules.py:567 lib/solaar/ui/diversion_rules.py:2026\nmsgid   \"Execute\"\nmsgstr  \"Menjalankan\"\n\n#: lib/solaar/ui/diversion_rules.py:568 lib/solaar/ui/diversion_rules.py:1160\nmsgid   \"Later\"\nmsgstr  \"Nanti\"\n\n#: lib/solaar/ui/diversion_rules.py:597\nmsgid   \"Insert new rule\"\nmsgstr  \"Masukkan aturan baru\"\n\n#: lib/solaar/ui/diversion_rules.py:617 lib/solaar/ui/diversion_rules.py:1681\n#: lib/solaar/ui/diversion_rules.py:1786 lib/solaar/ui/diversion_rules.py:1985\nmsgid   \"Delete\"\nmsgstr  \"Menghapus\"\n\n#: lib/solaar/ui/diversion_rules.py:639\nmsgid   \"Negate\"\nmsgstr  \"Meniadakan\"\n\n#: lib/solaar/ui/diversion_rules.py:663\nmsgid   \"Wrap with\"\nmsgstr  \"Bungkus dengan\"\n\n#: lib/solaar/ui/diversion_rules.py:685\nmsgid   \"Cut\"\nmsgstr  \"Potong\"\n\n#: lib/solaar/ui/diversion_rules.py:700\nmsgid   \"Paste\"\nmsgstr  \"Tempel\"\n\n#: lib/solaar/ui/diversion_rules.py:706\nmsgid   \"Copy\"\nmsgstr  \"Salin\"\n\n#: lib/solaar/ui/diversion_rules.py:1070\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"Editor ini belum mendukung komponen aturan yang dipilih.\"\n\n#: lib/solaar/ui/diversion_rules.py:1140\nmsgid   \"Number of seconds to delay.\"\nmsgstr  \"Jumlah detik untuk ditunda.\"\n\n#: lib/solaar/ui/diversion_rules.py:1178\nmsgid   \"Not\"\nmsgstr  \"Bukan\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"Proses aktif X11. Hanya untuk digunakan di X11.\"\n\n#: lib/solaar/ui/diversion_rules.py:1217\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"Proses mouse X11. Hanya untuk digunakan di X11.\"\n\n#: lib/solaar/ui/diversion_rules.py:1234\nmsgid   \"MouseProcess\"\nmsgstr  \"Proses Tikus\"\n\n#: lib/solaar/ui/diversion_rules.py:1258\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"Nama fitur notifikasi yang memicu pemrosesan aturan.\"\n\n#: lib/solaar/ui/diversion_rules.py:1305\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"Laporkan jumlah pemberitahuan yang memicu pemrosesan aturan.\"\n\n#: lib/solaar/ui/diversion_rules.py:1338\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"Pengubah keyboard aktif. Tidak selalu tersedia di Wayland.\"\n\n#: lib/solaar/ui/diversion_rules.py:1378\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"Tombol atau tombol yang dialihkan ditekan atau dilepaskan.\\n\"\n        \"Gunakan pengaturan Pengalihan Tombol/Tombol dan Pengalihan Tombol G \"\n        \"untuk mengalihkankunci dan tombol.\"\n\n#: lib/solaar/ui/diversion_rules.py:1387\nmsgid   \"Key down\"\nmsgstr  \"Kunci bawah\"\n\n#: lib/solaar/ui/diversion_rules.py:1390\nmsgid   \"Key up\"\nmsgstr  \"Kunci atas\"\n\n#: lib/solaar/ui/diversion_rules.py:1430\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"Tombol atau tombol yang dialihkan sedang tidak aktif.\\n\"\n        \"Gunakan pengaturan Pengalihan Tombol/Tombol dan Pengalihan Tombol G \"\n        \"untuk mengalihkankunci dan tombol.\"\n\n#: lib/solaar/ui/diversion_rules.py:1468\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"Uji kondisi pada notifikasi yang memicu pemrosesan aturan.\"\n\n#: lib/solaar/ui/diversion_rules.py:1472\nmsgid   \"Parameter\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1534\nmsgid   \"begin (inclusive)\"\nmsgstr  \"mulai (inklusif)\"\n\n#: lib/solaar/ui/diversion_rules.py:1535\nmsgid   \"end (exclusive)\"\nmsgstr  \"akhir (eksklusif)\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid   \"range\"\nmsgstr  \"jangkauan\"\n\n#: lib/solaar/ui/diversion_rules.py:1546\nmsgid   \"minimum\"\nmsgstr  \"minimum\"\n\n#: lib/solaar/ui/diversion_rules.py:1547\nmsgid   \"maximum\"\nmsgstr  \"maksimum\"\n\n#: lib/solaar/ui/diversion_rules.py:1549\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"byte %(0)d hingga %(1)d, mulai dari %(2)d hingga %(3)d\"\n\n#: lib/solaar/ui/diversion_rules.py:1552 lib/solaar/ui/diversion_rules.py:1553\nmsgid   \"mask\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"byte %(0)d hingga %(1)d, sembunyikan %(2)d\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"Pengujian bit atau rentang pada byte dalam aturan pemicu pesan \"\n        \"notifikasipengolahan.\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid   \"type\"\nmsgstr  \"jenis\"\n\n#: lib/solaar/ui/diversion_rules.py:1661\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"Gerakan mouse dengan tombol memulai opsional diikuti dengan nol atau \"\n        \"lebih banyak gerakan tikus.\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid   \"Add movement\"\nmsgstr  \"Tambahkan gerakan\"\n\n#: lib/solaar/ui/diversion_rules.py:1760\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"Simulasikan klik atau tekan atau lepaskan kunci chord.\\n\"\n        \"On Wayland memerlukan akses tulis ke /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1765\nmsgid   \"Add key\"\nmsgstr  \"Tambahkan kunci\"\n\n#: lib/solaar/ui/diversion_rules.py:1768\nmsgid   \"Click\"\nmsgstr  \"Klik\"\n\n#: lib/solaar/ui/diversion_rules.py:1771\nmsgid   \"Depress\"\nmsgstr  \"Menekan\"\n\n#: lib/solaar/ui/diversion_rules.py:1774\nmsgid   \"Release\"\nmsgstr  \"Melepaskan\"\n\n#: lib/solaar/ui/diversion_rules.py:1859\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"Simulasikan gulir mouse.\\n\"\n        \"On Wayland memerlukan akses tulis ke /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1915\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"Simulasikan klik mouse.\\n\"\n        \"On Wayland memerlukan akses tulis ke /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid   \"Button\"\nmsgstr  \"Tombol\"\n\n#: lib/solaar/ui/diversion_rules.py:1919\nmsgid   \"Count and Action\"\nmsgstr  \"Hitungan dan Tindakan\"\n\n#: lib/solaar/ui/diversion_rules.py:1968\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"Jalankan perintah dengan argumen.\"\n\n#: lib/solaar/ui/diversion_rules.py:1971\nmsgid   \"Add argument\"\nmsgstr  \"Tambahkan argumen\"\n\n#: lib/solaar/ui/diversion_rules.py:2046\nmsgid   \"Toggle\"\nmsgstr  \"Beralih\"\n\n#: lib/solaar/ui/diversion_rules.py:2047\nmsgid   \"True\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2048\nmsgid   \"False\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2061\nmsgid   \"Unsupported setting\"\nmsgstr  \"Pengaturan tidak didukung\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2243\n#: lib/solaar/ui/diversion_rules.py:2325 lib/solaar/ui/diversion_rules.py:2568\n#: lib/solaar/ui/diversion_rules.py:2586\nmsgid   \"Originating device\"\nmsgstr  \"Perangkat asal\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"Perangkat aktif dan pengaturannya dapat diubah.\"\n\n#: lib/solaar/ui/diversion_rules.py:2265\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"Perangkat yang memunculkan notifikasi saat ini.\"\n\n#: lib/solaar/ui/diversion_rules.py:2278\nmsgid   \"Name of host computer.\"\nmsgstr  \"Nama komputer induk.\"\n\n#: lib/solaar/ui/diversion_rules.py:2345\nmsgid   \"Value\"\nmsgstr  \"Nilai\"\n\n#: lib/solaar/ui/diversion_rules.py:2353\nmsgid   \"Item\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2627\nmsgid   \"Change setting on device\"\nmsgstr  \"Ubah pengaturan pada perangkat\"\n\n#: lib/solaar/ui/diversion_rules.py:2643\nmsgid   \"Setting on device\"\nmsgstr  \"Pengaturan pada perangkat\"\n\n#: lib/solaar/ui/notify.py:118\nmsgid   \"unspecified reason\"\nmsgstr  \"alasan yang tidak ditentukan\"\n\n#: lib/solaar/ui/pair_window.py:126 lib/solaar/ui/pair_window.py:260\n#: lib/solaar/ui/pair_window.py:296\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"%(receiver_name)s: memasangkan perangkat baru\"\n\n#: lib/solaar/ui/pair_window.py:127\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"Masukkan kode sandi pada %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:130\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"Ketik %(passcode)s lalu tekan tombol enter.\"\n\n#: lib/solaar/ui/pair_window.py:133\nmsgid   \"left\"\nmsgstr  \"Kiri\"\n\n#: lib/solaar/ui/pair_window.py:133\nmsgid   \"right\"\nmsgstr  \"Kanan\"\n\n#: lib/solaar/ui/pair_window.py:135\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"Tekan %(code)s\\n\"\n        \"lalu tekan tombol kiri dan kanan secara bersamaan.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid   \"Pairing failed\"\nmsgstr  \"Pemasangan gagal\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"Pastikan perangkat Anda berada dalam jangkauan dan memiliki baterai \"\n        \"yang layakmengenakan biaya.\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"Perangkat baru terdeteksi, tetapi tidak kompatibel dengan \"\n        \"inipenerima.\"\n\n#: lib/solaar/ui/pair_window.py:198\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"Lebih banyak perangkat berpasangan daripada yang dapat didukung oleh \"\n        \"receiver.\"\n\n#: lib/solaar/ui/pair_window.py:200\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"Tidak ada rincian lebih lanjut yang tersedia tentang kesalahan \"\n        \"tersebut.\"\n\n#: lib/solaar/ui/pair_window.py:214\nmsgid   \"Found a new device:\"\nmsgstr  \"Menemukan perangkat baru:\"\n\n#: lib/solaar/ui/pair_window.py:239\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"Tautan nirkabel tidak dienkripsi\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"Penerima Unifying hanya kompatibel dengan perangkat Unifying.\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"Penerima Bolt hanya kompatibel dengan perangkat Bolt.\"\n\n#: lib/solaar/ui/pair_window.py:272\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"Receiver lain hanya kompatibel dengan beberapa perangkat.\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"Perangkat tidak boleh dipasangkan dengan receiver terdekat yang \"\n        \"aktif.\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"Tekan tombol atau kunci penyandingan hingga lampu penyandingan \"\n        \"berkedipdengan cepat.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid   \"You may have to first turn the device off and on again.\"\nmsgstr  \"Anda mungkin harus mematikan dan menghidupkan kembali perangkat \"\n        \"terlebih dahulu.\"\n\n#: lib/solaar/ui/pair_window.py:282\nmsgid   \"Turn on the device you want to pair.\"\nmsgstr  \"Nyalakan perangkat yang ingin Anda pasangkan.\"\n\n#: lib/solaar/ui/pair_window.py:284\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"Jika perangkat sudah dihidupkan, matikan dan hidupkan kembali.\"\n\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\\n\"\n        \"\\n\"\n        \"Penerima ini memiliki %d sisa penyandingan.\"\n\n#: lib/solaar/ui/pair_window.py:294\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\\n\"\n        \"Membatalkan pada saat ini tidak akan menghabiskan pasangan.\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid   \"No supported device found\"\nmsgstr  \"Tidak ditemukan perangkat yang didukung\"\n\n#: lib/solaar/ui/tray.py:63 lib/solaar/ui/window.py:321\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"Tentang %s\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"Keluar %s\"\n\n#: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:302\nmsgid   \"no receiver\"\nmsgstr  \"tidak ada penerima\"\n\n#: lib/solaar/ui/tray.py:315 lib/solaar/ui/tray.py:320\nmsgid   \"offline\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:318\nmsgid   \"no status\"\nmsgstr  \"tidak ada status\"\n\n#: lib/solaar/ui/window.py:99\nmsgid   \"Scanning\"\nmsgstr  \"Memindai\"\n\n#: lib/solaar/ui/window.py:132\nmsgid   \"Battery\"\nmsgstr  \"Baterai\"\n\n#: lib/solaar/ui/window.py:135\nmsgid   \"Wireless Link\"\nmsgstr  \"Tautan Nirkabel\"\n\n#: lib/solaar/ui/window.py:139\nmsgid   \"Lighting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:173\nmsgid   \"Show Technical Details\"\nmsgstr  \"Tampilkan Detail Teknis\"\n\n#: lib/solaar/ui/window.py:189\nmsgid   \"Pair new device\"\nmsgstr  \"Pasangkan perangkat baru\"\n\n#: lib/solaar/ui/window.py:207\nmsgid   \"Select a device\"\nmsgstr  \"Pilih perangkat\"\n\n#: lib/solaar/ui/window.py:324\nmsgid   \"Rule Editor\"\nmsgstr  \"Editor Aturan\"\n\n#: lib/solaar/ui/window.py:543\nmsgid   \"Path\"\nmsgstr  \"Path\"\n\n#: lib/solaar/ui/window.py:546\nmsgid   \"USB ID\"\nmsgstr  \"ID USB\"\n\n#: lib/solaar/ui/window.py:549 lib/solaar/ui/window.py:551\n#: lib/solaar/ui/window.py:566 lib/solaar/ui/window.py:568\nmsgid   \"Serial\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:555\nmsgid   \"Index\"\nmsgstr  \"Indeks\"\n\n#: lib/solaar/ui/window.py:557\nmsgid   \"Wireless PID\"\nmsgstr  \"PID Nirkabel\"\n\n#: lib/solaar/ui/window.py:559\nmsgid   \"Product ID\"\nmsgstr  \"ID Produk\"\n\n#: lib/solaar/ui/window.py:561\nmsgid   \"Protocol\"\nmsgstr  \"Protokol\"\n\n#: lib/solaar/ui/window.py:561\nmsgid   \"Unknown\"\nmsgstr  \"Tidak Diketahui\"\n\n#: lib/solaar/ui/window.py:563\nmsgid   \"Polling rate\"\nmsgstr  \"Tingkat pemungutan suara\"\n\n#: lib/solaar/ui/window.py:570\nmsgid   \"Unit ID\"\nmsgstr  \"ID Satuan\"\n\n#: lib/solaar/ui/window.py:584\nmsgid   \"Notifications\"\nmsgstr  \"Pemberitahuan\"\n\n#: lib/solaar/ui/window.py:628\nmsgid   \"No device paired.\"\nmsgstr  \"Tidak ada perangkat yang dipasangkan.\"\n\n#: lib/solaar/ui/window.py:637\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"Hingga %(max_count)s perangkat dapat dipasangkan ke receiver \"\n        \"ini.\"\n\n#: lib/solaar/ui/window.py:648\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"Penerima ini memiliki %d sisa penyandingan.\"\n\n#: lib/solaar/ui/window.py:705\nmsgid   \"Battery Voltage\"\nmsgstr  \"Tegangan Baterai\"\n\n#: lib/solaar/ui/window.py:707\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"Tegangan dilaporkan oleh baterai\"\n\n#: lib/solaar/ui/window.py:709\nmsgid   \"Battery Level\"\nmsgstr  \"Tingkat Baterai\"\n\n#: lib/solaar/ui/window.py:711\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"Perkiraan level yang dilaporkan oleh baterai\"\n\n#: lib/solaar/ui/window.py:718 lib/solaar/ui/window.py:720\nmsgid   \"next reported \"\nmsgstr  \"selanjutnya dilaporkan \"\n\n#: lib/solaar/ui/window.py:721\nmsgid   \" and next level to be reported.\"\nmsgstr  \" dan tingkat selanjutnya yang akan dilaporkan.\"\n\n#: lib/solaar/ui/window.py:737\nmsgid   \"encrypted\"\nmsgstr  \"terenkripsi\"\n\n#: lib/solaar/ui/window.py:739\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"Hubungan nirkabel antara perangkat ini dan penerimanya dienkripsi.\"\n\n#: lib/solaar/ui/window.py:741\nmsgid   \"not encrypted\"\nmsgstr  \"tidak dienkripsi\"\n\n#: lib/solaar/ui/window.py:745\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"Hubungan nirkabel antara perangkat ini dan penerimanya tidak \"\n        \"terenkripsi.\\n\"\n        \"Ini adalah masalah keamanan untuk perangkat penunjuk, dan merupakan \"\n        \"masalah keamanan utamamasalah untuk perangkat input teks.\"\n\n#: lib/solaar/ui/window.py:761\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"%(light_level)d mewah\"\n"
  },
  {
    "path": "po/it.po",
    "content": "# Italian translations for solaar package.\n# Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2013.\n#\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 0.9.2\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n        \"PO-Revision-Date: 2021-01-28 19:21+0000\\n\"\n        \"Last-Translator: Lorenzo <Unknown>\\n\"\n        \"Language-Team: none\\n\"\n        \"Language: it\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=2; plural=n != 1;\\n\"\n        \"X-Launchpad-Export-Date: 2021-02-17 00:56+0000\\n\"\n        \"X-Generator: Launchpad (build \"\n        \"b3a93345a124168b715ec9ae0945884caa15f58f)\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid   \"Bolt Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid   \"Unifying Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid   \"Nano Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"empty\"\nmsgstr  \"vuoto\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"critical\"\nmsgstr  \"critico\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"low\"\nmsgstr  \"bassa\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"average\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid   \"good\"\nmsgstr  \"buono\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"full\"\nmsgstr  \"piena\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"discharging\"\nmsgstr  \"in scarica\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"recharging\"\nmsgstr  \"in ricarica\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid   \"charging\"\nmsgstr  \"in ricarica\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"not charging\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"almost full\"\nmsgstr  \"quasi piena\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"charged\"\nmsgstr  \"carico\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"slow recharge\"\nmsgstr  \"ricarica lenta\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"invalid battery\"\nmsgstr  \"batteria non valida\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"thermal error\"\nmsgstr  \"errore di temperatura\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"error\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid   \"standard\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"fast\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid   \"device timeout\"\nmsgstr  \"timeout del dispositivo\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid   \"device not supported\"\nmsgstr  \"dispositivo non supportato\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"too many devices\"\nmsgstr  \"troppe periferiche\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"sequence timeout\"\nmsgstr  \"timeout della sequenza\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid   \"Firmware\"\nmsgstr  \"Firmware\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Bootloader\"\nmsgstr  \"Bootloader\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Hardware\"\nmsgstr  \"Hardware\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Other\"\nmsgstr  \"Altro\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Smart Shift\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"DPI Switch\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Left Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Right Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Left Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Right Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"Mouse Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid   \"pressed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid   \"released\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid   \"connected\"\nmsgstr  \"connesso\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid   \"disconnected\"\nmsgstr  \"disconnesso\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid   \"unpaired\"\nmsgstr  \"non associato\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid   \"powered on\"\nmsgstr  \"acceso\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid   \"register\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid   \"feature\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid   \"Swap Fx function\"\nmsgstr  \"Inverti funzioni Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"Quando abilitato, i tasti F1..F12 attivano le funzioni speciali,\\n\"\n        \"e dovrai tenere premuto il tasto FN per attivare le funzioni \"\n        \"standard.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"Quando disabilitato, i tasti F1..F12 attivano le funzioni standard,\\n\"\n        \"dovrai tenere premuto il tasto FN per attivare le funzioni speciali.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid   \"Hand Detection\"\nmsgstr  \"Rilevamento mano\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"Accendi l'illuminazione quando le mani sono sopra la tastiera.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"Modalità di alta sensibilità per lo scorrimento verticale con la \"\n        \"rotella.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid   \"Side Scrolling\"\nmsgstr  \"Scorrimento Laterale\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"Quando disabilitato, spingendo la rotella lateralmente vengono \"\n        \"inviati eventi personalizzati\\n\"\n        \"invece degli eventi standard di scorrimento laterale.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"Sensibilità al movimento del mouse\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid   \"Backlight\"\nmsgstr  \"Retroilluminazione\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid   \"Turn illumination on or off on keyboard.\"\nmsgstr  \"Accendi o spegni l'illuminazione della tastiera\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"Direzione di scorrimento con la rotella\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"Inverti la direzione per lo scorrimento verticale con la rotella\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"Risoluzione dello scorrimento con la rotella\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"Sensibilità (velocità del puntatore)\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"Moltiplicatore della velocità del mouse (256 è il moltiplicatore \"\n        \"normale)\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid   \"Onboard Profiles\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid   \"Enable onboard profiles, which often control report rate and \"\n        \"keyboard lighting\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid   \"Polling Rate (ms)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid   \"Frequency of device polling, in milliseconds\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid   \"Divert crown events\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid   \"Divert G Keys\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid   \"Make G keys send GKEY HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid   \"May also make M keys and MR key send HID++ notifications\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Freespinning\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid   \"Key/Button Actions\"\nmsgstr  \"Azioni tasto/pulsante\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"Cambia l'azione per il tasto o il pulsante\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"Cambiare azioni importanti (come per il bottone sinistro del mouse) \"\n        \"può rendere inutilizzabile il sistema\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Diverted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid   \"Mouse Gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Regular\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid   \"Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"Sensibilità (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid   \"Off\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid   \"Disable keys\"\nmsgstr  \"Disabilita i pulsanti\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"Disabilita dei pulsanti specifici della tastiera\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"Disabilita il tasto %s\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid   \"Set OS\"\nmsgstr  \"Specifica il sistema operativo\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"Cambia i pulsanti in funzione del sistema operativo\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid   \"Change Host\"\nmsgstr  \"Cambia Host\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"Connetti ad un host differente\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Performs a left click.\"\nmsgstr  \"Clicca con il pulsante sinistro\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Single tap\"\nmsgstr  \"tocco singolo\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Performs a right click.\"\nmsgstr  \"Clicca con il pulsante destro\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"tocco singolo con due dita\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"tocco singolo con tre dita\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Double tap\"\nmsgstr  \"doppio tocco\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Performs a double click.\"\nmsgstr  \"Esegue un doppio click\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"doppio tocco con due dita\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"doppio tocco con tre dita\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"Trascina gli elementi muovendo il dito dopo aver fatto un doppio tap\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Tap and drag\"\nmsgstr  \"tocca e trascina\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"Trascina gli elementi muovendo il dito dopo aver fatto un doppio tap\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"tocca e trascina con due dita\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"tocca e trascina con tre dita\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid   \"Scroll with one finger\"\nmsgstr  \"scorri con un dito\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scrolls.\"\nmsgstr  \"Scorre.\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"scorri con due dita\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"scorri orizzontalmente con due dita\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"scorre orizzontalmente\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"scorri verticalmente con due dita\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"scorre verticalmente\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"inverte la direzione di scorrimento\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Natural scrolling\"\nmsgstr  \"Scorrimento naturale\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Thumbwheel\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"scorri dal bordo superiore\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"scorri dal bordo sinistro\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"scorri dal bordo destro\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"scorri dal bordo inferiore\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"scorri con due dita dal bordo sinistro\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"scorri con due dita dal bordo detro\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"scorri con due dita dal bordo inferiore\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"scorri con due dita dal bordo superiore\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"fai lo zoom con due dita\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"pizzica per rimpicciolire\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"fai lo zoom con tre dita\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"fai lo zoom con due dita\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid   \"Pixel zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid   \"Ratio zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Scale factor\"\nmsgstr  \"Fattore di scala\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left\"\nmsgstr  \"Sinistra\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width\"\nmsgstr  \"Larghezza\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width.\"\nmsgstr  \"Larghezza\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height\"\nmsgstr  \"Altezza\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height.\"\nmsgstr  \"Altezza\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Cursor speed.\"\nmsgstr  \"Velocità del cursore\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Scale\"\nmsgstr  \"Scala\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid   \"Gestures\"\nmsgstr  \"Gesti\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"Personalizza il comportamento del mouse/touchpad\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid   \"Gestures Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid   \"Gesture params\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"Cambia i paramentri numerici di un mouse/touchpad\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid   \"M-Key LEDs\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid   \"MR-Key LED\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Sidetone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid   \"Set sidetone level.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid   \"Equalizer\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid   \"Hz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid   \"Power Management\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid   \"No paired devices.\"\nmsgstr  \"Nessun dispositivo associato.\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"%(count)s dispositivo connesso.\"\nmsgstr[1]       \"%(count)s dispositivi connessi.\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid   \"Battery: %(level)s\"\nmsgstr  \"Batteria: %(level)s\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid   \"Battery: %(percent)d%%\"\nmsgstr  \"Batteria: %(percent)d%%\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid   \"Lighting: %(level)s lux\"\nmsgstr  \"Illuminazione: %(level)s lux\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"Batteria: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"Batteria: %(percent)d%% (%(status)s)\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid   \"Permissions error\"\nmsgstr  \"Errore di permessi\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid   \"Unpairing failed\"\nmsgstr  \"Disassociazione fallita\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"Disassociazione fallita di  %{device} da %{receiver}.\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"Il ricevitore ha ritornato un errore senza ulteriori dettagli.\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:44\nmsgid   \"Additional Programming\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:45\nmsgid   \"GUI design\"\nmsgstr  \"GUI design\"\n\n#: lib/solaar/ui/about.py:47\nmsgid   \"Testing\"\nmsgstr  \"Testing\"\n\n#: lib/solaar/ui/about.py:54\nmsgid   \"Logitech documentation\"\nmsgstr  \"Documentazione Logitech\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid   \"Unpair\"\nmsgstr  \"Disassocia\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid   \"Cancel\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Incomplete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"%d valore\"\nmsgstr[1]       \"%d valori\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid   \"Changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid   \"No changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid   \"Ignore this setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid   \"Working\"\nmsgstr  \"Lavorando\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"Operazione di Lettura/Scrittura fallita.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"Built-in rules\"\nmsgstr  \"Regole integrate\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"User-defined rules\"\nmsgstr  \"Regole definite dall'utente\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid   \"Rule\"\nmsgstr  \"Regola\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid   \"Sub-rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid   \"[empty]\"\nmsgstr  \"[vuoto]\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"Editor di regole di Solaar\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Make changes permanent?\"\nmsgstr  \"Rendi le modifiche permanenti?\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid   \"Yes\"\nmsgstr  \"Sì\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid   \"No\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"Se scegli No, le modifiche saranno perse quando Solaar viene chiuso\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid   \"Save changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid   \"Discard changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid   \"Insert here\"\nmsgstr  \"Inserisci qui\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid   \"Insert above\"\nmsgstr  \"Inserisci sopra\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid   \"Insert below\"\nmsgstr  \"Inserisci sotto\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid   \"Insert new rule here\"\nmsgstr  \"Inserisci una nuova regola qui\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid   \"Insert new rule above\"\nmsgstr  \"Inserisci una nuova regola sopra\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Insert new rule below\"\nmsgstr  \"Inserisci una nuova regola sotto\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid   \"Paste here\"\nmsgstr  \"Incolla qui\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid   \"Paste above\"\nmsgstr  \"Incolla sopra\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid   \"Paste below\"\nmsgstr  \"Incolla sotto\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid   \"Paste rule here\"\nmsgstr  \"Incolla la regola qui\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid   \"Paste rule above\"\nmsgstr  \"Incolla la regola sopra\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Paste rule below\"\nmsgstr  \"Incolla la regola sotto\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid   \"Paste rule\"\nmsgstr  \"Incolla la regola\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid   \"Flatten\"\nmsgstr  \"Appiattisci\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Insert\"\nmsgstr  \"Inserisci\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Or\"\nmsgstr  \"Oppure\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid   \"And\"\nmsgstr  \"E\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid   \"Condition\"\nmsgstr  \"Condizione\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid   \"Feature\"\nmsgstr  \"Funzionalità\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid   \"Report\"\nmsgstr  \"Segnala\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid   \"Process\"\nmsgstr  \"Processo\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid   \"Mouse process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid   \"Modifiers\"\nmsgstr  \"Modificatori\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid   \"Key\"\nmsgstr  \"Chiave\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid   \"KeyIsDown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid   \"Active\"\nmsgstr  \"Attivo\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid   \"Device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid   \"Setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid   \"Test\"\nmsgstr  \"Test\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid   \"Test bytes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid   \"Mouse Gesture\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid   \"Action\"\nmsgstr  \"Azione\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid   \"Key press\"\nmsgstr  \"Pressione del tasto\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid   \"Mouse scroll\"\nmsgstr  \"Scorrimento del mouse\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid   \"Mouse click\"\nmsgstr  \"Click del mouse\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Set\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid   \"Execute\"\nmsgstr  \"Esegui\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Later\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Insert new rule\"\nmsgstr  \"Inserisci una nuova regola\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid   \"Delete\"\nmsgstr  \"Elimina\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid   \"Negate\"\nmsgstr  \"Nega\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid   \"Wrap with\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid   \"Cut\"\nmsgstr  \"Taglia\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid   \"Paste\"\nmsgstr  \"Incolla\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid   \"Copy\"\nmsgstr  \"Copia\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"Questo editor ancora non supporta la componente selezionata\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid   \"Number of seconds to delay.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid   \"Not\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid   \"MouseProcess\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid   \"Key down\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid   \"Key up\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid   \"Parameter\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid   \"begin (inclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid   \"end (exclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid   \"range\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid   \"minimum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid   \"maximum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid   \"mask\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid   \"type\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid   \"Add movement\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid   \"Add key\"\nmsgstr  \"Aggiungi chiave\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid   \"Click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid   \"Depress\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid   \"Release\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid   \"Button\"\nmsgstr  \"Pulsante\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid   \"Count and Action\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid   \"Add argument\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"Toggle\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"True\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid   \"False\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid   \"Unsupported setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid   \"Originating device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid   \"Name of host computer.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid   \"Value\"\nmsgstr  \"Valore\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid   \"Item\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid   \"Change setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid   \"Setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid   \"offline\"\nmsgstr  \"disconnesso\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"%(receiver_name)s: accoppia un nuovo dispositivo\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"left\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"right\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid   \"Pairing failed\"\nmsgstr  \"Associazione fallita\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"Assicurati che il dispositivo sia vicino al ricevitore e che abbia \"\n        \"le batterie cariche.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"Un nuovo dispositivo è stato rilevato, ma non è compatibile con \"\n        \"questo ricevitore.\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"Più dispositivi accoppiati di quanti il ricevitore possa supportarne\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"Non sono disponibili ulteriori dettagli per l'errore.\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid   \"Found a new device:\"\nmsgstr  \"Trovato un nuovo dispositivo:\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"Il collegamento wireless non è ciftrato.\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid   \"You may have to first turn the device off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid   \"Turn on the device you want to pair.\"\nmsgstr  \"Accendi il dispositivo che vuoi associare.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\\n\"\n        \"\\n\"\n        \"Questo ricevitore ha %d accoppiamento rimanente.\"\nmsgstr[1]       \"\\n\"\n        \"\\n\"\n        \"Questo ricevitore ha %d accoppiamenti rimanenti.\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\\n\"\n        \"Annullando a questo punto non costerà un accoppiamento\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid   \"No supported device found\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"Informazioni %s\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"Esci %s\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid   \"no receiver\"\nmsgstr  \"nessun ricevitore\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid   \"no status\"\nmsgstr  \"nessuno stato\"\n\n#: lib/solaar/ui/window.py:96\nmsgid   \"Scanning\"\nmsgstr  \"Ricerca\"\n\n#: lib/solaar/ui/window.py:129\nmsgid   \"Battery\"\nmsgstr  \"Batteria\"\n\n#: lib/solaar/ui/window.py:132\nmsgid   \"Wireless Link\"\nmsgstr  \"Collegamento Wireless\"\n\n#: lib/solaar/ui/window.py:136\nmsgid   \"Lighting\"\nmsgstr  \"Luminosità\"\n\n#: lib/solaar/ui/window.py:170\nmsgid   \"Show Technical Details\"\nmsgstr  \"Mostra Dettagli Tecnici\"\n\n#: lib/solaar/ui/window.py:186\nmsgid   \"Pair new device\"\nmsgstr  \"Associa un nuovo dispositivo\"\n\n#: lib/solaar/ui/window.py:205\nmsgid   \"Select a device\"\nmsgstr  \"Seleziona un dispositivo\"\n\n#: lib/solaar/ui/window.py:322\nmsgid   \"Rule Editor\"\nmsgstr  \"Editor regole\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Path\"\nmsgstr  \"Percorso\"\n\n#: lib/solaar/ui/window.py:536\nmsgid   \"USB ID\"\nmsgstr  \"ID USB\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid   \"Serial\"\nmsgstr  \"Seriale\"\n\n#: lib/solaar/ui/window.py:545\nmsgid   \"Index\"\nmsgstr  \"Indice\"\n\n#: lib/solaar/ui/window.py:547\nmsgid   \"Wireless PID\"\nmsgstr  \"PID Wireless\"\n\n#: lib/solaar/ui/window.py:549\nmsgid   \"Product ID\"\nmsgstr  \"ID Prodotto\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Protocol\"\nmsgstr  \"Protocollo\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Unknown\"\nmsgstr  \"Sconosciuto\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid   \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr  \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#: lib/solaar/ui/window.py:554\nmsgid   \"Polling rate\"\nmsgstr  \"Frequenza di aggiornamento\"\n\n#: lib/solaar/ui/window.py:565\nmsgid   \"Unit ID\"\nmsgstr  \"ID unità\"\n\n#: lib/solaar/ui/window.py:576\nmsgid   \"none\"\nmsgstr  \"nessuno\"\n\n#: lib/solaar/ui/window.py:577\nmsgid   \"Notifications\"\nmsgstr  \"Notifiche\"\n\n#: lib/solaar/ui/window.py:621\nmsgid   \"No device paired.\"\nmsgstr  \"Nessun dispositivo accoppiato\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"Fino a %(max_count)s dispositivo può essere accoppiato con \"\n        \"questo ricevitore\"\nmsgstr[1]       \"Fino a %(max_count)s dispositivi possono essere accoppiati \"\n        \"con questo ricevitore\"\n\n#: lib/solaar/ui/window.py:634\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"Solo un dispositivo può essere collegato a questo ricevitore\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"Questo ricevitore ha %d accoppiamento rimanente\"\nmsgstr[1]       \"Questo ricevitore ha %d accoppiamenti rimanenti\"\n\n#: lib/solaar/ui/window.py:692\nmsgid   \"Battery Voltage\"\nmsgstr  \"Tensione della batteria\"\n\n#: lib/solaar/ui/window.py:694\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"Tensione riportata dalla batteria\"\n\n#: lib/solaar/ui/window.py:696\nmsgid   \"Battery Level\"\nmsgstr  \"Livello batteria\"\n\n#: lib/solaar/ui/window.py:698\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"Livello approssimativo riportato dalla batteria\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid   \"next reported \"\nmsgstr  \"Prossimo livello \"\n\n#: lib/solaar/ui/window.py:708\nmsgid   \" and next level to be reported.\"\nmsgstr  \" e il prossimo livello che verrà riportato\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"last known\"\nmsgstr  \"ultimo conosciuto\"\n\n#: lib/solaar/ui/window.py:724\nmsgid   \"encrypted\"\nmsgstr  \"cifrato\"\n\n#: lib/solaar/ui/window.py:726\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"Il collegamento wireless tra il dispositivo e il suo ricevitore è \"\n        \"cifrato.\"\n\n#: lib/solaar/ui/window.py:728\nmsgid   \"not encrypted\"\nmsgstr  \"non cifrato\"\n\n#: lib/solaar/ui/window.py:732\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"%(light_level)d lux\"\n\n#~ msgid        \"Adjust the DPI by sliding the mouse horizontally while \"\n#~      \"holding the DPI button.\"\n#~ msgstr       \"Modifica i DPI facendo scorrere il mouse orizzontalmente \"\n#~      \"mentre si preme il pulsante DPI\"\n\n#~ msgid        \"Battery information unknown.\"\n#~ msgstr       \"Informazioni sulla batteria sconosciute\"\n\n#~ msgid        \"Click to allow changes.\"\n#~ msgstr       \"Premi per consentire modifiche\"\n\n#~ msgid        \"Click to prevent changes.\"\n#~ msgstr       \"Clicca per evitare modifiche\"\n\n#~ msgid        \"Count\"\n#~ msgstr       \"Numero\"\n\n#~ msgid        \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr       \"Di fatto in Linux disattiva lo scorrimento con la rotella\"\n\n#~ msgid        \"For more information see the Solaar installation directions\\n\"\n#~      \"at https://pwr-solaar.github.io/Solaar/installation\"\n#~ msgstr       \"Per ulteriori informazioni consulta le istruzioni \"\n#~      \"all'installazione di Solaar\\n\"\n#~      \"su https://pwr-solaar.github.io/Solaar/installation\"\n\n#, python-format\n#~ msgid        \"Found a Logitech Receiver (%s), but did not have permission \"\n#~      \"to open it.\"\n#~ msgstr       \"Rilevato un ricevitore Logitech (%s), ma non si hanno i \"\n#~      \"permessi per aprirlo.\"\n\n#~ msgid        \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr       \"Modalità HID++ per lo scorrimento verticale con la rotella\"\n\n#~ msgid        \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr       \"Se il dispositivo è già acceso, spegnilo e accendilo \"\n#~      \"nuovamente.\"\n\n#~ msgid        \"If you've just installed Solaar, try removing the receiver \"\n#~      \"and plugging it back in.\"\n#~ msgstr       \"Se hai appena installato Solaar prova a scollegare e \"\n#~      \"ricollegare il ricevitore.\"\n\n#~ msgid        \"No Logitech receiver found\"\n#~ msgstr       \"Nessun ricevitore Logitech trovato\"\n\n#~ msgid        \"Shows status of devices connected\\n\"\n#~      \"through wireless Logitech receivers.\"\n#~ msgstr       \"Mostra lo stato dei dispositivi connessi\\n\"\n#~      \"attraverso i ricevitori Logitech.\"\n\n#~ msgid        \"Solaar depends on a udev file that is not present\"\n#~ msgstr       \"Solaar dipende da un file udev non presente\"\n\n#~ msgid        \"The wireless link between this device and its receiver is \"\n#~      \"not encrypted.\\n\"\n#~      \"\\n\"\n#~      \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~      \"security issue.\\n\"\n#~      \"\\n\"\n#~      \"It is, however, a major security issue for text-input devices \"\n#~      \"(keyboards, numpads),\\n\"\n#~      \"because typed text can be sniffed inconspicuously by 3rd parties \"\n#~      \"within range.\"\n#~ msgstr       \"Il collegamento wireless tra il dispositivo e il suo \"\n#~      \"ricevitore non è cifrato.\\n\"\n#~      \"\\n\"\n#~      \"Per i dispositivi di puntamento (mouse, trackball, trackpad) non è \"\n#~      \"un grave problema.\\n\"\n#~      \"\\n\"\n#~      \"E' un problema maggiore per i dispositivi di immissione di testo \"\n#~      \"(tastiera, numpad),\\n\"\n#~      \"perché il testo digitato potrebbe essere intercettato da dispositivi \"\n#~      \"di terze parti vicini.\"\n\n#~ msgid        \"Thumb Wheel HID++ Scrolling\"\n#~ msgstr       \"Rotella di scorrimento Scorrimento HID++\"\n\n#~ msgid        \"height\"\n#~ msgstr       \"altezza\"\n\n#~ msgid        \"top\"\n#~ msgstr       \"in alto\"\n\n#~ msgid        \"unknown\"\n#~ msgstr       \"sconosciuto\"\n\n#~ msgid        \"width\"\n#~ msgstr       \"larghezza\"\n"
  },
  {
    "path": "po/ja.po",
    "content": "# Japanese translations for solaar package\n# Copyright (C) 2021 SOLAAR'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the Solaar package.\n#\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 1.0.6\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n        \"PO-Revision-Date: 2021-09-24 00:25+0900\\n\"\n        \"Last-Translator: Ryunosuke Toda <toda.ryunosuke@gmail.com>\\n\"\n        \"Language-Team: \\n\"\n        \"Language: ja\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=1; plural=0;\\n\"\n        \"X-Generator: Poedit 3.0\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid   \"Bolt Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid   \"Unifying Receiver\"\nmsgstr  \"Unifying レシーバー\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid   \"Nano Receiver\"\nmsgstr  \"Nano レシーバー\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"Lightspeed レシーバー\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"EX100 レシーバー 27 Mhz\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"empty\"\nmsgstr  \"空\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"critical\"\nmsgstr  \"わずか\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"low\"\nmsgstr  \"低\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"average\"\nmsgstr  \"中\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid   \"good\"\nmsgstr  \"良好\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"full\"\nmsgstr  \"満充電\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"discharging\"\nmsgstr  \"低下\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"recharging\"\nmsgstr  \"再充電中\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid   \"charging\"\nmsgstr  \"充電中\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"not charging\"\nmsgstr  \"充電していません\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"almost full\"\nmsgstr  \"ほぼ満充電\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"charged\"\nmsgstr  \"充電完了\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"slow recharge\"\nmsgstr  \"低速充電\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"invalid battery\"\nmsgstr  \"バッテリー不正\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"thermal error\"\nmsgstr  \"温度エラー\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"error\"\nmsgstr  \"エラー\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid   \"standard\"\nmsgstr  \"標準\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"fast\"\nmsgstr  \"高速\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"slow\"\nmsgstr  \"低速\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid   \"device timeout\"\nmsgstr  \"デバイス応答なし\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid   \"device not supported\"\nmsgstr  \"非対応のデバイス\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"too many devices\"\nmsgstr  \"デバイス数超過\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"sequence timeout\"\nmsgstr  \"シーケンス応答なし\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid   \"Firmware\"\nmsgstr  \"Firmware\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Bootloader\"\nmsgstr  \"Bootloader\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Hardware\"\nmsgstr  \"Hardware\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Other\"\nmsgstr  \"Other\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Left Button\"\nmsgstr  \"左ボタン\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"Right Button\"\nmsgstr  \"右ボタン\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Middle Button\"\nmsgstr  \"中ボタン\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Back Button\"\nmsgstr  \"戻るボタン\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Forward Button\"\nmsgstr  \"進むボタン\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"マウスジェスチャーボタン\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Smart Shift\"\nmsgstr  \"SmartShift\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"DPI Switch\"\nmsgstr  \"DPIスイッチ\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Left Tilt\"\nmsgstr  \"左チルト\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Right Tilt\"\nmsgstr  \"右チルト\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Left Click\"\nmsgstr  \"左クリック\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Right Click\"\nmsgstr  \"右クリック\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"マウス中ボタン\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"Mouse Back Button\"\nmsgstr  \"マウス戻るボタン\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"マウス進むボタン\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid   \"pressed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid   \"released\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is closed\"\nmsgstr  \"ペアリング試行終了\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is open\"\nmsgstr  \"ペアリング試行開始\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid   \"connected\"\nmsgstr  \"接続\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid   \"disconnected\"\nmsgstr  \"切断\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid   \"unpaired\"\nmsgstr  \"ペアリング解除\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid   \"powered on\"\nmsgstr  \"電源オン\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid   \"register\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid   \"feature\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid   \"Swap Fx function\"\nmsgstr  \"ファンクションキー動作を入替\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"オンにすると、F1〜F12をカスタマイズキーとして使用します。\\n\"\n        \"標準のファンクションキーとして使用するには、fnキーを押しながら操作し\"\n        \"ます。\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"オフにすると、F1〜F12を標準のファンクションキーとして使用します。\\n\"\n        \"カスタマイズキーとして使用するには、fnキーを押しながら操作します。\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid   \"Hand Detection\"\nmsgstr  \"手の検出\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"手がキーボードの上にあるとき照明をオンにします。\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"ホイール縦スクロール高感度モード。\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid   \"Side Scrolling\"\nmsgstr  \"サイドスクロール\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"マウスの動きの感度\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid   \"Backlight\"\nmsgstr  \"バックライト\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid   \"Turn illumination on or off on keyboard.\"\nmsgstr  \"バックライトのON/OFFを切り替えます。\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"高解像度スクロールホイール\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"スクロールホイール迂回\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"ホイールのスクロール方向\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"ホイールでの縦スクロール方向を逆にします。\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"ホイールのスクロール解像度\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"感度（ポインタ速度）\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"マウス速度の倍率（256で標準）。\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"サムホイールの方向\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"サムホイールのスクロール方向を反転します。\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid   \"Onboard Profiles\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid   \"Enable onboard profiles, which often control report rate and \"\n        \"keyboard lighting\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid   \"Polling Rate (ms)\"\nmsgstr  \"ポーリングレート(ミリ秒)\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid   \"Frequency of device polling, in milliseconds\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid   \"Divert crown events\"\nmsgstr  \"クラウンをルールへ迂回\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"CrownにCROWNHID++通知を送信させます（Solaarルールをトリガーしますが、\"\n        \"それ以外の場合は無視されます）。\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid   \"Divert G Keys\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid   \"Make G keys send GKEY HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid   \"May also make M keys and MR key send HID++ notifications\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Freespinning\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid   \"Key/Button Actions\"\nmsgstr  \"キー/ボタン動作\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"キーやボタンの動作を変更します。\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"重要なアクション（マウスの左ボタンなど）を変更すると、システムが使用\"\n        \"できなくなる可能性があります。\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"キー/ボタンをルールへ迂回\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Diverted\"\nmsgstr  \"迂回する\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid   \"Mouse Gestures\"\nmsgstr  \"マウスジェスチャー\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Regular\"\nmsgstr  \"通常通り\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid   \"Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"感度（DPI）\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid   \"Off\"\nmsgstr  \"オフ\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid   \"Disable keys\"\nmsgstr  \"無効キー\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"特定のキーを無効にします。\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"キー %s を無効にする。\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid   \"Set OS\"\nmsgstr  \"OS設定\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"OSに合わせたキーに変更します。\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid   \"Change Host\"\nmsgstr  \"ホスト変更\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"接続を他のホストへ切り替えます\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Performs a left click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Single tap\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Performs a right click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Double tap\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Performs a double click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Tap and drag\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"タップおよびエッジジェスチャを無効にします（Fn + LeftClickを押すのと\"\n        \"同等）。\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"タップとエッジジェスチャーの無効化\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid   \"Scroll with one finger\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scrolls.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Natural scrolling\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Thumbwheel\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid   \"Pixel zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid   \"Ratio zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Scale factor\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"カーソル速度を設定します。\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width\"\nmsgstr  \"幅\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height\"\nmsgstr  \"高さ\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Cursor speed.\"\nmsgstr  \"カーソル速度。\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Scale\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid   \"Gestures\"\nmsgstr  \"ジェスチャー\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"マウス/タッチパッドの動作を微調整します。\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid   \"Gestures Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid   \"Gesture params\"\nmsgstr  \"ジェスチャーパラメータ\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"マウス/タッチパッドの数値パラメータを変更します。\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid   \"M-Key LEDs\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid   \"MR-Key LED\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Sidetone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid   \"Set sidetone level.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid   \"Equalizer\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid   \"Hz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid   \"Power Management\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid   \"No paired devices.\"\nmsgstr  \"ペアリングされたデバイスはありません。\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"%(count)s デバイスとペアリングされています。\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid   \"Battery: %(level)s\"\nmsgstr  \"バッテリー残量: %(level)s\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid   \"Battery: %(percent)d%%\"\nmsgstr  \"バッテリー残量: %(percent)d%%\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid   \"Lighting: %(level)s lux\"\nmsgstr  \"照明: %(level)s ルクス\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"バッテリー残量: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"バッテリー残量: %(percent)d%% (%(status)s)\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid   \"Permissions error\"\nmsgstr  \"権限エラー\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"デバイスに接続できません\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"%s で Logitech のレシーバーまたはデバイスが見つかりましたが、接続中に\"\n        \"エラーが発生しました。\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid   \"Unpairing failed\"\nmsgstr  \"ペアリング解除失敗\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"%{receiver} からの %{device} のペアリング解除に失敗しました。\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"レシーバーがこれ以上の詳細なしでエラーを返しました。\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"Logitechのレシーバー、キーボード、\\n\"\n        \"マウス、タブレットを管理。\"\n\n#: lib/solaar/ui/about.py:44\nmsgid   \"Additional Programming\"\nmsgstr  \"追加のプログラミング\"\n\n#: lib/solaar/ui/about.py:45\nmsgid   \"GUI design\"\nmsgstr  \"GUIデザイン\"\n\n#: lib/solaar/ui/about.py:47\nmsgid   \"Testing\"\nmsgstr  \"テスト\"\n\n#: lib/solaar/ui/about.py:54\nmsgid   \"Logitech documentation\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid   \"Unpair\"\nmsgstr  \"ペアリング解除\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid   \"Cancel\"\nmsgstr  \"キャンセル\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Incomplete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid   \"Changes allowed\"\nmsgstr  \"変更を許可する\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid   \"No changes allowed\"\nmsgstr  \"変更を許可しない\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid   \"Ignore this setting\"\nmsgstr  \"この設定を無視する\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid   \"Working\"\nmsgstr  \"処理中\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"読取または書込処理に失敗しました。\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"Built-in rules\"\nmsgstr  \"組み込みのルール\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"User-defined rules\"\nmsgstr  \"ユーザー定義のルール\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid   \"Rule\"\nmsgstr  \"ルール\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid   \"Sub-rule\"\nmsgstr  \"サブルール\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid   \"[empty]\"\nmsgstr  \"[空]\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"Solaarルールエディタ\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Make changes permanent?\"\nmsgstr  \"変更を保存しますか？\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid   \"Yes\"\nmsgstr  \"はい\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid   \"No\"\nmsgstr  \"いいえ\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"[いいえ]を選択すると、Solaarを閉じるときに変更が失われます。\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid   \"Save changes\"\nmsgstr  \"保存\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid   \"Discard changes\"\nmsgstr  \"変更を破棄\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid   \"Insert here\"\nmsgstr  \"ここに挿入\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid   \"Insert above\"\nmsgstr  \"上に挿入\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid   \"Insert below\"\nmsgstr  \"下に挿入\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid   \"Insert new rule here\"\nmsgstr  \"新しいルールをここに挿入\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid   \"Insert new rule above\"\nmsgstr  \"新しいルールを上に挿入\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Insert new rule below\"\nmsgstr  \"新しいルールを下に挿入\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid   \"Paste here\"\nmsgstr  \"ここに貼り付け\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid   \"Paste above\"\nmsgstr  \"上に貼り付け\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid   \"Paste below\"\nmsgstr  \"下に貼り付け\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid   \"Paste rule here\"\nmsgstr  \"ここにルールを貼り付け\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid   \"Paste rule above\"\nmsgstr  \"上にルールを貼り付け\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Paste rule below\"\nmsgstr  \"下にルールを貼り付け\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid   \"Paste rule\"\nmsgstr  \"ルールを貼り付け\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid   \"Flatten\"\nmsgstr  \"フラット化\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Insert\"\nmsgstr  \"挿入\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Or\"\nmsgstr  \"どれか\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid   \"And\"\nmsgstr  \"すべて\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid   \"Condition\"\nmsgstr  \"状態\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid   \"Feature\"\nmsgstr  \"機能\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid   \"Report\"\nmsgstr  \"通知\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid   \"Process\"\nmsgstr  \"プロセス\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid   \"Mouse process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid   \"Modifiers\"\nmsgstr  \"修飾キー\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid   \"Key\"\nmsgstr  \"キー\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid   \"KeyIsDown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid   \"Active\"\nmsgstr  \"有効\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid   \"Device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid   \"Setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid   \"Test\"\nmsgstr  \"評価\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid   \"Test bytes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid   \"Mouse Gesture\"\nmsgstr  \"マウスジェスチャー\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid   \"Action\"\nmsgstr  \"アクション\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid   \"Key press\"\nmsgstr  \"キー押下\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid   \"Mouse scroll\"\nmsgstr  \"マウススクロール\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid   \"Mouse click\"\nmsgstr  \"マウスクリック\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Set\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid   \"Execute\"\nmsgstr  \"実行\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Later\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Insert new rule\"\nmsgstr  \"新しいルールを挿入\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid   \"Delete\"\nmsgstr  \"削除\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid   \"Negate\"\nmsgstr  \"否\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid   \"Wrap with\"\nmsgstr  \"次で覆う\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid   \"Cut\"\nmsgstr  \"切り取り\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid   \"Paste\"\nmsgstr  \"貼り付け\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid   \"Copy\"\nmsgstr  \"コピー\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"このエディタは、選択したルールコンポーネントをまだサポートしていませ\"\n        \"ん。\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid   \"Number of seconds to delay.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid   \"Not\"\nmsgstr  \"否\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid   \"MouseProcess\"\nmsgstr  \"マウスプロセス\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid   \"Key down\"\nmsgstr  \"押す\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid   \"Key up\"\nmsgstr  \"離す\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid   \"Parameter\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid   \"begin (inclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid   \"end (exclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid   \"range\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid   \"minimum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid   \"maximum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid   \"mask\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid   \"type\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid   \"Add movement\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid   \"Add key\"\nmsgstr  \"キー追加\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid   \"Click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid   \"Depress\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid   \"Release\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid   \"Button\"\nmsgstr  \"ボタン\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid   \"Count and Action\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid   \"Add argument\"\nmsgstr  \"引数を追加\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"Toggle\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"True\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid   \"False\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid   \"Unsupported setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid   \"Originating device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid   \"Name of host computer.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid   \"Value\"\nmsgstr  \"値\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid   \"Item\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid   \"Change setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid   \"Setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid   \"offline\"\nmsgstr  \"未接続\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"%(receiver_name)s: 新しいデバイスをペアリング\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"left\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"right\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid   \"Pairing failed\"\nmsgstr  \"ペアリング失敗\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"デバイスが範囲内にあり、適切なバッテリー充電が行われていることを確認\"\n        \"してください。\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"新しいデバイスが検出されましたが、このレシーバーと互換性がありませ\"\n        \"ん。\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"レシーバーのサポートより多くペアリングされたデバイス。\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"エラーに関するこれ以上の詳細はありません。\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid   \"Found a new device:\"\nmsgstr  \"新しいデバイスが見つかりました:\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"この無線通信は暗号化されていません\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid   \"You may have to first turn the device off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid   \"Turn on the device you want to pair.\"\nmsgstr  \"ペアリングしたいデバイスの電源を入れて下さい。\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"デバイスの電源が既にオンになっている場合、オフにしてからもう一度オン\"\n        \"にします。\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\\n\"\n        \"\\n\"\n        \"このレシーバーはあと %d デバイスとペアリングできます。\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid   \"No supported device found\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"%sについて\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"%sを終了\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid   \"no receiver\"\nmsgstr  \"レシーバーなし\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid   \"no status\"\nmsgstr  \"ステータスなし\"\n\n#: lib/solaar/ui/window.py:96\nmsgid   \"Scanning\"\nmsgstr  \"スキャン中\"\n\n#: lib/solaar/ui/window.py:129\nmsgid   \"Battery\"\nmsgstr  \"バッテリー\"\n\n#: lib/solaar/ui/window.py:132\nmsgid   \"Wireless Link\"\nmsgstr  \"無線通信\"\n\n#: lib/solaar/ui/window.py:136\nmsgid   \"Lighting\"\nmsgstr  \"照明\"\n\n#: lib/solaar/ui/window.py:170\nmsgid   \"Show Technical Details\"\nmsgstr  \"技術的な詳細を表示\"\n\n#: lib/solaar/ui/window.py:186\nmsgid   \"Pair new device\"\nmsgstr  \"デバイスの追加\"\n\n#: lib/solaar/ui/window.py:205\nmsgid   \"Select a device\"\nmsgstr  \"デバイスを選択して下さい\"\n\n#: lib/solaar/ui/window.py:322\nmsgid   \"Rule Editor\"\nmsgstr  \"ルールエディタ\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Path\"\nmsgstr  \"Path\"\n\n#: lib/solaar/ui/window.py:536\nmsgid   \"USB ID\"\nmsgstr  \"USB ID\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid   \"Serial\"\nmsgstr  \"Serial\"\n\n#: lib/solaar/ui/window.py:545\nmsgid   \"Index\"\nmsgstr  \"Index\"\n\n#: lib/solaar/ui/window.py:547\nmsgid   \"Wireless PID\"\nmsgstr  \"Wireless PID\"\n\n#: lib/solaar/ui/window.py:549\nmsgid   \"Product ID\"\nmsgstr  \"Product ID\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Protocol\"\nmsgstr  \"Protocol\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Unknown\"\nmsgstr  \"Unknown\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid   \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr  \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#: lib/solaar/ui/window.py:554\nmsgid   \"Polling rate\"\nmsgstr  \"Polling rate\"\n\n#: lib/solaar/ui/window.py:565\nmsgid   \"Unit ID\"\nmsgstr  \"Unit ID\"\n\n#: lib/solaar/ui/window.py:576\nmsgid   \"none\"\nmsgstr  \"none\"\n\n#: lib/solaar/ui/window.py:577\nmsgid   \"Notifications\"\nmsgstr  \"Notifications\"\n\n#: lib/solaar/ui/window.py:621\nmsgid   \"No device paired.\"\nmsgstr  \"ペアリングされたデバイスはありません。\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"このレシーバーは最大 %(max_count)s デバイスとペアリングできま\"\n        \"す。\"\n\n#: lib/solaar/ui/window.py:634\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"このレシーバーは１つのデバイスのみとペアリングできます。\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"このレシーバーはあと %d デバイスとペアリングできます。\"\n\n#: lib/solaar/ui/window.py:692\nmsgid   \"Battery Voltage\"\nmsgstr  \"バッテリー電圧\"\n\n#: lib/solaar/ui/window.py:694\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"バッテリーから報告された電圧\"\n\n#: lib/solaar/ui/window.py:696\nmsgid   \"Battery Level\"\nmsgstr  \"バッテリー残量\"\n\n#: lib/solaar/ui/window.py:698\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"バッテリーから報告されたおおよその残量\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid   \"next reported \"\nmsgstr  \"〜 \"\n\n#: lib/solaar/ui/window.py:708\nmsgid   \" and next level to be reported.\"\nmsgstr  \" と 次に報告される残量。\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"last known\"\nmsgstr  \"最後に認識された値\"\n\n#: lib/solaar/ui/window.py:724\nmsgid   \"encrypted\"\nmsgstr  \"暗号化あり\"\n\n#: lib/solaar/ui/window.py:726\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"このデバイスとレシーバー間の通信は暗号化されています。\"\n\n#: lib/solaar/ui/window.py:728\nmsgid   \"not encrypted\"\nmsgstr  \"暗号化なし\"\n\n#: lib/solaar/ui/window.py:732\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"%(light_level)d ルクス\"\n\n#~ msgid        \"Add action\"\n#~ msgstr       \"操作追加\"\n\n#~ msgid        \"Adjust the DPI by sliding the mouse horizontally while \"\n#~      \"holding the button down.\"\n#~ msgstr       \"ボタンを押したままマウスを横に動かすことで感度(DPI)を調整しま\"\n#~      \"す。\"\n\n#~ msgid        \"Automatically switch the mouse wheel between ratchet and \"\n#~      \"freespin mode.\\n\"\n#~      \"The mouse wheel is always free at 0, and always ratcheted at 50\"\n#~ msgstr       \"マウスホイールのラチェットモードとフリースピンモードを自動的\"\n#~      \"に切り替えます。\\n\"\n#~      \"0で常にフリー、50で常にラチェットモードになります\"\n\n#~ msgid        \"Battery information unknown.\"\n#~ msgstr       \"バッテリー情報は不明です。\"\n\n#~ msgid        \"Count\"\n#~ msgstr       \"回数\"\n\n#~ msgid        \"DPI Sliding Adjustment\"\n#~ msgstr       \"DPIスライディング調整\"\n\n#~ msgid        \"ERROR: \"\n#~ msgstr       \"エラー: \"\n\n#~ msgid        \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr       \"事実上、Linuxでサムスクロールをオフにします。\"\n\n#~ msgid        \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr       \"事実上Linuxでのホイールスクロールを無効にします。\"\n\n#~ msgid        \"For more information see the Solaar installation directions\\n\"\n#~      \"at https://pwr-solaar.github.io/Solaar/installation\"\n#~ msgstr       \"詳細については、下記よりSolaarのインストール手順を参照してく\"\n#~      \"ださい\\n\"\n#~      \"https://pwr-solaar.github.io/Solaar/installation\"\n\n#, python-format\n#~ msgid        \"Found a Logitech Receiver (%s), but did not have permission \"\n#~      \"to open it.\"\n#~ msgstr       \"Logitechレシーバー (%s) が見つかりましたが、開く権限がありま\"\n#~      \"せんでした。\"\n\n#~ msgid        \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr       \"ホイールでのHID++モード縦スクロール。\"\n\n#~ msgid        \"If you've just installed Solaar, try removing the receiver \"\n#~      \"and plugging it back in.\"\n#~ msgstr       \"Solaarをインストールしたばかりの場合は、レシーバーを取り外し\"\n#~      \"て、再び接続してみてください。\"\n\n#~ msgid        \"Make the key or button send HID++ notifications (which \"\n#~      \"trigger Solaar rules but are otherwise ignored).\"\n#~ msgstr       \"キーまたはボタンにHID ++通知を送信させます（Solaarルールをト\"\n#~      \"リガーしますが、それ以外の場合は無視されます）。\"\n\n#~ msgid        \"No Logitech receiver found\"\n#~ msgstr       \"Logitechレシーバーが見つかりません\"\n\n#~ msgid        \"Scroll Wheel HID++ Scrolling\"\n#~ msgstr       \"HID++スクロールホイール\"\n\n#~ msgid        \"Scroll Wheel Rachet\"\n#~ msgstr       \"スクロールホイールラチェット\"\n\n#~ msgid        \"Send a gesture by sliding the mouse while holding the button \"\n#~      \"down.\"\n#~ msgstr       \"ボタンを押したままマウスをスライドさせることで任意のジェス\"\n#~      \"チャーを送信します。\"\n\n#~ msgid        \"Solaar depends on a udev file that is not present\"\n#~ msgstr       \"Solaarは存在しないudevファイルに依存しています\"\n\n#~ msgid        \"The wireless link between this device and its receiver is \"\n#~      \"not encrypted.\\n\"\n#~      \"\\n\"\n#~      \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~      \"security issue.\\n\"\n#~      \"\\n\"\n#~      \"It is, however, a major security issue for text-input devices \"\n#~      \"(keyboards, numpads),\\n\"\n#~      \"because typed text can be sniffed inconspicuously by 3rd parties \"\n#~      \"within range.\"\n#~ msgstr       \"このデバイスとレシーバー間の無線通信は暗号化されていませ\"\n#~      \"ん。\\n\"\n#~      \"\\n\"\n#~      \"ポインティングデバイス（マウス、トラックボール、トラックパッド）の場\"\n#~      \"合、重大ではありませんがセキュリティの問題があります。\\n\"\n#~      \"\\n\"\n#~      \"テキスト入力デバイス（キーボード、テンキー）の場合、重要なセキュリ\"\n#~      \"ティの問題があります。\\n\"\n#~      \"入力した文字は、範囲内の第三者によって盗聴される可能性があります。\"\n\n#~ msgid        \"Try removing the device and plugging it back in or turning \"\n#~      \"it off and then on.\"\n#~ msgstr       \"デバイスを取り外して再度接続するか、電源をオフにしてからオン\"\n#~      \"にしてみてください。\"\n\n#~ msgid        \"height\"\n#~ msgstr       \"高さ\"\n\n#~ msgid        \"unknown\"\n#~ msgstr       \"不明\"\n\n#~ msgid        \"width\"\n#~ msgstr       \"幅\"\n"
  },
  {
    "path": "po/ka.po",
    "content": "# translation of solaar to Georgian\n# Copyright (C) 2026 solaar's authors\n# This file is distributed under the same license as the solaar package.\n# Ekaterine Papava <papava.e@gtu.ge>, 2026.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 1.1.17rc3\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-01 21:43+0300\\n\"\n\"PO-Revision-Date: 2026-01-07 16:55+0100\\n\"\n\"Last-Translator: Ekaterine Papava <papava.e@gtu.ge>\\n\"\n\"Language-Team: Georgian <(nothing)>\\n\"\n\"Language: ka\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.8\\n\"\n\n#: lib/logitech_receiver/base_usb.py:52\nmsgid \"Bolt Receiver\"\nmsgstr \"Bolt მიმღები\"\n\n#: lib/logitech_receiver/base_usb.py:64\nmsgid \"Unifying Receiver\"\nmsgstr \"Unifying მიმღები\"\n\n#: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87\n#: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113\nmsgid \"Nano Receiver\"\nmsgstr \"Nano მიმღები\"\n\n#: lib/logitech_receiver/base_usb.py:125\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Lightspeed მიმღები\"\n\n#: lib/logitech_receiver/base_usb.py:135\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"EX100 მიმღები 27 მჰც\"\n\n#: lib/logitech_receiver/common.py:649\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"ელემენტი: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:652\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"ელემენტი: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:1048\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid \"Disabled\"\nmsgstr \"გამორთულია\"\n\n#: lib/logitech_receiver/hidpp20.py:1049\nmsgid \"Static\"\nmsgstr \"სტატიკური\"\n\n#: lib/logitech_receiver/hidpp20.py:1050\nmsgid \"Pulse\"\nmsgstr \"პულსი\"\n\n#: lib/logitech_receiver/hidpp20.py:1051\nmsgid \"Cycle\"\nmsgstr \"ციკლი\"\n\n#: lib/logitech_receiver/hidpp20.py:1052\nmsgid \"Boot\"\nmsgstr \"ჩატვირთვა\"\n\n#: lib/logitech_receiver/hidpp20.py:1053\nmsgid \"Demo\"\nmsgstr \"დემო\"\n\n#: lib/logitech_receiver/hidpp20.py:1055\nmsgid \"Breathe\"\nmsgstr \"სუნთქვა\"\n\n#: lib/logitech_receiver/hidpp20.py:1058\nmsgid \"Ripple\"\nmsgstr \"ჭავლი\"\n\n#: lib/logitech_receiver/hidpp20.py:1059\nmsgid \"Decomposition\"\nmsgstr \"დაშლა\"\n\n#: lib/logitech_receiver/hidpp20.py:1060\nmsgid \"Signature1\"\nmsgstr \"ხელმოწერა1\"\n\n#: lib/logitech_receiver/hidpp20.py:1061\nmsgid \"Signature2\"\nmsgstr \"ხელმოწერა2\"\n\n#: lib/logitech_receiver/hidpp20.py:1062\nmsgid \"CycleS\"\nmsgstr \"ციკლები\"\n\n#: lib/logitech_receiver/hidpp20.py:1126\nmsgid \"Unknown Location\"\nmsgstr \"უცნობი მდებარეობა\"\n\n#: lib/logitech_receiver/hidpp20.py:1127\nmsgid \"Primary\"\nmsgstr \"ძირითადი\"\n\n#: lib/logitech_receiver/hidpp20.py:1128\nmsgid \"Logo\"\nmsgstr \"ლოგო\"\n\n#: lib/logitech_receiver/hidpp20.py:1129\nmsgid \"Left Side\"\nmsgstr \"მარცხენა მხარე\"\n\n#: lib/logitech_receiver/hidpp20.py:1130\nmsgid \"Right Side\"\nmsgstr \"მარჯვენა მხარე\"\n\n#: lib/logitech_receiver/hidpp20.py:1131\nmsgid \"Combined\"\nmsgstr \"კომბინირებული\"\n\n#: lib/logitech_receiver/hidpp20.py:1132\nmsgid \"Primary 1\"\nmsgstr \"ძირითადი 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1133\nmsgid \"Primary 2\"\nmsgstr \"ძირითადი 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1134\nmsgid \"Primary 3\"\nmsgstr \"ძირითადი 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1135\nmsgid \"Primary 4\"\nmsgstr \"ძირითადი 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1136\nmsgid \"Primary 5\"\nmsgstr \"ძირითადი 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1137\nmsgid \"Primary 6\"\nmsgstr \"ძირითადი 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"ცარიელია\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"კრიტიკული\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"დაბალი\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"საშუალო\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"კარგი\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"მთლიანი\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"იცლება\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"თავიდან დატენვა\"\n\n#: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700\nmsgid \"charging\"\nmsgstr \"იტენება\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"არ იტენება\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"თითქმის სავსეა\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"დამუხტული\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"ნელი თავიდან დატენვა\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"invalid battery\"\nmsgstr \"არასწორი ელემენტი\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"თერმალის შეცდომა\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"შეცდომა\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"სტანდარტული\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"სწრაფი\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"ნელი\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"მოწყობილობის მოლოდინის დრო ამოიწურა\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"მოწყობილობა მხარდაჭერილი არაა\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"მეტისმეტად ბევრი მოწყობილობა\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"მიმდევრობის მოლოდინის ვადა ამოიწურა\"\n\n#: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555\nmsgid \"Firmware\"\nmsgstr \"მიკროკოდი\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"ჩამტვირთავი\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"აპარატურა\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"სხვა\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"მარცხენა ღილაკი\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"მარჯვენა ღილაკი\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"შუა ღილაკი\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"ღილაკი უკან\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"ღილაკი წინ\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"თაგუნას ჟესტის ღილაკი\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"ჭკვიანი გადასვლა\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"DPI გადამრთველი\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"მარცხნივ დახრა\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"მარჯვნივ დახრა\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"მარცხენა-წკაპი\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"მარჯვენა-წკაპი\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"თაგუნას შუა ღილაკი\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"თაგუნას ღილაკი 'უკან'\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"თაგუნას ღილაკი 'წუნ'\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"ნავიგაცია ჟესტის ღილაკით\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"თაგუნას მარცხნივ გადახვევის ღილაკი\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"თაგუნას მარჯვნივ გადახვევის ღილაკი\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"დაწოლილი\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"აშვებულია\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"connected\"\nmsgstr \"დაკავშირებულია\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"disconnected\"\nmsgstr \"გათიშულია\"\n\n#: lib/logitech_receiver/notifications.py:182\nmsgid \"unpaired\"\nmsgstr \"დაუწყვილებელია\"\n\n#: lib/logitech_receiver/notifications.py:231\nmsgid \"powered on\"\nmsgstr \"ჩართულია\"\n\n#: lib/logitech_receiver/notifications.py:283\nmsgid \"ADC measurement notification\"\nmsgstr \"ADC გაზომვის გაფრთხილება\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:483\nmsgid \"pairing lock is closed\"\nmsgstr \"დაწყვილება დაბლოკილია\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:483\nmsgid \"pairing lock is open\"\nmsgstr \"დაწყვილება ჩართულია\"\n\n#: lib/logitech_receiver/notifications.py:446\nmsgid \"discovery lock is closed\"\nmsgstr \"აღმოჩენა დაბლოკილია\"\n\n#: lib/logitech_receiver/notifications.py:446\nmsgid \"discovery lock is open\"\nmsgstr \"აღმოჩენა ჩართულია\"\n\n#: lib/logitech_receiver/receiver.py:437\nmsgid \"No paired devices.\"\nmsgstr \"შეწყვილებული მოწყობილობების გარეშე.\"\n\n#: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s დაწყვილებული მოწყობილობა.\"\nmsgstr[1] \"%(count)s დაწყვილებული მოწყობილობა.\"\n\n#: lib/logitech_receiver/settings.py:602\nmsgid \"register\"\nmsgstr \"რეგისტრაცია\"\n\n#: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654\nmsgid \"feature\"\nmsgstr \"თვისება\"\n\n#: lib/logitech_receiver/settings_templates.py:138\nmsgid \"Swap Fx function\"\nmsgstr \"Fx-ის ფუნქციის გაცვლა\"\n\n#: lib/logitech_receiver/settings_templates.py:141\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"როცა დაყენებულია, ღილაკები F1..F12 თავიანთ სპეციალურ ფუნქციას გაააქტიურებენ\\n\"\n\"და თქვენ უნდა გეჭიროთ FN ღილაკზე, რომ მათი სტანდარტული ფუნქცია გაააქტიუროთ.\"\n\n#: lib/logitech_receiver/settings_templates.py:146\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"როცა დაყენებულია, ღილაკები F1..F12 თავიანთ სტანდარტული ფუნქციას \"\n\"გაააქტიურებენ\\n\"\n\"და თქვენ უნდა გეჭიროთ FN ღილაკზე, რომ მათი სპეციალურ ფუნქცია გაააქტიუროთ.\"\n\n#: lib/logitech_receiver/settings_templates.py:154\nmsgid \"Hand Detection\"\nmsgstr \"ხელის ამოცნობა\"\n\n#: lib/logitech_receiver/settings_templates.py:155\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"ილუმინაციის ჩართვა, როცა ხელებს კლავიატურაზე გააჩერებთ.\"\n\n#: lib/logitech_receiver/settings_templates.py:162\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"გლუვი გადახვევა თაგუნას ბორბლით\"\n\n#: lib/logitech_receiver/settings_templates.py:163\n#: lib/logitech_receiver/settings_templates.py:410\n#: lib/logitech_receiver/settings_templates.py:439\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"მაღალი მგრძნობელობის რეჟიმი ბორბლით ვერტიკალური გადახვევისთვის.\"\n\n#: lib/logitech_receiver/settings_templates.py:170\nmsgid \"Side Scrolling\"\nmsgstr \"გვერდზე გადახვევა\"\n\n#: lib/logitech_receiver/settings_templates.py:172\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"როცა გამორთულია, ბორბლის გვერდზე დაჭერა მომხმარებლის ღილაკის მოვლენებს\\n\"\n\"აგზავნის სტანდარტული გვერდზე გადახვევის მოვლენების მაგიერ.\"\n\n#: lib/logitech_receiver/settings_templates.py:182\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"მგრძნობელობა (DPI - ძველი თაგუნები)\"\n\n#: lib/logitech_receiver/settings_templates.py:183\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"თაგუნას მოძრაობის მგრძნობელობა\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid \"Backlight Timed\"\nmsgstr \"შენათების დრო\"\n\n#: lib/logitech_receiver/settings_templates.py:257\n#: lib/logitech_receiver/settings_templates.py:397\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"განათების დროის დაყენება კლავიატურისთვის.\"\n\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid \"Backlight\"\nmsgstr \"შენათება\"\n\n#: lib/logitech_receiver/settings_templates.py:269\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"\"\n\"განათების დონე კლავიატურაზე.  ცვლილებები ძალაში, მხოლოდ, 'ხელით' რეჟიმში \"\n\"შედის.\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid \"Automatic\"\nmsgstr \"ავტომატური\"\n\n#: lib/logitech_receiver/settings_templates.py:303\nmsgid \"Manual\"\nmsgstr \"ხელით\"\n\n#: lib/logitech_receiver/settings_templates.py:305\nmsgid \"Enabled\"\nmsgstr \"ჩართულია\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid \"Backlight Level\"\nmsgstr \"შენათების დონე\"\n\n#: lib/logitech_receiver/settings_templates.py:312\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"განათების დონე კლავიატურაზე რეჟიმში 'ხელით'.\"\n\n#: lib/logitech_receiver/settings_templates.py:369\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"შენათების დაყოვნება ხელების გაწევისას\"\n\n#: lib/logitech_receiver/settings_templates.py:370\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"\"\n\"დაყოვნება წამებში, სანამ მოხდება შენათების მინავლება, როცა ხელებს \"\n\"კლავიატურიდან შორს წაიღებთ.\"\n\n#: lib/logitech_receiver/settings_templates.py:378\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"შენათების დაყოვნება ხელების მიახლოებისას\"\n\n#: lib/logitech_receiver/settings_templates.py:379\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"\"\n\"დაყოვნება წამებში, სანამ მოხდება შენათების გამოჩენა, როცა ხელებს \"\n\"კლავიატურასთან მიიტანთ.\"\n\n#: lib/logitech_receiver/settings_templates.py:387\nmsgid \"Backlight Delay Powered\"\nmsgstr \"შენათების ჩართვის დაყოვნება\"\n\n#: lib/logitech_receiver/settings_templates.py:388\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"დაყოვნება წამებში, სანამ მოხდება შენათების მინავლება გარე კვებით.\"\n\n#: lib/logitech_receiver/settings_templates.py:396\nmsgid \"Backlight (Seconds)\"\nmsgstr \"შენათება (წმ)\"\n\n#: lib/logitech_receiver/settings_templates.py:408\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"გადახვევის ბორბლის მაღალი გარჩევადობა\"\n\n#: lib/logitech_receiver/settings_templates.py:412\n#: lib/logitech_receiver/settings_templates.py:441\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"დააყენეთ დაიგნორებაზე, თუ გადახვევა არანორმალურად სწრაფი, ან ნელია\"\n\n#: lib/logitech_receiver/settings_templates.py:419\n#: lib/logitech_receiver/settings_templates.py:450\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"გადახვევის ბორბლის ქცევა\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"ბორბლისთვის LOWRES_WHEEL HID++ გაფრთხილების გაგზავნის იძულება (რომელიც \"\n\"გაუშვებს Solaar-ის წესებს, მაგრამ სხვაგვარად ყურადღებას არაფერი აქცევს).\"\n\n#: lib/logitech_receiver/settings_templates.py:428\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"გადახვევის ბორბლის მიმართულება\"\n\n#: lib/logitech_receiver/settings_templates.py:429\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"ბორბლით ვერტიკალური გადახვევის მიმართულების ინვერსია.\"\n\n#: lib/logitech_receiver/settings_templates.py:437\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"გადახვევის ბორბლის გარჩევადობა\"\n\n#: lib/logitech_receiver/settings_templates.py:452\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"ბორბლისთვის HIRES_WHEEL HID++ გაფრთხილების გაგზავნის იძულება (რომელიც \"\n\"გაუშვებს Solaar-ის წესებს, მაგრამ სხვაგვარად ყურადღებას არაფერი აქცევს).\"\n\n#: lib/logitech_receiver/settings_templates.py:461\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"მგრძნობელობა (მაჩვენებლის სიჩქარე)\"\n\n#: lib/logitech_receiver/settings_templates.py:462\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"სიჩქარის მამრავლი თაგუნასთვის (256 ნორმალური მამრავლია).\"\n\n#: lib/logitech_receiver/settings_templates.py:472\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"ცერა თითის ბორბლის ქცევა\"\n\n#: lib/logitech_receiver/settings_templates.py:474\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"ბორბლისთვის THUMB_WHEEL HID++ გაფრთხილების გაგზავნის იძულება (რომელიც \"\n\"გაუშვებს Solaar-ის წესებს, მაგრამ სხვაგვარად ყურადღებას არაფერი აქცევს).\"\n\n#: lib/logitech_receiver/settings_templates.py:483\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"ცერა თითის ბორბლის მიმართულება\"\n\n#: lib/logitech_receiver/settings_templates.py:484\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"ცერა თითის ბორბლით გადახვევის მიმართულების ინვერსია.\"\n\n#: lib/logitech_receiver/settings_templates.py:504\nmsgid \"Onboard Profiles\"\nmsgstr \"ჩაშენებული პროფილები\"\n\n#: lib/logitech_receiver/settings_templates.py:505\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"\"\n\"ჩაშენებული პროფილის ჩართვა, რომელიც მართავს ანგარიშების სიხშირეს, \"\n\"მგრძნობელობას და ღილაკის ქმედებებს\"\n\n#: lib/logitech_receiver/settings_templates.py:549\n#: lib/logitech_receiver/settings_templates.py:582\nmsgid \"Report Rate\"\nmsgstr \"ანგარიშის სიხშირე\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\nmsgid \"Frequency of device movement reports\"\nmsgstr \"მოწყობილობის მოძრაობის ანგარიშების სიხშირე\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1421\n#: lib/logitech_receiver/settings_templates.py:1452\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"\"\n\"იმისათვის, რომ ეფექტური იყოს, შეიძლება, ჩაშენებული პროფილების გამორთვა \"\n\"დასჭირდეს.\"\n\n#: lib/logitech_receiver/settings_templates.py:612\nmsgid \"Divert crown events\"\nmsgstr \"ვენიერის ქცევა\"\n\n#: lib/logitech_receiver/settings_templates.py:613\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"ვერნიერისთვის CROWN WHEEL HID++ გაფრთხილების გაგზავნის იძულება (რომელიც \"\n\"გაუშვებს Solaar-ის წესებს, მაგრამ სხვაგვარად ყურადღებას არაფერი აქცევს).\"\n\n#: lib/logitech_receiver/settings_templates.py:621\nmsgid \"Crown smooth scroll\"\nmsgstr \"ვენიერის გლუვი გადახვევა\"\n\n#: lib/logitech_receiver/settings_templates.py:622\nmsgid \"Set crown smooth scroll\"\nmsgstr \"ვენიერის გლუვი გადახვევის დაყენება\"\n\n#: lib/logitech_receiver/settings_templates.py:630\nmsgid \"Divert G and M Keys\"\nmsgstr \"G და M ღილაკების გადამისამართება\"\n\n#: lib/logitech_receiver/settings_templates.py:631\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"G და M ღილაკებისთვის WHEEL HID++ გაფრთხილების გაგზავნის იძულება (რომელიც \"\n\"გაუშვებს Solaar-ის წესებს, მაგრამ სხვაგვარად ყურადღებას არაფერი აქცევს).\"\n\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"ხრუტუნა მექანიზმით გადახვევის ბორბალი\"\n\n#: lib/logitech_receiver/settings_templates.py:646\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"\"\n\"თაგუნას ბორბლის გადართვა სიჩქარით მართულ ხრუტუნა მექანიზმსა და ყოველთვის \"\n\"თავისუფალ ტრიალს შორის.\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Freespinning\"\nmsgstr \"თავისუფალი ბრუნვა\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Ratcheted\"\nmsgstr \"ბრუნვა ხრუტუნა მექანიზმით\"\n\n#: lib/logitech_receiver/settings_templates.py:655\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"თაგუნას ბორბლის ტრიალის სიჩქარე\"\n\n#: lib/logitech_receiver/settings_templates.py:657\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"თაგუნას ბორბლის სიჩქარის გამოყენება ხრუტუნა მექანიზმსა და თავისუფლად ტრიალს \"\n\"შორის გადასართავად.\\n\"\n\"თაგუნას ბორბლის ხრუტუნა მექანიზმის სიჩქარე ყოველთვის 50-ს უდრის.\"\n\n#: lib/logitech_receiver/settings_templates.py:707\nmsgid \"Scroll Wheel Ratchet Torque\"\nmsgstr \"ხრუტუნა ბორბლით გადახვევის მოჭიდება\"\n\n#: lib/logitech_receiver/settings_templates.py:708\nmsgid \"Change the torque needed to overcome the ratchet.\"\nmsgstr \"ხრუტუნა ბორბლის გადასაფარად მოჭიდების შეცვლაა საწირო.\"\n\n#: lib/logitech_receiver/settings_templates.py:743\nmsgid \"Key/Button Actions\"\nmsgstr \"ღილაკის ქმედებები\"\n\n#: lib/logitech_receiver/settings_templates.py:745\nmsgid \"Change the action for the key or button.\"\nmsgstr \"ქმედების შეცვლა ღილაკისთვის.\"\n\n#: lib/logitech_receiver/settings_templates.py:747\nmsgid \"Overridden by diversion.\"\nmsgstr \"გადაფარულია გადამისამარტებით.\"\n\n#: lib/logitech_receiver/settings_templates.py:749\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"\"\n\"მნიშვნელოვანი ქმედებების შეცვლამ (მაგ: მარცხენა თაგუნას ღილაკისთვის), \"\n\"შეიძლება, სისტემის არასტაბილურობამდე მიგიყვანოთ.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid \"Key/Button Diversion\"\nmsgstr \"ღილაკის გადამისამართება\"\n\n#: lib/logitech_receiver/settings_templates.py:925\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse \"\n\"Gestures or Sliding DPI\"\nmsgstr \"\"\n\"ღილაკისთვის იძულება, HD++ გაფრთხილებები გააგზავნოს (გადამისამართებული) ან \"\n\"მოახდინოს თაგუნას ჟესტების ინიციაცია, ან სრიალა DPI-ის\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Diverted\"\nmsgstr \"გადამისამართებულია\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\nmsgid \"Mouse Gestures\"\nmsgstr \"თაგუნას ჟესტები\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Regular\"\nmsgstr \"ჩვეულებრივი\"\n\n#: lib/logitech_receiver/settings_templates.py:928\nmsgid \"Sliding DPI\"\nmsgstr \"მცურავი DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"მგრძნობელობა (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:1123\nmsgid \"Sensitivity Switching\"\nmsgstr \"მგრძნობელობის გადართვა\"\n\n#: lib/logitech_receiver/settings_templates.py:1125\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key \"\n\"or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\"მიმდინარე მგრძნობელობასა და დამახსოვრებულ მგრძნობელობას შორის გადართვა, როცა \"\n\"ღილაკს დააწვებით.\\n\"\n\"თუ დამახსოვრებული მგრძნობელობა არ არსებობს, მოხდება მიმდინარე მგრძნობელობის \"\n\"დამახსოვრება\"\n\n#: lib/logitech_receiver/settings_templates.py:1129\nmsgid \"Off\"\nmsgstr \"გამორთ\"\n\n#: lib/logitech_receiver/settings_templates.py:1160\nmsgid \"Disable keys\"\nmsgstr \"ღილაკების გათიშვა\"\n\n#: lib/logitech_receiver/settings_templates.py:1161\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"მითითებული კლავიატურის ღილაკების გამორთვა.\"\n\n#: lib/logitech_receiver/settings_templates.py:1164\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"გამორთავს ღილაკს %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1177\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid \"Set OS\"\nmsgstr \"ოპერაციული სისტემა\"\n\n#: lib/logitech_receiver/settings_templates.py:1178\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid \"Change keys to match OS.\"\nmsgstr \"ღილაკების შეცვლა ოს-თან შესაბამისად.\"\n\n#: lib/logitech_receiver/settings_templates.py:1247\nmsgid \"Change Host\"\nmsgstr \"ჰოსტის შეცვლა\"\n\n#: lib/logitech_receiver/settings_templates.py:1248\nmsgid \"Switch connection to a different host\"\nmsgstr \"კავშირის გადართვა სხვა ჰოსტზე\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Performs a left click.\"\nmsgstr \"შეასრულებს მარცხენა წკაპს.\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Single tap\"\nmsgstr \"ერთი ტყაპი\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Performs a right click.\"\nmsgstr \"შეასრულებს მარჯვენა წკაპს.\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Single tap with two fingers\"\nmsgstr \"ერთი ტყაპი ორი თითით\"\n\n#: lib/logitech_receiver/settings_templates.py:1274\nmsgid \"Single tap with three fingers\"\nmsgstr \"ერთი ტყაპი სამი თითით\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Double tap\"\nmsgstr \"ორმაგი ტყაპი\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Performs a double click.\"\nmsgstr \"შეასრულებს ორმაგ წკაპს.\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid \"Double tap with two fingers\"\nmsgstr \"ორმაგი ტყაპი ორი თითით\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Double tap with three fingers\"\nmsgstr \"ორმაგი ტყაპი სამი თითით\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"ელემენტების გადათრევა თითის გაწევით ორი ტყაპის შემდეგ.\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Tap and drag\"\nmsgstr \"დატყაპუნება და გადათრევა\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"დატყაპუნება და გადათრევა ორი თითით\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"გადაათრიეთ ელემენტები თითების გადათრევით ორმაგი დატყაპუნების შემდეგ.\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"დატყაპუნება და გადათრევა სამი თითით\"\n\n#: lib/logitech_receiver/settings_templates.py:1291\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"ტყაპუნის და წიბოს ჟესტების ჩახშობა\"\n\n#: lib/logitech_receiver/settings_templates.py:1292\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"\"\n\"გამორთავს დატყაპუნების და წიბოს ჟესტებს (იგივეა, რაც Fn+მარცხენაწკაპი).\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\nmsgid \"Scroll with one finger\"\nmsgstr \"გადახვევა ერთი თითით\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scrolls.\"\nmsgstr \"ვერტიკალური გადახვევა.\"\n\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scroll with two fingers\"\nmsgstr \"გადახვევა ორი თითით\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"ჰორიზონტალური გადახვევა ორი თითით\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scrolls horizontally.\"\nmsgstr \"ჰორიზონტალური გადახვევა.\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"ვერტიკალური გადახვევა ორი თითით\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scrolls vertically.\"\nmsgstr \"ვერტიკალური გადახვევა.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"გადახვევის მიმართულების ინვერსია.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Natural scrolling\"\nmsgstr \"ჩვეულებრივი გადახვევა\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"ჩართავს ცერა თითის ბორბალს.\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Thumbwheel\"\nmsgstr \"ცერა თითის ბორბალი\"\n\n#: lib/logitech_receiver/settings_templates.py:1311\n#: lib/logitech_receiver/settings_templates.py:1315\nmsgid \"Swipe from the top edge\"\nmsgstr \"გასმა ზედა წიბოდან\"\n\n#: lib/logitech_receiver/settings_templates.py:1312\nmsgid \"Swipe from the left edge\"\nmsgstr \"გასმა მარცხენა წიბოდან\"\n\n#: lib/logitech_receiver/settings_templates.py:1313\nmsgid \"Swipe from the right edge\"\nmsgstr \"გასმა მარჯვენა წიბოდან\"\n\n#: lib/logitech_receiver/settings_templates.py:1314\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"გასმა ქვედა წიბოდან\"\n\n#: lib/logitech_receiver/settings_templates.py:1316\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"ორი თითის გასმა მარცხენა წიბოდან\"\n\n#: lib/logitech_receiver/settings_templates.py:1317\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"ორი თითის გასმა მარჯვენა წიბოდან\"\n\n#: lib/logitech_receiver/settings_templates.py:1318\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"ორი თითის გასმა ქვედა წიბოდან\"\n\n#: lib/logitech_receiver/settings_templates.py:1319\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"ორი თითის გასმა ზედა წიბოდან\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"ჩქმეტა დასაპატარავებლად. გაწევა გასადიდებლად.\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\nmsgid \"Zoom with two fingers.\"\nmsgstr \"გადიდება ორი თითით.\"\n\n#: lib/logitech_receiver/settings_templates.py:1321\nmsgid \"Pinch to zoom out.\"\nmsgstr \"ჩქმეტა დასაპატარავებლად.\"\n\n#: lib/logitech_receiver/settings_templates.py:1322\nmsgid \"Spread to zoom in.\"\nmsgstr \"გადაშლა გასადიდებლად.\"\n\n#: lib/logitech_receiver/settings_templates.py:1323\nmsgid \"Zoom with three fingers.\"\nmsgstr \"გადიდება სამი თითით.\"\n\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Zoom with two fingers\"\nmsgstr \"გადიდება ორი თითით\"\n\n#: lib/logitech_receiver/settings_templates.py:1342\nmsgid \"Pixel zone\"\nmsgstr \"პიქსელების ზონა\"\n\n#: lib/logitech_receiver/settings_templates.py:1343\nmsgid \"Ratio zone\"\nmsgstr \"ფარდობის დონე\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Scale factor\"\nmsgstr \"გადიდების კოეფიციენტი\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Sets the cursor speed.\"\nmsgstr \"აყენებს კურსორის სიჩქარეს.\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left\"\nmsgstr \"მარცხენა\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left-most coordinate.\"\nmsgstr \"ყველაზე მარცხენა კოორდინატი.\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom\"\nmsgstr \"ქვემოთ\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom coordinate.\"\nmsgstr \"ქვედა კოორდინატი.\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width\"\nmsgstr \"სიგანე\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width.\"\nmsgstr \"სიგანე.\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height\"\nmsgstr \"სიმაღლე\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height.\"\nmsgstr \"სიმაღლე.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Cursor speed.\"\nmsgstr \"კურსორის სიჩქარე.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Scale\"\nmsgstr \"მასშტაბი\"\n\n#: lib/logitech_receiver/settings_templates.py:1358\nmsgid \"Gestures\"\nmsgstr \"ჟესტები\"\n\n#: lib/logitech_receiver/settings_templates.py:1359\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"თაგუნას/თაჩპედის ქცევის შეცვლა.\"\n\n#: lib/logitech_receiver/settings_templates.py:1375\nmsgid \"Gestures Diversion\"\nmsgstr \"ჟესტების ქცევა\"\n\n#: lib/logitech_receiver/settings_templates.py:1376\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"თაჩპედის/თაგუნას ჟესტების მორგება.\"\n\n#: lib/logitech_receiver/settings_templates.py:1392\nmsgid \"Gesture params\"\nmsgstr \"ჟესტის პარამეტრები\"\n\n#: lib/logitech_receiver/settings_templates.py:1393\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"თაგუნას/თაჩპედის რიცხვითი პარამეტრების შეცვლა.\"\n\n#: lib/logitech_receiver/settings_templates.py:1417\nmsgid \"M-Key LEDs\"\nmsgstr \"M-ღილაკის LED-ები\"\n\n#: lib/logitech_receiver/settings_templates.py:1419\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"M-ღილაკის LED-ების მართვა.\"\n\n#: lib/logitech_receiver/settings_templates.py:1423\n#: lib/logitech_receiver/settings_templates.py:1454\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"\"\n\"შეიძლება, იმისათვის, რომ ეფექტური იყოს, G ღილაკების გადამისამართება \"\n\"დაგჭირდეთ.\"\n\n#: lib/logitech_receiver/settings_templates.py:1429\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"აანთებს ღილაკს %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1448\nmsgid \"MR-Key LED\"\nmsgstr \"MR ღილაკის LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1450\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"MR ღილაკის LED-ის მართვა.\"\n\n#: lib/logitech_receiver/settings_templates.py:1471\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"მუდმივი ღილაკის ასახვა\"\n\n#: lib/logitech_receiver/settings_templates.py:1473\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"ღილაკის ასახვის მუდმივად შეცვლა.\"\n\n#: lib/logitech_receiver/settings_templates.py:1475\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"\"\n\"მნიშვნელოვანი ღილაკების შეცვლამ (მაგ: მარცხენა თაგუნას ღილაკისთვის), \"\n\"შეიძლება, სისტემის არასტაბილურობამდე მიგიყვანოთ.\"\n\n#: lib/logitech_receiver/settings_templates.py:1532\nmsgid \"Sidetone\"\nmsgstr \"თვითმოსმენა\"\n\n#: lib/logitech_receiver/settings_templates.py:1533\nmsgid \"Set sidetone level.\"\nmsgstr \"თვითმოსმენის დონის დაყენება.\"\n\n#: lib/logitech_receiver/settings_templates.py:1542\nmsgid \"Equalizer\"\nmsgstr \"ეკვალაიზერი\"\n\n#: lib/logitech_receiver/settings_templates.py:1543\nmsgid \"Set equalizer levels.\"\nmsgstr \"ეკვალაიზერის დონეების დაყენება.\"\n\n#: lib/logitech_receiver/settings_templates.py:1565\nmsgid \"Hz\"\nmsgstr \"ჰც\"\n\n#: lib/logitech_receiver/settings_templates.py:1571\nmsgid \"Power Management\"\nmsgstr \"კვების მართვა\"\n\n#: lib/logitech_receiver/settings_templates.py:1572\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"კვების გამორთვა მითითებულ წუთში (0 ნიშნავს 'არასდროს').\"\n\n#: lib/logitech_receiver/settings_templates.py:1584\nmsgid \"Brightness Control\"\nmsgstr \"სიკაშკაშის კონტროლი\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\nmsgid \"Control overall brightness\"\nmsgstr \"საერთო სიკაშკაშის მართვა\"\n\n#: lib/logitech_receiver/settings_templates.py:1628\n#: lib/logitech_receiver/settings_templates.py:1681\nmsgid \"LED Control\"\nmsgstr \"LED-ების მართვა\"\n\n#: lib/logitech_receiver/settings_templates.py:1629\n#: lib/logitech_receiver/settings_templates.py:1682\nmsgid \"Switch control of LED zones between device and Solaar\"\nmsgstr \"LED-ის ზონების კონტროლის გადართვა მოწყობილობასა და Solaar-ს შორის\"\n\n#: lib/logitech_receiver/settings_templates.py:1644\n#: lib/logitech_receiver/settings_templates.py:1692\nmsgid \"LED Zone Effects\"\nmsgstr \"LED-ის ზონის ეფექტები\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr \"იმისათვის, რომ ეფექტური იყოს, LED-ის მართვა Solaar-ზე უნდა დააყენოთ.\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"Set effect for LED Zone\"\nmsgstr \"ეფექტის დაყენება LED ზონისთვის\"\n\n#: lib/logitech_receiver/settings_templates.py:1647\nmsgid \"Color\"\nmsgstr \"ფერი\"\n\n#: lib/logitech_receiver/settings_templates.py:1648\nmsgid \"Speed\"\nmsgstr \"სიჩქარე\"\n\n#: lib/logitech_receiver/settings_templates.py:1649\nmsgid \"Period\"\nmsgstr \"პერიოდი\"\n\n#: lib/logitech_receiver/settings_templates.py:1650\nmsgid \"Intensity\"\nmsgstr \"ინტენსივობა\"\n\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid \"Ramp\"\nmsgstr \"პანდუსი\"\n\n#: lib/logitech_receiver/settings_templates.py:1666\nmsgid \"LEDs\"\nmsgstr \"LED-ები\"\n\n#: lib/logitech_receiver/settings_templates.py:1703\nmsgid \"Per-key Lighting\"\nmsgstr \"ინდივიდუალური განათება ღილაკებისთვის\"\n\n#: lib/logitech_receiver/settings_templates.py:1704\nmsgid \"Control per-key lighting.\"\nmsgstr \"ინდივიდუალური განათების კონტროლი ღილაკებისთვის.\"\n\n#: lib/logitech_receiver/settings_templates.py:1786\nmsgid \"Force Sensing Buttons\"\nmsgstr \"დაჭერის სენსორის მქონე ღილაკები\"\n\n#: lib/logitech_receiver/settings_templates.py:1787\nmsgid \"Change the force required to activate button.\"\nmsgstr \"აირჩიეთ ძალა, რომელიც საჭიროა ღილაკის გასააქტიურებლად.\"\n\n#: lib/logitech_receiver/settings_templates.py:1804\nmsgid \"Force Sensing Button\"\nmsgstr \"დაჭერის სენსორის მქონე ღილაკი\"\n\n#: lib/logitech_receiver/settings_templates.py:1814\nmsgid \"Haptic Feeback Level\"\nmsgstr \"ტაქტილური უკუკავშირის დონე\"\n\n#: lib/logitech_receiver/settings_templates.py:1815\nmsgid \"Change power of haptic feedback.  (Zero to turn off.)\"\nmsgstr \"ტაქტილური უკუკავშირის სიმძლავრის შეცვლა.  (0 გამოსართავად.)\"\n\n#: lib/logitech_receiver/settings_templates.py:1857\nmsgid \"Play Haptic Waveform\"\nmsgstr \"სიგნალის ტაქტილური ფორმის დაკვრა\"\n\n#: lib/logitech_receiver/settings_templates.py:1858\nmsgid \"Tell device to play a haptic waveform.\"\nmsgstr \"მოწყობილობისთვის ტაქტილური ფორმის სიგნალის ბრძანების გადაცემა.\"\n\n#: lib/solaar/ui/__init__.py:120\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"\"\n\"უკვე გაშვებულია Solaar-ის სხვა პროცესი, ასე რომ, უბრალოდ ამოკეცეთ ის ფანჯარა\"\n\n#: lib/solaar/ui/about/model.py:36\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"მართავს Logitech-ის მიმღებებს,\\n\"\n\"კლავიატურებს, თაგუნებს და ტაბლეტებს.\"\n\n#: lib/solaar/ui/about/model.py:63\nmsgid \"Additional Programming\"\nmsgstr \"დამატებითი პროგრამირება\"\n\n#: lib/solaar/ui/about/model.py:64\nmsgid \"GUI design\"\nmsgstr \"GUI-ის დიზაინი\"\n\n#: lib/solaar/ui/about/model.py:66\nmsgid \"Testing\"\nmsgstr \"ტესტირება\"\n\n#: lib/solaar/ui/about/model.py:74\nmsgid \"Logitech documentation\"\nmsgstr \"Logitech-ის დოკუმენტაცია\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92\n#: lib/solaar/ui/window.py:208\nmsgid \"Unpair\"\nmsgstr \"დაწყვილების მოხსნა\"\n\n#: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141\nmsgid \"Cancel\"\nmsgstr \"გაუქმება\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Permissions error\"\nmsgstr \"წვდომების შეცდომა\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"\"\n\"აღმოჩენილია Logitech-ის მიმღები, ან მოწყობილობა (%s), მაგრამ მისი გახსნის \"\n\"უფლება არ მაქვს.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"\"\n\"თუ Solaar ახლახან დააყენეთ, სცადეთ, გათიშოთ მიმღები, ან მოწყობილობა და \"\n\"შემდეგ თავიდან მიაერთეთ.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Cannot connect to device error\"\nmsgstr \"მოწყობილობასთან დაკავშირების შეცდომა\"\n\n#: lib/solaar/ui/common.py:51\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"ვიპოვნე Logitech მიმღები ან მოწყობილობა %s-ზე, მაგრამ დაკავშირებისას \"\n\"აღმოჩენილია შეცდომა.\"\n\n#: lib/solaar/ui/common.py:53\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"\"\n\"სცადეთ, გათიშოთ მოწყობილობა და თავიდან მიაერთოთ, ან გამორთეთ ის და თავიდან \"\n\"ჩართეთ.\"\n\n#: lib/solaar/ui/common.py:56\nmsgid \"Unpairing failed\"\nmsgstr \"დაწყვილების გაუქმება ჩავარდა\"\n\n#: lib/solaar/ui/common.py:58\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"%{receiver}-დან %{device}-ის დაწყვილების გაუმების შეცდომა.\"\n\n#: lib/solaar/ui/common.py:63\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"მიმღებმა დააბრუნა შეცდომა, მაგრამ დეტალების გარეშე.\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Complete - ENTER to change\"\nmsgstr \"დასრულდა - Enter შესაცვლელად\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Incomplete\"\nmsgstr \"არასრული\"\n\n#: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d მნიშვნელობა\"\nmsgstr[1] \"%d მნიშვნელობა\"\n\n#: lib/solaar/ui/config_panel.py:642\nmsgid \"Changes allowed\"\nmsgstr \"ცვლილებები დაშვებულია\"\n\n#: lib/solaar/ui/config_panel.py:643\nmsgid \"No changes allowed\"\nmsgstr \"ცვლილებები დაშვებული არაა\"\n\n#: lib/solaar/ui/config_panel.py:644\nmsgid \"Ignore this setting\"\nmsgstr \"ამ პარამეტრის გამოტოვება\"\n\n#: lib/solaar/ui/config_panel.py:690\nmsgid \"Working\"\nmsgstr \"მუშაობს\"\n\n#: lib/solaar/ui/config_panel.py:693\nmsgid \"Read/write operation failed.\"\nmsgstr \"წაკითხვა/ჩაწერის ოპერაცია ჩავარდა.\"\n\n#: lib/solaar/ui/desktop_notifications.py:112\nmsgid \"unspecified reason\"\nmsgstr \"დაუზუსტებელი მიზეზი\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"Built-in rules\"\nmsgstr \"ჩაშენებული წესები\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"User-defined rules\"\nmsgstr \"მომხმარებლის აღწერილი წესები\"\n\n#: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126\nmsgid \"Rule\"\nmsgstr \"წესი\"\n\n#: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382\n#: lib/solaar/ui/diversion_rules.py:509\nmsgid \"Sub-rule\"\nmsgstr \"ქვეწესი\"\n\n#: lib/solaar/ui/diversion_rules.py:108\nmsgid \"[empty]\"\nmsgstr \"[ცარიელი]\"\n\n#: lib/solaar/ui/diversion_rules.py:132\nmsgid \"Make changes permanent?\"\nmsgstr \"გახდეს ცვლილებები მუდმივი?\"\n\n#: lib/solaar/ui/diversion_rules.py:137\nmsgid \"Yes\"\nmsgstr \"დიახ\"\n\n#: lib/solaar/ui/diversion_rules.py:139\nmsgid \"No\"\nmsgstr \"არა\"\n\n#: lib/solaar/ui/diversion_rules.py:144\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"თუ აირჩევთ 'არას', ცვლილებები დაიკარგება, როცა Solaar-ს დახურავთ.\"\n\n#: lib/solaar/ui/diversion_rules.py:273\nmsgid \"Paste here\"\nmsgstr \"აქ ჩასმა\"\n\n#: lib/solaar/ui/diversion_rules.py:275\nmsgid \"Paste above\"\nmsgstr \"ზემოთ ჩასმა\"\n\n#: lib/solaar/ui/diversion_rules.py:277\nmsgid \"Paste below\"\nmsgstr \"ქვემოთ ჩასმა\"\n\n#: lib/solaar/ui/diversion_rules.py:283\nmsgid \"Paste rule here\"\nmsgstr \"წესის ჩასმა აქ\"\n\n#: lib/solaar/ui/diversion_rules.py:285\nmsgid \"Paste rule above\"\nmsgstr \"წესის ჩასმა ზემოთ\"\n\n#: lib/solaar/ui/diversion_rules.py:287\nmsgid \"Paste rule below\"\nmsgstr \"წესის ჩასმა ქვემოთ\"\n\n#: lib/solaar/ui/diversion_rules.py:291\nmsgid \"Paste rule\"\nmsgstr \"წესის ჩასმა\"\n\n#: lib/solaar/ui/diversion_rules.py:306\nmsgid \"Insert here\"\nmsgstr \"აქ ჩასმა\"\n\n#: lib/solaar/ui/diversion_rules.py:308\nmsgid \"Insert above\"\nmsgstr \"ზემოთ ჩასმა\"\n\n#: lib/solaar/ui/diversion_rules.py:310\nmsgid \"Insert below\"\nmsgstr \"ქვემოთ ჩასმა\"\n\n#: lib/solaar/ui/diversion_rules.py:316\nmsgid \"Insert new rule here\"\nmsgstr \"ახალი წესის ჩასმა აქ\"\n\n#: lib/solaar/ui/diversion_rules.py:318\nmsgid \"Insert new rule above\"\nmsgstr \"ახალი წესის ჩასმა ზემოთ\"\n\n#: lib/solaar/ui/diversion_rules.py:320\nmsgid \"Insert new rule below\"\nmsgstr \"ახალი წესის ჩასმა ქვემოთ\"\n\n#: lib/solaar/ui/diversion_rules.py:347\nmsgid \"Flatten\"\nmsgstr \"გაბრტყელება\"\n\n#: lib/solaar/ui/diversion_rules.py:380\nmsgid \"Insert\"\nmsgstr \"ჩასმა\"\n\n#: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511\n#: lib/solaar/ui/diversion_rules.py:1158\nmsgid \"Or\"\nmsgstr \"ან\"\n\n#: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510\n#: lib/solaar/ui/diversion_rules.py:1144\nmsgid \"And\"\nmsgstr \"და\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid \"Condition\"\nmsgstr \"პირობა\"\n\n#: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154\nmsgid \"Feature\"\nmsgstr \"თვისება\"\n\n#: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188\nmsgid \"Report\"\nmsgstr \"ანგარიში\"\n\n#: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69\nmsgid \"Process\"\nmsgstr \"პროცესი\"\n\n#: lib/solaar/ui/diversion_rules.py:391\nmsgid \"Mouse process\"\nmsgstr \"თაგუნას ქმედება\"\n\n#: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225\nmsgid \"Modifiers\"\nmsgstr \"მოდიფიკატორები\"\n\n#: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277\nmsgid \"Key\"\nmsgstr \"ღილაკი\"\n\n#: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318\nmsgid \"KeyIsDown\"\nmsgstr \"ღილაკი დაჭერილია\"\n\n#: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432\nmsgid \"Active\"\nmsgstr \"აქტიური\"\n\n#: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390\n#: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487\nmsgid \"Device\"\nmsgstr \"მოწყობილობა\"\n\n#: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467\nmsgid \"Host\"\nmsgstr \"ჰოსტი\"\n\n#: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506\nmsgid \"Setting\"\nmsgstr \"პარამეტრი\"\n\n#: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333\n#: lib/solaar/ui/rule_conditions.py:382\nmsgid \"Test\"\nmsgstr \"შემოწმება\"\n\n#: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507\nmsgid \"Test bytes\"\nmsgstr \"სატესტო ბაიტები\"\n\n#: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608\nmsgid \"Mouse Gesture\"\nmsgstr \"თაგუნას ჟესტი\"\n\n#: lib/solaar/ui/diversion_rules.py:405\nmsgid \"Action\"\nmsgstr \"ქმედება\"\n\n#: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138\nmsgid \"Key press\"\nmsgstr \"ღილაკის დაწოლა\"\n\n#: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191\nmsgid \"Mouse scroll\"\nmsgstr \"გადახვევა თაგუნათი\"\n\n#: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256\nmsgid \"Mouse click\"\nmsgstr \"თაგუნას წკაპი\"\n\n#: lib/solaar/ui/diversion_rules.py:410\nmsgid \"Set\"\nmsgstr \"დაყენება\"\n\n#: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328\nmsgid \"Execute\"\nmsgstr \"შესრულება\"\n\n#: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189\nmsgid \"Later\"\nmsgstr \"მოგვიანებით\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid \"Insert new rule\"\nmsgstr \"ახალი წესის ჩასმა\"\n\n#: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82\n#: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556\nmsgid \"Delete\"\nmsgstr \"წაშლა\"\n\n#: lib/solaar/ui/diversion_rules.py:483\nmsgid \"Negate\"\nmsgstr \"უარყოფა\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid \"Wrap with\"\nmsgstr \"ჩაკეცვა სად\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid \"Cut\"\nmsgstr \"ამოჭრა\"\n\n#: lib/solaar/ui/diversion_rules.py:553\nmsgid \"Paste\"\nmsgstr \"ჩასმა\"\n\n#: lib/solaar/ui/diversion_rules.py:559\nmsgid \"Copy\"\nmsgstr \"კოპირება\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Solaar-ის წესების რედაქტორი\"\n\n#: lib/solaar/ui/diversion_rules.py:668\nmsgid \"Save changes\"\nmsgstr \"ცვლილებების შენახვა\"\n\n#: lib/solaar/ui/diversion_rules.py:673\nmsgid \"Discard changes\"\nmsgstr \"ცვლილებების გაუქმება\"\n\n#: lib/solaar/ui/diversion_rules.py:1104\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"ამ რედაქტორს ჯერ არ აქვს მონიშნული წესის კომპონენტის მხარდაჭერა.\"\n\n#: lib/solaar/ui/diversion_rules.py:1169\nmsgid \"\"\n\"Number of seconds to delay.  Delay between 0 and 1 is done with higher \"\n\"precision.\"\nmsgstr \"\"\n\"დაყოვნების დრო წამებში.  დაყოვნება 0-სა და 1-ს შორის უფრო დიდი სიზუსტით \"\n\"ხდება.\"\n\n#: lib/solaar/ui/diversion_rules.py:1207\nmsgid \"Not\"\nmsgstr \"არ\"\n\n#: lib/solaar/ui/diversion_rules.py:1238\nmsgid \"Toggle\"\nmsgstr \"გადართვა\"\n\n#: lib/solaar/ui/diversion_rules.py:1239\nmsgid \"True\"\nmsgstr \"ჭეშმარიტი\"\n\n#: lib/solaar/ui/diversion_rules.py:1240\nmsgid \"False\"\nmsgstr \"მცდარი\"\n\n#: lib/solaar/ui/diversion_rules.py:1253\nmsgid \"Unsupported setting\"\nmsgstr \"მხარდაუჭერელი პარამეტრი\"\n\n#: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415\n#: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748\n#: lib/solaar/ui/diversion_rules.py:1766\nmsgid \"Originating device\"\nmsgstr \"წყარო მოწყობილობა\"\n\n#: lib/solaar/ui/diversion_rules.py:1428\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"მოწყობილობა აქტიურია და შეგიძლიათ, მისი პარამეტრები შეცვალოთ.\"\n\n#: lib/solaar/ui/diversion_rules.py:1437\nmsgid \"Device that originated the current notification.\"\nmsgstr \"მოწყობილობა, რომელიც მიმდინარე გაფრთხილებიდან დაიწყო.\"\n\n#: lib/solaar/ui/diversion_rules.py:1450\nmsgid \"Name of host computer.\"\nmsgstr \"მთავარი კომპიუტერის სახელი.\"\n\n#: lib/solaar/ui/diversion_rules.py:1520\nmsgid \"Value\"\nmsgstr \"მნიშვნელობა\"\n\n#: lib/solaar/ui/diversion_rules.py:1529\nmsgid \"Item\"\nmsgstr \"ელემენტი\"\n\n#: lib/solaar/ui/diversion_rules.py:1808\nmsgid \"Change setting on device\"\nmsgstr \"პარამეტრის შეცვლა მოწყობილობაზე\"\n\n#: lib/solaar/ui/diversion_rules.py:1824\nmsgid \"Setting on device\"\nmsgstr \"პარამეტრი მოწყობილობაზე\"\n\n#: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: ახალი მოწყობილობის დაწყვილება\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"ორივე მიმღები, მხოლოდ, Bolt მოწყობილობასთანაა თავსებადი.\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"\"\n\"დააჭირეთ დაწყვილების ღილაკს, სანამ დაწყვილების ნათურა სწრაფად არ აციმციმდება.\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"\"\n\"გაერთიანებული მიმღებები, მხოლოდ, გაერთიანებულ მოწყობილობებთანაა თავსებადი.\"\n\n#: lib/solaar/ui/pair_window.py:53\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"სხვა მიმღებები, მხოლოდ, რამდენიმე მოწყობილობასთანაა თავსებადი.\"\n\n#: lib/solaar/ui/pair_window.py:55\nmsgid \"For most devices, turn on the device you want to pair.\"\nmsgstr \"\"\n\"მოწყობილობების უმრავლესობისთვის, უბრალოდ ჩართეთ მოწყობილობა, რომლის \"\n\"დაწყვილებაც გნებავთ.\"\n\n#: lib/solaar/ui/pair_window.py:56\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"თუ მოწყობილობა უკვე ჩართულია, გამორთეთ და ისევ ჩართეთ.\"\n\n#: lib/solaar/ui/pair_window.py:58\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"მოწყობილობა არ უნდა იყოს დაწყვილებული ახლომდებარე ჩართულ მიმღებთან.\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid \"\"\n\"For devices with multiple channels, press, hold, and release the button for \"\n\"the channel you wish to pair\\n\"\n\"or use the channel switch button to select a channel and then press, hold, \"\n\"and release the channel switch button.\"\nmsgstr \"\"\n\"მრავალი არხის მქონე მოწყობილობებისთვის დააჭირეთ ღილაკს, გააჩერეთ და აუშვით \"\n\"ღილაკს იმ არხისთვის, რომლის დაწყვილებაც გსურთ\\n\"\n\"ან გამოიყენეთ არხის გადამრთველი ღილაკი არხის ასარჩევად და შემდეგ დააჭირეთ \"\n\"ღილაკს და აუშვით არხის გადართვის ღილაკს.\"\n\n#: lib/solaar/ui/pair_window.py:68\nmsgid \"The channel indicator light should be blinking rapidly.\"\nmsgstr \"არხის ინდიკატორის სინათლე სწრაფად უნდა ციმციმებდეს.\"\n\n#: lib/solaar/ui/pair_window.py:72\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"ამ მიმღებს %d დაწყვილება დარჩა.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"ამ მიმღებს %d დაწყვილება დარჩა.\"\n\n#: lib/solaar/ui/pair_window.py:78\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"ამ მომენტში გაუქმება დაწყვილებას არ გამოიყენებს.\"\n\n#: lib/solaar/ui/pair_window.py:168\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"შეიყვანეთ პაროლი %(name)s-ზე.\"\n\n#: lib/solaar/ui/pair_window.py:171\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"აკრიფეთ %(passcode)s და შემდეგ დააჭირეთ ღილაკს Enter.\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"left\"\nmsgstr \"მარცხენა\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"right\"\nmsgstr \"მარჯვენა\"\n\n#: lib/solaar/ui/pair_window.py:178\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"დააჭირეთ ღილაკს %(code)s\\n\"\n\"და შემდეგ დააჭირეთ მარცხენა და მარჯვენა ღილაკებს ერთდროულად.\"\n\n#: lib/solaar/ui/pair_window.py:221\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"უსადენო კავშირი დაშიფრული არაა\"\n\n#: lib/solaar/ui/pair_window.py:226\nmsgid \"Found a new device:\"\nmsgstr \"აღმოჩენილია ახალი მოწყობილობა:\"\n\n#: lib/solaar/ui/pair_window.py:247\nmsgid \"Pairing failed\"\nmsgstr \"დაწყვილება ჩავარდა\"\n\n#: lib/solaar/ui/pair_window.py:249\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"\"\n\"დარწმუნდით, რომ თქვენი მოწყობილობა ხელმისაწვდომ დაშორებაზეა და აქვს ელემენტი \"\n\"საკმარისადაა დამუხტული.\"\n\n#: lib/solaar/ui/pair_window.py:251\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"\"\n\"აღმოჩენილია ახალი მოწყობილობა, მაგრამ ის არ არის თავსებადი ამ მიმღებთან.\"\n\n#: lib/solaar/ui/pair_window.py:253\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"უფრო მეტი დაწყვილებული მოწყობილობა, ვიდრე მიმღებს შეუძლია მხარდაჭერა.\"\n\n#: lib/solaar/ui/pair_window.py:255\nmsgid \"No further details are available about the error.\"\nmsgstr \"შეცდომის შესახებ დამატებითი დეტალები ხელმისაწვდომი არაა.\"\n\n#: lib/solaar/ui/rule_actions.py:54\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"აკორდული ღილაკის დაწკაპუნების, დაჭერის ან აშვების სიმულაცია.\\n\"\n\"Wayland-ზე სჭირდება ჩაწერის უფლება სპეციალურ ფაილში /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:60\nmsgid \"Add key\"\nmsgstr \"გასაღების დამატება\"\n\n#: lib/solaar/ui/rule_actions.py:63\nmsgid \"Click\"\nmsgstr \"წკაპი\"\n\n#: lib/solaar/ui/rule_actions.py:66\nmsgid \"Depress\"\nmsgstr \"გაჭყლეტა\"\n\n#: lib/solaar/ui/rule_actions.py:69\nmsgid \"Release\"\nmsgstr \"რელიზი\"\n\n#: lib/solaar/ui/rule_actions.py:153\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"თაგუნას გადახვევის სიმულაცია.\\n\"\n\"Wayland-ზე სჭირდება ჩაწერის უფლება სპეციალურ ფაილში /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:211\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"თაგუნას დაწკაპუნების სიმულაცია.\\n\"\n\"Wayland-ზე სჭირდება ჩაწერის უფლება სპეციალურ ფაილში /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:216\nmsgid \"Button\"\nmsgstr \"ღილაკი\"\n\n#: lib/solaar/ui/rule_actions.py:218\nmsgid \"Action (and Count, if click)\"\nmsgstr \"ქმედება (და რაოდენობა, თუ წკაპია)\"\n\n#: lib/solaar/ui/rule_actions.py:269\nmsgid \"Execute a command with arguments.\"\nmsgstr \"ბრძანების შესრულება არგუმენტებით.\"\n\n#: lib/solaar/ui/rule_actions.py:273\nmsgid \"Add argument\"\nmsgstr \"არგუმენტის დამატება\"\n\n#: lib/solaar/ui/rule_conditions.py:52\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"X11-ის აქტიური პროცესი. გამოიყენება, მხოლოდ, X11-ში.\"\n\n#: lib/solaar/ui/rule_conditions.py:82\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"X11-ის თაგუნას პროცესი. გამოიყენება, მხოლოდ, X11-ში.\"\n\n#: lib/solaar/ui/rule_conditions.py:99\nmsgid \"MouseProcess\"\nmsgstr \"თაგუნას ქმედება\"\n\n#: lib/solaar/ui/rule_conditions.py:123\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"შეტყობინების ფუნქციის სახელი, რომელიც იწვევს წესის დამუშავებას.\"\n\n#: lib/solaar/ui/rule_conditions.py:169\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"წესის დამუშავების დამატრიგერებელი გაფრთხილებების რაოდენობის გადაცემა.\"\n\n#: lib/solaar/ui/rule_conditions.py:201\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"\"\n\"აქტიური კლავიატურის მოდიფიკატორების. Wayland-ზე ყოველთვის ხელმისაწვდომი არაა.\"\n\n#: lib/solaar/ui/rule_conditions.py:241\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"გადამისამართებულ ღილაკს დააწვნენ, ან აუშვეს.\\n\"\n\"ღილაკის გადამისამართების და G ღილაკის პარამეტრების გამოყენება ღილაკების \"\n\"გადამისამართებისთვის.\"\n\n#: lib/solaar/ui/rule_conditions.py:250\nmsgid \"Key down\"\nmsgstr \"ღილაკის დაჭერა\"\n\n#: lib/solaar/ui/rule_conditions.py:253\nmsgid \"Key up\"\nmsgstr \"ღილაკის გაშვება\"\n\n#: lib/solaar/ui/rule_conditions.py:293\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"გადამისამართებული ღილაკი ამჟამად დაჭერილია.\\n\"\n\"ღილაკის გადამისამართების და G ღილაკის პარამეტრების გამოყენება ღილაკების \"\n\"გადამისამართებისთვის.\"\n\n#: lib/solaar/ui/rule_conditions.py:331\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"სატესტო პირობა წესის დამუშავების გაფრთხილებაზე.\"\n\n#: lib/solaar/ui/rule_conditions.py:335\nmsgid \"Parameter\"\nmsgstr \"პარამეტრი\"\n\n#: lib/solaar/ui/rule_conditions.py:408\nmsgid \"begin (inclusive)\"\nmsgstr \"დასაწყისი (ჩათვლით)\"\n\n#: lib/solaar/ui/rule_conditions.py:409\nmsgid \"end (exclusive)\"\nmsgstr \"დასასრული (მხოლოდ)\"\n\n#: lib/solaar/ui/rule_conditions.py:417\nmsgid \"range\"\nmsgstr \"შუალედი\"\n\n#: lib/solaar/ui/rule_conditions.py:420\nmsgid \"minimum\"\nmsgstr \"მინიმუმი\"\n\n#: lib/solaar/ui/rule_conditions.py:421\nmsgid \"maximum\"\nmsgstr \"მაქსიმუმი\"\n\n#: lib/solaar/ui/rule_conditions.py:423\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"ბაიტი %(0)d-დან %(1)d-მდე, დაწყებული %(2)d-დან %(3)d-მდე\"\n\n#: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427\nmsgid \"mask\"\nmsgstr \"ნიღაბი\"\n\n#: lib/solaar/ui/rule_conditions.py:428\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"ბაიტი %(0)d-დან %(1)d-მდე, ნიღაბი %(2)d\"\n\n#: lib/solaar/ui/rule_conditions.py:437\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\"ბიტის ან დიაპაზონის ტესტი ბაიტებზე შეტყობინებების შეტყობინების გამომწვევი \"\n\"წესის დამუშავებაში.\"\n\n#: lib/solaar/ui/rule_conditions.py:447\nmsgid \"type\"\nmsgstr \"ტიპი\"\n\n#: lib/solaar/ui/rule_conditions.py:535\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"\"\n\"თაგუნას ჟესტი არასავალდებულო გამშვები ღილაკით, რომელსაც 0, ან მეტი თაგუნას \"\n\"მოძრაობა მოჰყვება.\"\n\n#: lib/solaar/ui/rule_conditions.py:541\nmsgid \"Add movement\"\nmsgstr \"მოძრაობის დამატება\"\n\n#: lib/solaar/ui/tray.py:55\nmsgid \"No supported device found\"\nmsgstr \"მხარდაჭერილი მოწყობილობა აღმოჩენილი არაა\"\n\n#: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328\n#, python-format\nmsgid \"About %s\"\nmsgstr \"%s-ის შესახებ\"\n\n#: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"%s-დან გასვლა\"\n\n#: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281\nmsgid \"no receiver\"\nmsgstr \"მიმღების გარეშე\"\n\n#: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299\n#: lib/solaar/ui/window.py:728\nmsgid \"offline\"\nmsgstr \"გათიშული\"\n\n#: lib/solaar/ui/tray.py:297\nmsgid \"no status\"\nmsgstr \"სტატუსის გარეშე\"\n\n#: lib/solaar/ui/window.py:110\nmsgid \"Scanning\"\nmsgstr \"სკანირება\"\n\n#: lib/solaar/ui/window.py:141\nmsgid \"Battery\"\nmsgstr \"ელემენტი\"\n\n#: lib/solaar/ui/window.py:144\nmsgid \"Wireless Link\"\nmsgstr \"უსადენო კავშირი\"\n\n#: lib/solaar/ui/window.py:148\nmsgid \"Lighting\"\nmsgstr \"განათება\"\n\n#: lib/solaar/ui/window.py:182\nmsgid \"Show Technical Details\"\nmsgstr \"ტექნიკური დეტალების ჩვენება\"\n\n#: lib/solaar/ui/window.py:198\nmsgid \"Pair new device\"\nmsgstr \"ახალი მოწყობილობის დაწყვილება\"\n\n#: lib/solaar/ui/window.py:216\nmsgid \"Select a device\"\nmsgstr \"აირჩიეთ მოწყობილობა\"\n\n#: lib/solaar/ui/window.py:331\nmsgid \"Rule Editor\"\nmsgstr \"წესების რედაქტორი\"\n\n#: lib/solaar/ui/window.py:522\nmsgid \"Path\"\nmsgstr \"ბილიკი\"\n\n#: lib/solaar/ui/window.py:524\nmsgid \"USB ID\"\nmsgstr \"USB ID\"\n\n#: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529\n#: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546\nmsgid \"Serial\"\nmsgstr \"სერიული\"\n\n#: lib/solaar/ui/window.py:533\nmsgid \"Index\"\nmsgstr \"ინდექსი\"\n\n#: lib/solaar/ui/window.py:535\nmsgid \"Wireless PID\"\nmsgstr \"უსადენო PID\"\n\n#: lib/solaar/ui/window.py:537\nmsgid \"Product ID\"\nmsgstr \"პროდუქტის ID\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Protocol\"\nmsgstr \"პროტოკოლი\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Unknown\"\nmsgstr \"უცნობი\"\n\n#: lib/solaar/ui/window.py:541\nmsgid \"Polling rate\"\nmsgstr \"გამოკითხვის სიხშირე\"\n\n#: lib/solaar/ui/window.py:548\nmsgid \"Unit ID\"\nmsgstr \"ერთეულის ID\"\n\n#: lib/solaar/ui/window.py:559\nmsgid \"none\"\nmsgstr \"არცერთი\"\n\n#: lib/solaar/ui/window.py:560\nmsgid \"Notifications\"\nmsgstr \"შეტყობინებები\"\n\n#: lib/solaar/ui/window.py:604\nmsgid \"No device paired.\"\nmsgstr \"დაწყვილებული მოწყობილობების გარეშე.\"\n\n#: lib/solaar/ui/window.py:613\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"\"\n\"ამ მიმღებთან, მაქსიმუმ, %(max_count)s მოწყობილობის დაწყვილება შეიძლება.\"\nmsgstr[1] \"\"\n\"ამ მიმღებთან, მაქსიმუმ, %(max_count)s მოწყობილობის დაწყვილება შეიძლება.\"\n\n#: lib/solaar/ui/window.py:620\nmsgid \"Only one device can be paired to this receiver.\"\nmsgstr \"ამ მიმღებთან, მაქს., ერთი მოწყობილობის დაწყვილებაა შესაძლებელი.\"\n\n#: lib/solaar/ui/window.py:624\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"ამ მიმღებს %d დაწყვილება აქვს დარჩენილი.\"\nmsgstr[1] \"ამ მიმღებს %d დაწყვილება აქვს დარჩენილი.\"\n\n#: lib/solaar/ui/window.py:681\nmsgid \"Battery Voltage\"\nmsgstr \"ელემენტის ვოლტაჟი\"\n\n#: lib/solaar/ui/window.py:683\nmsgid \"Voltage reported by battery\"\nmsgstr \"ელემენტის მიერ მოწოდებული ძაბვა\"\n\n#: lib/solaar/ui/window.py:685\nmsgid \"Battery Level\"\nmsgstr \"ელემენტის მუხტის დონე\"\n\n#: lib/solaar/ui/window.py:687\nmsgid \"Approximate level reported by battery\"\nmsgstr \"დონის მიერ მუხტის მოწოდებული დაახლოებითი დონე\"\n\n#: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696\nmsgid \"next reported \"\nmsgstr \"შემდეგი ანგარიში \"\n\n#: lib/solaar/ui/window.py:697\nmsgid \" and next level to be reported.\"\nmsgstr \" და შემდეგი დონე გადასაცემად.\"\n\n#: lib/solaar/ui/window.py:702\nmsgid \"last known\"\nmsgstr \"ბოლო ცნობილი\"\n\n#: lib/solaar/ui/window.py:713\nmsgid \"encrypted\"\nmsgstr \"დაშიფრულია\"\n\n#: lib/solaar/ui/window.py:715\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"უსადენო კავშირი ამ მოწყობილობასა და მის მიმღებს შორის დაშიფრულია.\"\n\n#: lib/solaar/ui/window.py:717\nmsgid \"not encrypted\"\nmsgstr \"დაშიფრული არაა\"\n\n#: lib/solaar/ui/window.py:721\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"უსადენო კავშირი ამ მოწყობილობასა და მის მიმღებს შორის დაშიფრული არაა.\\n\"\n\"ეს უსაფრთხოების პრობლემაა მაჩვენებელი მოწყობილობებისთვის და უსაფრთხოების \"\n\"დიდი პრობლემაა ტექსტის შეყვანის მოწყობილობებისთვის.\"\n\n#: lib/solaar/ui/window.py:737\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d ლუქსი\"\n"
  },
  {
    "path": "po/nb.po",
    "content": "# Norwegian Bokmal translations for solaar package.\n# Copyright (C) 2020 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2020.\n# John Erling Blad <jeblad@gmail.com>, 2020-2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 1.0.3\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-10-24 03:15+0200\\n\"\n\"PO-Revision-Date: 2024-10-31 02:21+0100\\n\"\n\"Last-Translator: John Erling Blad <jeblad@gmail.com>\\n\"\n\"Language-Team:  <gnome-no@gnome.org>\\n\"\n\"Language: nb\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n!=1)\\n\"\n\"X-Generator: Gtranslator 47.0\\n\"\n\n#: lib/logitech_receiver/base_usb.py:48\nmsgid \"Bolt Receiver\"\nmsgstr \"Bolt mottaker\"\n\n#: lib/logitech_receiver/base_usb.py:60\nmsgid \"Unifying Receiver\"\nmsgstr \"Unifying mottaker\"\n\n#: lib/logitech_receiver/base_usb.py:71 lib/logitech_receiver/base_usb.py:83\n#: lib/logitech_receiver/base_usb.py:96 lib/logitech_receiver/base_usb.py:109\nmsgid \"Nano Receiver\"\nmsgstr \"Nano mottaker\"\n\n#: lib/logitech_receiver/base_usb.py:121\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Lightspeed mottaker\"\n\n#: lib/logitech_receiver/base_usb.py:131\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"EX100 mottaker 27 Mhz mottaker\"\n\n#: lib/logitech_receiver/common.py:648\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"Batteri: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:651\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"Batteri: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:962\n#: lib/logitech_receiver/settings_templates.py:294\nmsgid \"Disabled\"\nmsgstr \"Avslått\"\n\n#: lib/logitech_receiver/hidpp20.py:963\nmsgid \"Static\"\nmsgstr \"Statisk\"\n\n#: lib/logitech_receiver/hidpp20.py:964\nmsgid \"Pulse\"\nmsgstr \"Puls\"\n\n#: lib/logitech_receiver/hidpp20.py:965\nmsgid \"Cycle\"\nmsgstr \"Syklus\"\n\n#: lib/logitech_receiver/hidpp20.py:966\nmsgid \"Boot\"\nmsgstr \"Boot\"\n\n#: lib/logitech_receiver/hidpp20.py:967\nmsgid \"Demo\"\nmsgstr \"Demo\"\n\n#: lib/logitech_receiver/hidpp20.py:969\nmsgid \"Breathe\"\nmsgstr \"Pust\"\n\n#: lib/logitech_receiver/hidpp20.py:972\nmsgid \"Ripple\"\nmsgstr \"Krusning\"\n\n#: lib/logitech_receiver/hidpp20.py:973\nmsgid \"Decomposition\"\nmsgstr \"Dekomponering\"\n\n#: lib/logitech_receiver/hidpp20.py:974\nmsgid \"Signature1\"\nmsgstr \"Signatur1\"\n\n#: lib/logitech_receiver/hidpp20.py:975\nmsgid \"Signature2\"\nmsgstr \"Signatur2\"\n\n#: lib/logitech_receiver/hidpp20.py:976\nmsgid \"CycleS\"\nmsgstr \"SyklusS\"\n\n#: lib/logitech_receiver/hidpp20.py:1040\nmsgid \"Unknown Location\"\nmsgstr \"Ukjent lokasjon\"\n\n#: lib/logitech_receiver/hidpp20.py:1041\nmsgid \"Primary\"\nmsgstr \"Primær\"\n\n#: lib/logitech_receiver/hidpp20.py:1042\nmsgid \"Logo\"\nmsgstr \"Logo\"\n\n#: lib/logitech_receiver/hidpp20.py:1043\nmsgid \"Left Side\"\nmsgstr \"Venstre side\"\n\n#: lib/logitech_receiver/hidpp20.py:1044\nmsgid \"Right Side\"\nmsgstr \"Høyre side\"\n\n#: lib/logitech_receiver/hidpp20.py:1045\nmsgid \"Combined\"\nmsgstr \"Kombinert\"\n\n#: lib/logitech_receiver/hidpp20.py:1046\nmsgid \"Primary 1\"\nmsgstr \"Primær 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1047\nmsgid \"Primary 2\"\nmsgstr \"Primær 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1048\nmsgid \"Primary 3\"\nmsgstr \"Primær 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1049\nmsgid \"Primary 4\"\nmsgstr \"Primær 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1050\nmsgid \"Primary 5\"\nmsgstr \"Primær 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1051\nmsgid \"Primary 6\"\nmsgstr \"Primær 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"tom\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"kritisk\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"lav\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"middels\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"god\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"full\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"utlading\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"opplading\"\n\n#: lib/logitech_receiver/i18n.py:37\nmsgid \"charging\"\nmsgstr \"lader\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"lader ikke\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"nesten full\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"ladet\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"langsom lading\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"invalid battery\"\nmsgstr \"batterifeil\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"termisk feil\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"feil\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"standard\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"rask\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"langsom\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"enheten svarte ikke\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"enheten er ikke støttet\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"for mange enheter\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"sekvens timeout\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid \"Firmware\"\nmsgstr \"Fastvare\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"Oppstartslaster\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"Maskinvare\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"Annet\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"Venstreknapp\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"Høyreknapp\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"Midtknapp\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"Tilbakeknapp\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"Foroverknapp\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"Bevegelsesknapp\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"Smart skift\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"DPI-bryter\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"Venstre-tilt\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"Høyre-tilt\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"Venstre-klikk\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"Høyre-klikk\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"Midtknapp for mus\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"Tilbakeknapp for mus\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"Foroverknapp for mus\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"Navigering med bevegelsesknapp\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"Venstre rulleknapp for mus\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"Høyre rulleknapp for mus\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"nedtrykt\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"utløst\"\n\n#: lib/logitech_receiver/notifications.py:86\n#: lib/logitech_receiver/notifications.py:138\nmsgid \"pairing lock is closed\"\nmsgstr \"parlåsen er lukket\"\n\n#: lib/logitech_receiver/notifications.py:86\n#: lib/logitech_receiver/notifications.py:138\nmsgid \"pairing lock is open\"\nmsgstr \"parlåsen er åpen\"\n\n#: lib/logitech_receiver/notifications.py:103\nmsgid \"discovery lock is closed\"\nmsgstr \"oppdagelseslåsen er lukket\"\n\n#: lib/logitech_receiver/notifications.py:103\nmsgid \"discovery lock is open\"\nmsgstr \"oppdagelseslåsen er åpen\"\n\n#: lib/logitech_receiver/notifications.py:232 lib/solaar/listener.py:247\nmsgid \"connected\"\nmsgstr \"tilkoblet\"\n\n#: lib/logitech_receiver/notifications.py:232 lib/solaar/listener.py:247\nmsgid \"disconnected\"\nmsgstr \"frakoblet\"\n\n#: lib/logitech_receiver/notifications.py:258\nmsgid \"unpaired\"\nmsgstr \"uparet\"\n\n#: lib/logitech_receiver/notifications.py:305\nmsgid \"powered on\"\nmsgstr \"påslått\"\n\n#: lib/logitech_receiver/receiver.py:383\nmsgid \"No paired devices.\"\nmsgstr \"Ingen paret enhet.\"\n\n#: lib/logitech_receiver/receiver.py:385 lib/solaar/ui/window.py:590\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s paret enhet.\"\nmsgstr[1] \"%(count)s parede enheter.\"\n\n#: lib/logitech_receiver/settings.py:614\nmsgid \"register\"\nmsgstr \"register\"\n\n#: lib/logitech_receiver/settings.py:628 lib/logitech_receiver/settings.py:663\nmsgid \"feature\"\nmsgstr \"karakteristikk\"\n\n#: lib/logitech_receiver/settings_templates.py:133\nmsgid \"Swap Fx function\"\nmsgstr \"Bytt Fx-funksjon\"\n\n#: lib/logitech_receiver/settings_templates.py:136\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"Hvis aktivert, vil F1–F12-tastene aktivere sin spesialfunksjon,\\n\"\n\"og du må holde FN-tasten nede for å aktivere deres standardfunksjon.\"\n\n#: lib/logitech_receiver/settings_templates.py:141\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"Hvis deaktivert, vil F1–F12-tastene aktivere sin standardfunksjon,\\n\"\n\"og du må holde FN-tasten nede for å aktivere deres spesialfunksjon.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid \"Hand Detection\"\nmsgstr \"Håndpåvisning\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"Slå på belysning når hendene er over tastaturet.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"Myk rulling med rullehjul\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:405\n#: lib/logitech_receiver/settings_templates.py:434\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"Høysensitiv modus for vertikal rulling med hjulet.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid \"Side Scrolling\"\nmsgstr \"Siderulling\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"Hvis avslått; trykkes hjulet sideveis så sendes en tilpasset knappehendelse\\n\"\n\"istedenfor standard siderulling.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"Følsomhet (DPI – eldre mus)\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:977\n#: lib/logitech_receiver/settings_templates.py:1005\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"Følsomhet for musbevegelser\"\n\n#: lib/logitech_receiver/settings_templates.py:251\nmsgid \"Backlight Timed\"\nmsgstr \"Tidsbestemt bakgrunnslys\"\n\n#: lib/logitech_receiver/settings_templates.py:252\n#: lib/logitech_receiver/settings_templates.py:392\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"Still inn belysningstid for tastatur.\"\n\n#: lib/logitech_receiver/settings_templates.py:263\nmsgid \"Backlight\"\nmsgstr \"Bakbelysning\"\n\n#: lib/logitech_receiver/settings_templates.py:264\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"\"\n\"Lysnivå på tastaturet. Endringer som er gjort, brukes kun i manuell modus.\"\n\n#: lib/logitech_receiver/settings_templates.py:296\nmsgid \"Automatic\"\nmsgstr \"Automatisk\"\n\n#: lib/logitech_receiver/settings_templates.py:298\nmsgid \"Manual\"\nmsgstr \"Manuell\"\n\n#: lib/logitech_receiver/settings_templates.py:300\nmsgid \"Enabled\"\nmsgstr \"Påslått\"\n\n#: lib/logitech_receiver/settings_templates.py:306\nmsgid \"Backlight Level\"\nmsgstr \"Bakgrunnslysnivå\"\n\n#: lib/logitech_receiver/settings_templates.py:307\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"Lysnivå på tastaturet i manuell modus.\"\n\n#: lib/logitech_receiver/settings_templates.py:364\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"Forsinkelse på bakgrunnsbelysning når hendene fjernes\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"\"\n\"Forsinkelse i sekunder til bakgrunnsbelysningen toner ut når hendene er \"\n\"borte fra tastaturet.\"\n\n#: lib/logitech_receiver/settings_templates.py:373\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"Forsinkelse på bakgrunnsbelysning når hendene er nære\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"\"\n\"Forsinkelse i sekunder til bakgrunnsbelysningen toner ut når hendene er nære \"\n\"tastaturet.\"\n\n#: lib/logitech_receiver/settings_templates.py:382\nmsgid \"Backlight Delay Powered\"\nmsgstr \"Forsinkelse på bakgrunnsbelysning når strømforsynt\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"\"\n\"Forsinkelse i sekunder til bakgrunnsbelysningen toner ut med ekstern \"\n\"strømforsyning.\"\n\n#: lib/logitech_receiver/settings_templates.py:391\nmsgid \"Backlight (Seconds)\"\nmsgstr \"Bakgrunnslys (sekunder)\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"Høyoppløselig rullehjul\"\n\n#: lib/logitech_receiver/settings_templates.py:407\n#: lib/logitech_receiver/settings_templates.py:436\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"Sett til å ignorere hvis rullingen er unormalt rask eller sakte\"\n\n#: lib/logitech_receiver/settings_templates.py:414\n#: lib/logitech_receiver/settings_templates.py:445\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"Omdirigering for rullehjul\"\n\n#: lib/logitech_receiver/settings_templates.py:416\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Få rullehjulet til å sende LOWRES_WHEEL HID++-varsler (som utløser Solaar-\"\n\"regler, men som ellers ignoreres).\"\n\n#: lib/logitech_receiver/settings_templates.py:423\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"Retning på rullehjul\"\n\n#: lib/logitech_receiver/settings_templates.py:424\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"Inverter retning for vertikal rulling med hjul.\"\n\n#: lib/logitech_receiver/settings_templates.py:432\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"Oppløsning på rullehjul\"\n\n#: lib/logitech_receiver/settings_templates.py:447\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Få rullehjulet til å sende HIRES_WHEEL HID++-varsler (som utløser Solaar-\"\n\"regler, men som ellers ignoreres).\"\n\n#: lib/logitech_receiver/settings_templates.py:456\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"Følsomhet (pekerfart)\"\n\n#: lib/logitech_receiver/settings_templates.py:457\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"Fartsmultiplikator for mus (256 er normal multiplikator).\"\n\n#: lib/logitech_receiver/settings_templates.py:467\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"Omdirigering for tommelhjul\"\n\n#: lib/logitech_receiver/settings_templates.py:469\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Få tommelhjulet til å sende THUMB_WHEEL HID++-varsler (som utløser Solaar-\"\n\"regler, men som ellers ignoreres).\"\n\n#: lib/logitech_receiver/settings_templates.py:478\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"Retning på tommelhjul\"\n\n#: lib/logitech_receiver/settings_templates.py:479\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"Inverter rulleretning for tommelhjul.\"\n\n#: lib/logitech_receiver/settings_templates.py:499\nmsgid \"Onboard Profiles\"\nmsgstr \"Innebygde profiler\"\n\n#: lib/logitech_receiver/settings_templates.py:500\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"\"\n\"Aktiver en innebygd profil, som kontrollerer rapporthyppighet, følsomhet og \"\n\"knappehandlinger\"\n\n#: lib/logitech_receiver/settings_templates.py:544\n#: lib/logitech_receiver/settings_templates.py:577\nmsgid \"Report Rate\"\nmsgstr \"Rapporthyppighet\"\n\n#: lib/logitech_receiver/settings_templates.py:546\n#: lib/logitech_receiver/settings_templates.py:579\nmsgid \"Frequency of device movement reports\"\nmsgstr \"Frekvensen til rapporter om enhetsbevegelser\"\n\n#: lib/logitech_receiver/settings_templates.py:546\n#: lib/logitech_receiver/settings_templates.py:579\n#: lib/logitech_receiver/settings_templates.py:1005\n#: lib/logitech_receiver/settings_templates.py:1379\n#: lib/logitech_receiver/settings_templates.py:1410\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"\"\n\"Kan trenge at innebygde profiler settes til avslått for å være effektive.\"\n\n#: lib/logitech_receiver/settings_templates.py:607\nmsgid \"Divert crown events\"\nmsgstr \"Omdiriger krone-hendelser\"\n\n#: lib/logitech_receiver/settings_templates.py:608\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Få kronen til å sende CROWN HID++-varsler (som utløser Solaar-regler, men \"\n\"som ellers ignoreres).\"\n\n#: lib/logitech_receiver/settings_templates.py:616\nmsgid \"Crown smooth scroll\"\nmsgstr \"Glatt krone-rulling\"\n\n#: lib/logitech_receiver/settings_templates.py:617\nmsgid \"Set crown smooth scroll\"\nmsgstr \"Still inn glatt krone-rulling\"\n\n#: lib/logitech_receiver/settings_templates.py:625\nmsgid \"Divert G and M Keys\"\nmsgstr \"Omdiriger G- og M-taster\"\n\n#: lib/logitech_receiver/settings_templates.py:626\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Få G- og M-tastene til å sende HID++-varsler (som utløser Solaar-regler, men \"\n\"som ellers ignoreres).\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"Rullehjul sperrehaket\"\n\n#: lib/logitech_receiver/settings_templates.py:641\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"\"\n\"Bytt musehjulet mellom hastighetskontrollert sperrehake og alltid \"\n\"frittløpende.\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid \"Freespinning\"\nmsgstr \"Frittløpende\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid \"Ratcheted\"\nmsgstr \"Sperrehake\"\n\n#: lib/logitech_receiver/settings_templates.py:650\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"Rullehjul sperrehakefart\"\n\n#: lib/logitech_receiver/settings_templates.py:652\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"Bruk musehjulfarten til å bytte mellom sperrehake og frittløpende.\\n\"\n\"Musehjulet er alltid satt til 50.\"\n\n#: lib/logitech_receiver/settings_templates.py:701\nmsgid \"Key/Button Actions\"\nmsgstr \"Taste-/knappehandling\"\n\n#: lib/logitech_receiver/settings_templates.py:703\nmsgid \"Change the action for the key or button.\"\nmsgstr \"Endre handling for en tast eller knapp.\"\n\n#: lib/logitech_receiver/settings_templates.py:705\nmsgid \"Overridden by diversion.\"\nmsgstr \"Overstyrt av omdirigering.\"\n\n#: lib/logitech_receiver/settings_templates.py:707\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"\"\n\"Endring av viktige handlinger (for eksempel venstre musknapp) kan resultere \"\n\"i et ubrukbart system.\"\n\n#: lib/logitech_receiver/settings_templates.py:882\nmsgid \"Key/Button Diversion\"\nmsgstr \"Taste-/knappeomdirigering\"\n\n#: lib/logitech_receiver/settings_templates.py:883\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse \"\n\"Gestures or Sliding DPI\"\nmsgstr \"\"\n\"Få nøkkelen eller knappen til å sende HID++-varsler (omdirigert) eller \"\n\"initier musebevegelser eller glidende DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:886\n#: lib/logitech_receiver/settings_templates.py:887\n#: lib/logitech_receiver/settings_templates.py:888\nmsgid \"Diverted\"\nmsgstr \"Omdirigert\"\n\n#: lib/logitech_receiver/settings_templates.py:886\n#: lib/logitech_receiver/settings_templates.py:887\nmsgid \"Mouse Gestures\"\nmsgstr \"Musebevegelser\"\n\n#: lib/logitech_receiver/settings_templates.py:886\n#: lib/logitech_receiver/settings_templates.py:887\n#: lib/logitech_receiver/settings_templates.py:888\nmsgid \"Regular\"\nmsgstr \"Vanlig\"\n\n#: lib/logitech_receiver/settings_templates.py:886\nmsgid \"Sliding DPI\"\nmsgstr \"Glidende DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:976\n#: lib/logitech_receiver/settings_templates.py:1004\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"Følsomhet (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:1081\nmsgid \"Sensitivity Switching\"\nmsgstr \"Følsomhetsbytte\"\n\n#: lib/logitech_receiver/settings_templates.py:1083\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key \"\n\"or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\"Bytt gjeldende følsomhet og tidligere følsomhet når tasten eller knappen \"\n\"trykkes.\\n\"\n\"Hvis det ikke er noen tidligere følsomhet, sett kun gjeldende følsomhet\"\n\n#: lib/logitech_receiver/settings_templates.py:1087\nmsgid \"Off\"\nmsgstr \"Av\"\n\n#: lib/logitech_receiver/settings_templates.py:1118\nmsgid \"Disable keys\"\nmsgstr \"Slå av taster\"\n\n#: lib/logitech_receiver/settings_templates.py:1119\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"Slå av spesifikke tastaturtaster.\"\n\n#: lib/logitech_receiver/settings_templates.py:1122\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"Slår av %s-tasten.\"\n\n#: lib/logitech_receiver/settings_templates.py:1135\n#: lib/logitech_receiver/settings_templates.py:1192\nmsgid \"Set OS\"\nmsgstr \"Still OS\"\n\n#: lib/logitech_receiver/settings_templates.py:1136\n#: lib/logitech_receiver/settings_templates.py:1193\nmsgid \"Change keys to match OS.\"\nmsgstr \"Endre taster så de stemmer med OS.\"\n\n#: lib/logitech_receiver/settings_templates.py:1205\nmsgid \"Change Host\"\nmsgstr \"Endre tjener\"\n\n#: lib/logitech_receiver/settings_templates.py:1206\nmsgid \"Switch connection to a different host\"\nmsgstr \"Endre koblingen til en annen tjener\"\n\n#: lib/logitech_receiver/settings_templates.py:1230\nmsgid \"Performs a left click.\"\nmsgstr \"Utfører et venstreklikk.\"\n\n#: lib/logitech_receiver/settings_templates.py:1230\nmsgid \"Single tap\"\nmsgstr \"Enkeltklikk\"\n\n#: lib/logitech_receiver/settings_templates.py:1231\nmsgid \"Performs a right click.\"\nmsgstr \"Utfører et høyreklikk.\"\n\n#: lib/logitech_receiver/settings_templates.py:1231\nmsgid \"Single tap with two fingers\"\nmsgstr \"Enkelt trykk med to fingre\"\n\n#: lib/logitech_receiver/settings_templates.py:1232\nmsgid \"Single tap with three fingers\"\nmsgstr \"Enkelt trykk med tre fingre\"\n\n#: lib/logitech_receiver/settings_templates.py:1236\nmsgid \"Double tap\"\nmsgstr \"Dobbeltklikk\"\n\n#: lib/logitech_receiver/settings_templates.py:1236\nmsgid \"Performs a double click.\"\nmsgstr \"Utfører et dobbeltklikk.\"\n\n#: lib/logitech_receiver/settings_templates.py:1237\nmsgid \"Double tap with two fingers\"\nmsgstr \"Dobbeltklikk med to fingre\"\n\n#: lib/logitech_receiver/settings_templates.py:1238\nmsgid \"Double tap with three fingers\"\nmsgstr \"Dobbeltklikk med tre fingre\"\n\n#: lib/logitech_receiver/settings_templates.py:1241\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"Dra elementer med fingeren etter dobbeltklikk.\"\n\n#: lib/logitech_receiver/settings_templates.py:1241\nmsgid \"Tap and drag\"\nmsgstr \"Klikk og dra\"\n\n#: lib/logitech_receiver/settings_templates.py:1243\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"Klikk og dra med to fingre\"\n\n#: lib/logitech_receiver/settings_templates.py:1244\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"Dra elementer med fingrene etter dobbeltklikk.\"\n\n#: lib/logitech_receiver/settings_templates.py:1246\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"Klikk og dra med tre fingre\"\n\n#: lib/logitech_receiver/settings_templates.py:1249\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"Undertrykk klikk- og kantbevegelser\"\n\n#: lib/logitech_receiver/settings_templates.py:1250\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"Slår av klikk- og kantbevegelser (tilsvarer å trykke Fn+Venstreklikk).\"\n\n#: lib/logitech_receiver/settings_templates.py:1252\nmsgid \"Scroll with one finger\"\nmsgstr \"Rull med en finger\"\n\n#: lib/logitech_receiver/settings_templates.py:1252\n#: lib/logitech_receiver/settings_templates.py:1253\n#: lib/logitech_receiver/settings_templates.py:1256\nmsgid \"Scrolls.\"\nmsgstr \"Ruller.\"\n\n#: lib/logitech_receiver/settings_templates.py:1253\n#: lib/logitech_receiver/settings_templates.py:1256\nmsgid \"Scroll with two fingers\"\nmsgstr \"Rull med to fingre\"\n\n#: lib/logitech_receiver/settings_templates.py:1254\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"Rull horisontalt med to fingre\"\n\n#: lib/logitech_receiver/settings_templates.py:1254\nmsgid \"Scrolls horizontally.\"\nmsgstr \"Rull horisontalt.\"\n\n#: lib/logitech_receiver/settings_templates.py:1255\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"Rull vertikalt med to fingre\"\n\n#: lib/logitech_receiver/settings_templates.py:1255\nmsgid \"Scrolls vertically.\"\nmsgstr \"Rull vertikalt.\"\n\n#: lib/logitech_receiver/settings_templates.py:1257\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"Inverterer rulleretningen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1257\nmsgid \"Natural scrolling\"\nmsgstr \"Naturlig rulling\"\n\n#: lib/logitech_receiver/settings_templates.py:1258\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"Aktiverer tommelhjulet.\"\n\n#: lib/logitech_receiver/settings_templates.py:1258\nmsgid \"Thumbwheel\"\nmsgstr \"Tommelhjul\"\n\n#: lib/logitech_receiver/settings_templates.py:1269\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Swipe from the top edge\"\nmsgstr \"Sveip fra øvre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1270\nmsgid \"Swipe from the left edge\"\nmsgstr \"Sveip fra venstre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1271\nmsgid \"Swipe from the right edge\"\nmsgstr \"Sveip fra høyre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"Sveip fra nedre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1274\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"Sveip to fingre fra venstre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1275\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"Sveip to fingre fra høyre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1276\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"Sveip to fingre fra nedre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1277\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"Sveip to fingre fra øvre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\n#: lib/logitech_receiver/settings_templates.py:1282\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"Knip for å zoome ut; spre for å zoome inn.\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Zoom with two fingers.\"\nmsgstr \"Zoom med to fingre.\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid \"Pinch to zoom out.\"\nmsgstr \"Knip for å zoome ut.\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Spread to zoom in.\"\nmsgstr \"Spre for å zoome inn.\"\n\n#: lib/logitech_receiver/settings_templates.py:1281\nmsgid \"Zoom with three fingers.\"\nmsgstr \"Zoom med tre fingre.\"\n\n#: lib/logitech_receiver/settings_templates.py:1282\nmsgid \"Zoom with two fingers\"\nmsgstr \"Zoom med to fingre\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Pixel zone\"\nmsgstr \"Pikselsone\"\n\n#: lib/logitech_receiver/settings_templates.py:1301\nmsgid \"Ratio zone\"\nmsgstr \"Forholdssone\"\n\n#: lib/logitech_receiver/settings_templates.py:1302\nmsgid \"Scale factor\"\nmsgstr \"Skalafaktor\"\n\n#: lib/logitech_receiver/settings_templates.py:1302\nmsgid \"Sets the cursor speed.\"\nmsgstr \"Still inn markørhastigheten.\"\n\n#: lib/logitech_receiver/settings_templates.py:1306\nmsgid \"Left\"\nmsgstr \"Venstre\"\n\n#: lib/logitech_receiver/settings_templates.py:1306\nmsgid \"Left-most coordinate.\"\nmsgstr \"Koordinat lengst til venstre.\"\n\n#: lib/logitech_receiver/settings_templates.py:1307\nmsgid \"Bottom\"\nmsgstr \"Nederst\"\n\n#: lib/logitech_receiver/settings_templates.py:1307\nmsgid \"Bottom coordinate.\"\nmsgstr \"Nederste koordinat.\"\n\n#: lib/logitech_receiver/settings_templates.py:1308\nmsgid \"Width\"\nmsgstr \"Bredde\"\n\n#: lib/logitech_receiver/settings_templates.py:1308\nmsgid \"Width.\"\nmsgstr \"Bredde.\"\n\n#: lib/logitech_receiver/settings_templates.py:1309\nmsgid \"Height\"\nmsgstr \"Høyde\"\n\n#: lib/logitech_receiver/settings_templates.py:1309\nmsgid \"Height.\"\nmsgstr \"Høyde.\"\n\n#: lib/logitech_receiver/settings_templates.py:1310\nmsgid \"Cursor speed.\"\nmsgstr \"Markørhastighet.\"\n\n#: lib/logitech_receiver/settings_templates.py:1310\nmsgid \"Scale\"\nmsgstr \"Skala\"\n\n#: lib/logitech_receiver/settings_templates.py:1316\nmsgid \"Gestures\"\nmsgstr \"Bevegelser\"\n\n#: lib/logitech_receiver/settings_templates.py:1317\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"Juster musens/berøringsplatens oppførsel.\"\n\n#: lib/logitech_receiver/settings_templates.py:1333\nmsgid \"Gestures Diversion\"\nmsgstr \"Omdirigering av bevegelser\"\n\n#: lib/logitech_receiver/settings_templates.py:1334\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"Omdiriger musens/berøringsflatens bevegelser.\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Gesture params\"\nmsgstr \"Parametre for bevegelser\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"Endre numeriske parametere for en mus/berøringsplate.\"\n\n#: lib/logitech_receiver/settings_templates.py:1375\nmsgid \"M-Key LEDs\"\nmsgstr \"M-tast LED-ene\"\n\n#: lib/logitech_receiver/settings_templates.py:1377\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"Kontroller M-tast LED-ene.\"\n\n#: lib/logitech_receiver/settings_templates.py:1381\n#: lib/logitech_receiver/settings_templates.py:1412\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"Kan trenge omdirigering av G-taster for å være effektivt.\"\n\n#: lib/logitech_receiver/settings_templates.py:1387\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"Lyser opp %s-tasten.\"\n\n#: lib/logitech_receiver/settings_templates.py:1406\nmsgid \"MR-Key LED\"\nmsgstr \"MR-tast LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1408\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"Kontroller MR-tast LED.\"\n\n#: lib/logitech_receiver/settings_templates.py:1429\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"Vedvarende tast-/knapptilordning\"\n\n#: lib/logitech_receiver/settings_templates.py:1431\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"Endre tilordningen for tasten eller knappen permanent.\"\n\n#: lib/logitech_receiver/settings_templates.py:1433\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"\"\n\"Endring av viktige taster eller knapper (som venstre museknapp) kan \"\n\"resultere i et ubrukelig system.\"\n\n#: lib/logitech_receiver/settings_templates.py:1490\nmsgid \"Sidetone\"\nmsgstr \"Sidetone\"\n\n#: lib/logitech_receiver/settings_templates.py:1491\nmsgid \"Set sidetone level.\"\nmsgstr \"Still inn sidetone nivå.\"\n\n#: lib/logitech_receiver/settings_templates.py:1500\nmsgid \"Equalizer\"\nmsgstr \"Equalizer\"\n\n#: lib/logitech_receiver/settings_templates.py:1501\nmsgid \"Set equalizer levels.\"\nmsgstr \"Still inn equalizer nivå.\"\n\n#: lib/logitech_receiver/settings_templates.py:1523\nmsgid \"Hz\"\nmsgstr \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1529\nmsgid \"Power Management\"\nmsgstr \"Strømstyring\"\n\n#: lib/logitech_receiver/settings_templates.py:1530\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"Slå av i minutter (0 for aldri).\"\n\n#: lib/logitech_receiver/settings_templates.py:1541\nmsgid \"Brightness Control\"\nmsgstr \"Lysstyrkekontroll\"\n\n#: lib/logitech_receiver/settings_templates.py:1542\nmsgid \"Control overall brightness\"\nmsgstr \"Kontroller den generelle lysstyrken\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\n#: lib/logitech_receiver/settings_templates.py:1639\nmsgid \"LED Control\"\nmsgstr \"LED-kontroll\"\n\n#: lib/logitech_receiver/settings_templates.py:1586\n#: lib/logitech_receiver/settings_templates.py:1640\nmsgid \"Switch control of LED zones between device and Solaar\"\nmsgstr \"Bytt kontroll av LED-soner mellom enhet og Solaar\"\n\n#: lib/logitech_receiver/settings_templates.py:1601\n#: lib/logitech_receiver/settings_templates.py:1650\nmsgid \"LED Zone Effects\"\nmsgstr \"LED-soneeffekter\"\n\n#: lib/logitech_receiver/settings_templates.py:1602\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr \"LED-kontroll må settes til Solaar for å være effektiv.\"\n\n#: lib/logitech_receiver/settings_templates.py:1602\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid \"Set effect for LED Zone\"\nmsgstr \"Still inn effekt for LED-sone\"\n\n#: lib/logitech_receiver/settings_templates.py:1605\nmsgid \"Speed\"\nmsgstr \"Hastighet\"\n\n#: lib/logitech_receiver/settings_templates.py:1606\nmsgid \"Period\"\nmsgstr \"Periode\"\n\n#: lib/logitech_receiver/settings_templates.py:1607\nmsgid \"Intensity\"\nmsgstr \"Intensitet\"\n\n#: lib/logitech_receiver/settings_templates.py:1608\nmsgid \"Ramp\"\nmsgstr \"Stigning\"\n\n#: lib/logitech_receiver/settings_templates.py:1624\nmsgid \"LEDs\"\nmsgstr \"LEDs\"\n\n#: lib/logitech_receiver/settings_templates.py:1661\nmsgid \"Per-key Lighting\"\nmsgstr \"Lys for hver tast\"\n\n#: lib/logitech_receiver/settings_templates.py:1662\nmsgid \"Control per-key lighting.\"\nmsgstr \"Kontroller lys for hver tast.\"\n\n#: lib/solaar/ui/__init__.py:117\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"En annen Solaar-prosess kjører allerede, så bare vis vinduet\"\n\n#: lib/solaar/ui/about/model.py:36\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"Administrerer Logitech-mottakere,\\n\"\n\"tastaturer, mus og nettbrett.\"\n\n#: lib/solaar/ui/about/model.py:62\nmsgid \"Additional Programming\"\nmsgstr \"Ekstra programmering\"\n\n#: lib/solaar/ui/about/model.py:63\nmsgid \"GUI design\"\nmsgstr \"GUI utseende\"\n\n#: lib/solaar/ui/about/model.py:65\nmsgid \"Testing\"\nmsgstr \"Testing\"\n\n#: lib/solaar/ui/about/model.py:73\nmsgid \"Logitech documentation\"\nmsgstr \"Logitech dokumentasjon\"\n\n#: lib/solaar/ui/action.py:83 lib/solaar/ui/action.py:87\n#: lib/solaar/ui/window.py:188\nmsgid \"Unpair\"\nmsgstr \"Fjern paring\"\n\n#: lib/solaar/ui/action.py:86 lib/solaar/ui/diversion_rules.py:107\nmsgid \"Cancel\"\nmsgstr \"Avbryt\"\n\n#: lib/solaar/ui/common.py:35\nmsgid \"Permissions error\"\nmsgstr \"Rettighetsfeil\"\n\n#: lib/solaar/ui/common.py:37\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"\"\n\"Fant en Logitech-mottaker eller enhet (%s), men hadde ikke tillatelse til å \"\n\"åpne den.\"\n\n#: lib/solaar/ui/common.py:39\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"\"\n\"Hvis du nettopp har installert Solaar, kan du prøve å koble fra mottakeren \"\n\"eller enheten og deretter koble den til igjen.\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Cannot connect to device error\"\nmsgstr \"Kan ikke koble til enhet-feil\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"Fant en Logitech-mottaker eller -enhet på %s, men oppdaget en feil når den \"\n\"ble tilkoblet.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"\"\n\"Prøv å koble fra enheten og deretter koble den til igjen eller slå den av og \"\n\"på igjen.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Unpairing failed\"\nmsgstr \"Kunne ikke bryte paringen\"\n\n#: lib/solaar/ui/common.py:51\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"Mislyktes med å bryte paret %{device} og %{receiver}.\"\n\n#: lib/solaar/ui/common.py:56\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"Mottakeren rapporterte en feil, uten flere detaljer.\"\n\n#: lib/solaar/ui/config_panel.py:228\nmsgid \"Complete - ENTER to change\"\nmsgstr \"Fullfør - ENTER for å endre\"\n\n#: lib/solaar/ui/config_panel.py:228\nmsgid \"Incomplete\"\nmsgstr \"Ufullstendig\"\n\n#: lib/solaar/ui/config_panel.py:475 lib/solaar/ui/config_panel.py:527\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d verdi\"\nmsgstr[1] \"%d verdier\"\n\n#: lib/solaar/ui/config_panel.py:609\nmsgid \"Changes allowed\"\nmsgstr \"Endringer tillatt\"\n\n#: lib/solaar/ui/config_panel.py:610\nmsgid \"No changes allowed\"\nmsgstr \"Ingen endringer tillatt\"\n\n#: lib/solaar/ui/config_panel.py:611\nmsgid \"Ignore this setting\"\nmsgstr \"Ignorer denne innstillingen\"\n\n#: lib/solaar/ui/config_panel.py:655\nmsgid \"Working\"\nmsgstr \"Suksess\"\n\n#: lib/solaar/ui/config_panel.py:658\nmsgid \"Read/write operation failed.\"\nmsgstr \"Lese-/skriveoperasjonen mislyktes.\"\n\n#: lib/solaar/ui/desktop_notifications.py:114\nmsgid \"unspecified reason\"\nmsgstr \"uspesifisert årsak\"\n\n#: lib/solaar/ui/diversion_rules.py:69\nmsgid \"Built-in rules\"\nmsgstr \"Faste regler\"\n\n#: lib/solaar/ui/diversion_rules.py:69\nmsgid \"User-defined rules\"\nmsgstr \"Brukerdefinerte regler\"\n\n#: lib/solaar/ui/diversion_rules.py:71 lib/solaar/ui/diversion_rules.py:1089\nmsgid \"Rule\"\nmsgstr \"Regel\"\n\n#: lib/solaar/ui/diversion_rules.py:72 lib/solaar/ui/diversion_rules.py:348\n#: lib/solaar/ui/diversion_rules.py:475\nmsgid \"Sub-rule\"\nmsgstr \"Underregel\"\n\n#: lib/solaar/ui/diversion_rules.py:74\nmsgid \"[empty]\"\nmsgstr \"[tom]\"\n\n#: lib/solaar/ui/diversion_rules.py:98\nmsgid \"Make changes permanent?\"\nmsgstr \"Gjøre endringer permanente?\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"Yes\"\nmsgstr \"Ja\"\n\n#: lib/solaar/ui/diversion_rules.py:105\nmsgid \"No\"\nmsgstr \"Nei\"\n\n#: lib/solaar/ui/diversion_rules.py:110\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"Hvis du velger Nei, vil endringer gå tapt når Solaar lukkes.\"\n\n#: lib/solaar/ui/diversion_rules.py:239\nmsgid \"Paste here\"\nmsgstr \"Lim inn her\"\n\n#: lib/solaar/ui/diversion_rules.py:241\nmsgid \"Paste above\"\nmsgstr \"Lim inn ovenfor\"\n\n#: lib/solaar/ui/diversion_rules.py:243\nmsgid \"Paste below\"\nmsgstr \"Lim inn nedenfor\"\n\n#: lib/solaar/ui/diversion_rules.py:249\nmsgid \"Paste rule here\"\nmsgstr \"Lim inn regel her\"\n\n#: lib/solaar/ui/diversion_rules.py:251\nmsgid \"Paste rule above\"\nmsgstr \"Lim inn regel ovenfor\"\n\n#: lib/solaar/ui/diversion_rules.py:253\nmsgid \"Paste rule below\"\nmsgstr \"Lim inn regel nedenfor\"\n\n#: lib/solaar/ui/diversion_rules.py:257\nmsgid \"Paste rule\"\nmsgstr \"Lim inn regel\"\n\n#: lib/solaar/ui/diversion_rules.py:272\nmsgid \"Insert here\"\nmsgstr \"Sett inn her\"\n\n#: lib/solaar/ui/diversion_rules.py:274\nmsgid \"Insert above\"\nmsgstr \"Sett inn ovenfor\"\n\n#: lib/solaar/ui/diversion_rules.py:276\nmsgid \"Insert below\"\nmsgstr \"Sett inn nedenfor\"\n\n#: lib/solaar/ui/diversion_rules.py:282\nmsgid \"Insert new rule here\"\nmsgstr \"Sett inn ny regel her\"\n\n#: lib/solaar/ui/diversion_rules.py:284\nmsgid \"Insert new rule above\"\nmsgstr \"Sett inn ny regel ovenfor\"\n\n#: lib/solaar/ui/diversion_rules.py:286\nmsgid \"Insert new rule below\"\nmsgstr \"Sett inn ny regel nedenfor\"\n\n#: lib/solaar/ui/diversion_rules.py:313\nmsgid \"Flatten\"\nmsgstr \"Utflate\"\n\n#: lib/solaar/ui/diversion_rules.py:346\nmsgid \"Insert\"\nmsgstr \"Sett inn\"\n\n#: lib/solaar/ui/diversion_rules.py:349 lib/solaar/ui/diversion_rules.py:477\n#: lib/solaar/ui/diversion_rules.py:1121\nmsgid \"Or\"\nmsgstr \"Eller\"\n\n#: lib/solaar/ui/diversion_rules.py:350 lib/solaar/ui/diversion_rules.py:476\n#: lib/solaar/ui/diversion_rules.py:1107\nmsgid \"And\"\nmsgstr \"Og\"\n\n#: lib/solaar/ui/diversion_rules.py:352\nmsgid \"Condition\"\nmsgstr \"Betingelse\"\n\n#: lib/solaar/ui/diversion_rules.py:354 lib/solaar/ui/rule_conditions.py:145\nmsgid \"Feature\"\nmsgstr \"Karakteristikk\"\n\n#: lib/solaar/ui/diversion_rules.py:355 lib/solaar/ui/rule_conditions.py:179\nmsgid \"Report\"\nmsgstr \"Rapport\"\n\n#: lib/solaar/ui/diversion_rules.py:356 lib/solaar/ui/rule_conditions.py:60\nmsgid \"Process\"\nmsgstr \"Prosess\"\n\n#: lib/solaar/ui/diversion_rules.py:357\nmsgid \"Mouse process\"\nmsgstr \"Musprosess\"\n\n#: lib/solaar/ui/diversion_rules.py:358 lib/solaar/ui/rule_conditions.py:216\nmsgid \"Modifiers\"\nmsgstr \"Modifikatorer\"\n\n#: lib/solaar/ui/diversion_rules.py:359 lib/solaar/ui/rule_conditions.py:268\nmsgid \"Key\"\nmsgstr \"Tast\"\n\n#: lib/solaar/ui/diversion_rules.py:360 lib/solaar/ui/rule_conditions.py:309\nmsgid \"KeyIsDown\"\nmsgstr \"TastErNede\"\n\n#: lib/solaar/ui/diversion_rules.py:361 lib/solaar/ui/diversion_rules.py:1414\nmsgid \"Active\"\nmsgstr \"Aktiv\"\n\n#: lib/solaar/ui/diversion_rules.py:362 lib/solaar/ui/diversion_rules.py:1372\n#: lib/solaar/ui/diversion_rules.py:1423 lib/solaar/ui/diversion_rules.py:1470\nmsgid \"Device\"\nmsgstr \"Enhet\"\n\n#: lib/solaar/ui/diversion_rules.py:363 lib/solaar/ui/diversion_rules.py:1449\nmsgid \"Host\"\nmsgstr \"Vert\"\n\n#: lib/solaar/ui/diversion_rules.py:364 lib/solaar/ui/diversion_rules.py:1489\nmsgid \"Setting\"\nmsgstr \"Innstilling\"\n\n#: lib/solaar/ui/diversion_rules.py:365 lib/solaar/ui/rule_conditions.py:324\n#: lib/solaar/ui/rule_conditions.py:373\nmsgid \"Test\"\nmsgstr \"Test\"\n\n#: lib/solaar/ui/diversion_rules.py:366 lib/solaar/ui/rule_conditions.py:498\nmsgid \"Test bytes\"\nmsgstr \"Test bytes\"\n\n#: lib/solaar/ui/diversion_rules.py:367 lib/solaar/ui/rule_conditions.py:599\nmsgid \"Mouse Gesture\"\nmsgstr \"Musebevegelse\"\n\n#: lib/solaar/ui/diversion_rules.py:371\nmsgid \"Action\"\nmsgstr \"Handling\"\n\n#: lib/solaar/ui/diversion_rules.py:373 lib/solaar/ui/rule_actions.py:131\nmsgid \"Key press\"\nmsgstr \"Tastetrykk\"\n\n#: lib/solaar/ui/diversion_rules.py:374 lib/solaar/ui/rule_actions.py:182\nmsgid \"Mouse scroll\"\nmsgstr \"Muserulling\"\n\n#: lib/solaar/ui/diversion_rules.py:375 lib/solaar/ui/rule_actions.py:243\nmsgid \"Mouse click\"\nmsgstr \"Museklikk\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid \"Set\"\nmsgstr \"Still inn\"\n\n#: lib/solaar/ui/diversion_rules.py:377 lib/solaar/ui/rule_actions.py:313\nmsgid \"Execute\"\nmsgstr \"Utfør\"\n\n#: lib/solaar/ui/diversion_rules.py:378 lib/solaar/ui/diversion_rules.py:1152\nmsgid \"Later\"\nmsgstr \"Senere\"\n\n#: lib/solaar/ui/diversion_rules.py:407\nmsgid \"Insert new rule\"\nmsgstr \"Sett inn ny regel\"\n\n#: lib/solaar/ui/diversion_rules.py:427 lib/solaar/ui/rule_actions.py:74\n#: lib/solaar/ui/rule_actions.py:272 lib/solaar/ui/rule_conditions.py:546\nmsgid \"Delete\"\nmsgstr \"Slett\"\n\n#: lib/solaar/ui/diversion_rules.py:449\nmsgid \"Negate\"\nmsgstr \"Omvendt\"\n\n#: lib/solaar/ui/diversion_rules.py:473\nmsgid \"Wrap with\"\nmsgstr \"Pakk inn med\"\n\n#: lib/solaar/ui/diversion_rules.py:503\nmsgid \"Cut\"\nmsgstr \"Klipp ut\"\n\n#: lib/solaar/ui/diversion_rules.py:519\nmsgid \"Paste\"\nmsgstr \"Lim inn\"\n\n#: lib/solaar/ui/diversion_rules.py:525\nmsgid \"Copy\"\nmsgstr \"Kopier\"\n\n#: lib/solaar/ui/diversion_rules.py:534\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Solaar regel editor\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid \"Save changes\"\nmsgstr \"Lagre endringer\"\n\n#: lib/solaar/ui/diversion_rules.py:639\nmsgid \"Discard changes\"\nmsgstr \"Forkast endringer\"\n\n#: lib/solaar/ui/diversion_rules.py:1070\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"Denne editoren støtter foreløpig ikke den valgte regelkomponenten.\"\n\n#: lib/solaar/ui/diversion_rules.py:1132\nmsgid \"\"\n\"Number of seconds to delay.  Delay between 0 and 1 is done with higher \"\n\"precision.\"\nmsgstr \"\"\n\"Antall sekunder med forsinkelse. Forsinkelse mellom 0 og 1 gjøres med høyere \"\n\"presisjon.\"\n\n#: lib/solaar/ui/diversion_rules.py:1170\nmsgid \"Not\"\nmsgstr \"Ikke\"\n\n#: lib/solaar/ui/diversion_rules.py:1201\nmsgid \"Toggle\"\nmsgstr \"Veksle\"\n\n#: lib/solaar/ui/diversion_rules.py:1202\nmsgid \"True\"\nmsgstr \"Sann\"\n\n#: lib/solaar/ui/diversion_rules.py:1203\nmsgid \"False\"\nmsgstr \"Falsk\"\n\n#: lib/solaar/ui/diversion_rules.py:1216\nmsgid \"Unsupported setting\"\nmsgstr \"Innstillingen støttes ikke\"\n\n#: lib/solaar/ui/diversion_rules.py:1378 lib/solaar/ui/diversion_rules.py:1397\n#: lib/solaar/ui/diversion_rules.py:1476 lib/solaar/ui/diversion_rules.py:1731\n#: lib/solaar/ui/diversion_rules.py:1749\nmsgid \"Originating device\"\nmsgstr \"Kildeenhet\"\n\n#: lib/solaar/ui/diversion_rules.py:1410\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"Enheten er aktiv og innstillingene kan endres.\"\n\n#: lib/solaar/ui/diversion_rules.py:1419\nmsgid \"Device that originated the current notification.\"\nmsgstr \"Enheten som ga det gjeldende varselet.\"\n\n#: lib/solaar/ui/diversion_rules.py:1432\nmsgid \"Name of host computer.\"\nmsgstr \"Navn på vertsmaskin.\"\n\n#: lib/solaar/ui/diversion_rules.py:1503\nmsgid \"Value\"\nmsgstr \"Verdi\"\n\n#: lib/solaar/ui/diversion_rules.py:1512\nmsgid \"Item\"\nmsgstr \"Punkt\"\n\n#: lib/solaar/ui/diversion_rules.py:1791\nmsgid \"Change setting on device\"\nmsgstr \"Endre innstilling på enhet\"\n\n#: lib/solaar/ui/diversion_rules.py:1807\nmsgid \"Setting on device\"\nmsgstr \"Innstilling på enhet\"\n\n#: lib/solaar/ui/pair_window.py:37 lib/solaar/ui/pair_window.py:165\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: par ny enhet\"\n\n#: lib/solaar/ui/pair_window.py:39\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Bolt-mottakere er kun kompatible med Bolt-enheter.\"\n\n#: lib/solaar/ui/pair_window.py:41\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"\"\n\"Trykk på sammenkoblingsknappen eller -tasten til sammenkoblingslampen \"\n\"blinker raskt.\"\n\n#: lib/solaar/ui/pair_window.py:44\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"Unifying-mottakere er bare kompatible med Unifying-enheter.\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"Andre mottakere er kun kompatible med noen få enheter.\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid \"For most devices, turn on the device you want to pair.\"\nmsgstr \"For de fleste enheter slår du på enheten du vil pare.\"\n\n#: lib/solaar/ui/pair_window.py:49\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"Hvis enheten allerede er påslått, slå den av og på igjen.\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"Enheten må ikke pares med en påslått mottaker i nærheten.\"\n\n#: lib/solaar/ui/pair_window.py:54\nmsgid \"\"\n\"For devices with multiple channels, press, hold, and release the button for \"\n\"the channel you wish to pair\\n\"\n\"or use the channel switch button to select a channel and then press, hold, \"\n\"and release the channel switch button.\"\nmsgstr \"\"\n\"For enheter med flere kanaler, trykk, hold og slipp knappen for kanalen du \"\n\"ønsker å pare\\n\"\n\"eller bruk kanalbryterknappen for å velge en kanal og trykk, hold og slipp \"\n\"kanalbryterknappen.\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid \"The channel indicator light should be blinking rapidly.\"\nmsgstr \"Kanalindikatorlampen skal blinke raskt.\"\n\n#: lib/solaar/ui/pair_window.py:65\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"Denne mottakeren har %d gjenstående paring.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"Denne mottakeren har %d gjenstående paringer.\"\n\n#: lib/solaar/ui/pair_window.py:71\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"Kansellering nå vil ikke bruke opp en paring.\"\n\n#: lib/solaar/ui/pair_window.py:166\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"Skriv inn passordet på %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:169\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"Skriv inn %(passcode)s og trykk deretter på enter-tasten.\"\n\n#: lib/solaar/ui/pair_window.py:174\nmsgid \"left\"\nmsgstr \"venstre\"\n\n#: lib/solaar/ui/pair_window.py:174\nmsgid \"right\"\nmsgstr \"høyre\"\n\n#: lib/solaar/ui/pair_window.py:176\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"Trykk %(code)s\\n\"\n\"og trykk deretter på venstre og høyre knapp samtidig.\"\n\n#: lib/solaar/ui/pair_window.py:219\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"Den trådløse koblingen er ukryptert\"\n\n#: lib/solaar/ui/pair_window.py:224\nmsgid \"Found a new device:\"\nmsgstr \"Fant ny enhet:\"\n\n#: lib/solaar/ui/pair_window.py:245\nmsgid \"Pairing failed\"\nmsgstr \"Paringen feilet\"\n\n#: lib/solaar/ui/pair_window.py:247\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"\"\n\"Forsikre deg om at enheten er innen rekkevidde, og at den er tilstrekkelig \"\n\"oppladet.\"\n\n#: lib/solaar/ui/pair_window.py:249\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"En ny enhet ble påvist, men den er ukompatibel med denne mottakeren.\"\n\n#: lib/solaar/ui/pair_window.py:251\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"Fler parede enheter enn mottakeren kan støtte.\"\n\n#: lib/solaar/ui/pair_window.py:253\nmsgid \"No further details are available about the error.\"\nmsgstr \"Ingen ytterligere detaljer er tilgjengelig om feilen.\"\n\n#: lib/solaar/ui/rule_actions.py:48\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simuler en chorded (?) tast, klikk eller trykk ned eller slipp.\\n\"\n\"På Wayland krever dette skrivetilgang til /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:53\nmsgid \"Add key\"\nmsgstr \"Legg til tast\"\n\n#: lib/solaar/ui/rule_actions.py:56\nmsgid \"Click\"\nmsgstr \"Klikk\"\n\n#: lib/solaar/ui/rule_actions.py:59\nmsgid \"Depress\"\nmsgstr \"Nedtrykk\"\n\n#: lib/solaar/ui/rule_actions.py:62\nmsgid \"Release\"\nmsgstr \"Utløs\"\n\n#: lib/solaar/ui/rule_actions.py:146\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simuler en muserulling.\\n\"\n\"På Wayland krever dette skrivetilgang til /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:202\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simuler et museklikk.\\n\"\n\"På Wayland krever dette skrivetilgang til /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:205\nmsgid \"Button\"\nmsgstr \"Knapp\"\n\n#: lib/solaar/ui/rule_actions.py:206\nmsgid \"Count and Action\"\nmsgstr \"Antall og handling\"\n\n#: lib/solaar/ui/rule_actions.py:255\nmsgid \"Execute a command with arguments.\"\nmsgstr \"Utfør en kommando med argumenter.\"\n\n#: lib/solaar/ui/rule_actions.py:258\nmsgid \"Add argument\"\nmsgstr \"Legg til argument\"\n\n#: lib/solaar/ui/rule_conditions.py:43\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"X11 aktiv prosess. Kun til bruk i X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:73\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"X11-museprosess. Kun til bruk i X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:90\nmsgid \"MouseProcess\"\nmsgstr \"MusProsess\"\n\n#: lib/solaar/ui/rule_conditions.py:114\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"Funksjonsnavn på varsel som utløste regelbehandling.\"\n\n#: lib/solaar/ui/rule_conditions.py:160\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"Rapportnummer for varsling som utløser regelbehandling.\"\n\n#: lib/solaar/ui/rule_conditions.py:192\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"Aktive tastaturmodifikatorer. Ikke alltid tilgjengelig i Wayland.\"\n\n#: lib/solaar/ui/rule_conditions.py:232\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Omdirigert tast eller knapp som er trykket eller sluppet.\\n\"\n\"Bruk innstillingene for omdirigering av tast/knapp og omdiriger G-taster for \"\n\"å videresende taster og knapper.\"\n\n#: lib/solaar/ui/rule_conditions.py:241\nmsgid \"Key down\"\nmsgstr \"Tast ned\"\n\n#: lib/solaar/ui/rule_conditions.py:244\nmsgid \"Key up\"\nmsgstr \"Tast opp\"\n\n#: lib/solaar/ui/rule_conditions.py:284\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Omdirigert tast eller knapp er nede.\\n\"\n\"Bruk innstillingene for omdirigering av tast/knapp og omdirigerte G-taster \"\n\"for å videresende taster og knapper.\"\n\n#: lib/solaar/ui/rule_conditions.py:322\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"Testbetingelse på varsel som utløser regelbehandling.\"\n\n#: lib/solaar/ui/rule_conditions.py:326\nmsgid \"Parameter\"\nmsgstr \"Parameter\"\n\n#: lib/solaar/ui/rule_conditions.py:399\nmsgid \"begin (inclusive)\"\nmsgstr \"begynn (inklusiv)\"\n\n#: lib/solaar/ui/rule_conditions.py:400\nmsgid \"end (exclusive)\"\nmsgstr \"slutt (eksklusiv)\"\n\n#: lib/solaar/ui/rule_conditions.py:408\nmsgid \"range\"\nmsgstr \"område\"\n\n#: lib/solaar/ui/rule_conditions.py:411\nmsgid \"minimum\"\nmsgstr \"minimum\"\n\n#: lib/solaar/ui/rule_conditions.py:412\nmsgid \"maximum\"\nmsgstr \"maksimum\"\n\n#: lib/solaar/ui/rule_conditions.py:414\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"byte %(0)d til %(1)d, fra %(2)d til %(3)d\"\n\n#: lib/solaar/ui/rule_conditions.py:417 lib/solaar/ui/rule_conditions.py:418\nmsgid \"mask\"\nmsgstr \"maske\"\n\n#: lib/solaar/ui/rule_conditions.py:419\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"byte %(0)d til %(1)d, maske %(2)d\"\n\n#: lib/solaar/ui/rule_conditions.py:428\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\"Bit- eller områdetest på bytes i varselmelding som utløste regelbehandling.\"\n\n#: lib/solaar/ui/rule_conditions.py:438\nmsgid \"type\"\nmsgstr \"type\"\n\n#: lib/solaar/ui/rule_conditions.py:526\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"\"\n\"Musebevegelse med valgfri startknapp etterfulgt av null eller flere \"\n\"musebevegelser.\"\n\n#: lib/solaar/ui/rule_conditions.py:531\nmsgid \"Add movement\"\nmsgstr \"Legg til bevegelse\"\n\n#: lib/solaar/ui/tray.py:49\nmsgid \"No supported device found\"\nmsgstr \"Ingen støttede enheter er funnet\"\n\n#: lib/solaar/ui/tray.py:54 lib/solaar/ui/window.py:308\n#, python-format\nmsgid \"About %s\"\nmsgstr \"Om %s\"\n\n#: lib/solaar/ui/tray.py:55 lib/solaar/ui/window.py:306\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"Avslutt %s\"\n\n#: lib/solaar/ui/tray.py:270 lib/solaar/ui/tray.py:278\nmsgid \"no receiver\"\nmsgstr \"ingen mottaker\"\n\n#: lib/solaar/ui/tray.py:291 lib/solaar/ui/tray.py:296\nmsgid \"offline\"\nmsgstr \"avslått\"\n\n#: lib/solaar/ui/tray.py:294\nmsgid \"no status\"\nmsgstr \"ingen status\"\n\n#: lib/solaar/ui/window.py:90\nmsgid \"Scanning\"\nmsgstr \"Søker\"\n\n#: lib/solaar/ui/window.py:121\nmsgid \"Battery\"\nmsgstr \"Batteri\"\n\n#: lib/solaar/ui/window.py:124\nmsgid \"Wireless Link\"\nmsgstr \"Trådløs kobling\"\n\n#: lib/solaar/ui/window.py:128\nmsgid \"Lighting\"\nmsgstr \"Belysning\"\n\n#: lib/solaar/ui/window.py:162\nmsgid \"Show Technical Details\"\nmsgstr \"Vis tekniske detaljer\"\n\n#: lib/solaar/ui/window.py:178\nmsgid \"Pair new device\"\nmsgstr \"Par ny enhet\"\n\n#: lib/solaar/ui/window.py:196\nmsgid \"Select a device\"\nmsgstr \"Velg en enhet\"\n\n#: lib/solaar/ui/window.py:311\nmsgid \"Rule Editor\"\nmsgstr \"Regel editor\"\n\n#: lib/solaar/ui/window.py:504\nmsgid \"Path\"\nmsgstr \"Sti\"\n\n#: lib/solaar/ui/window.py:506\nmsgid \"USB ID\"\nmsgstr \"USB-ID\"\n\n#: lib/solaar/ui/window.py:509 lib/solaar/ui/window.py:511\n#: lib/solaar/ui/window.py:526 lib/solaar/ui/window.py:528\nmsgid \"Serial\"\nmsgstr \"Seriell\"\n\n#: lib/solaar/ui/window.py:515\nmsgid \"Index\"\nmsgstr \"Indeks\"\n\n#: lib/solaar/ui/window.py:517\nmsgid \"Wireless PID\"\nmsgstr \"Trådløs-PID\"\n\n#: lib/solaar/ui/window.py:519\nmsgid \"Product ID\"\nmsgstr \"Produkt-ID\"\n\n#: lib/solaar/ui/window.py:521\nmsgid \"Protocol\"\nmsgstr \"Protokoll\"\n\n#: lib/solaar/ui/window.py:521\nmsgid \"Unknown\"\nmsgstr \"Ukjent\"\n\n#: lib/solaar/ui/window.py:523\nmsgid \"Polling rate\"\nmsgstr \"Spørrerate\"\n\n#: lib/solaar/ui/window.py:530\nmsgid \"Unit ID\"\nmsgstr \"Enhets-ID\"\n\n#: lib/solaar/ui/window.py:544\nmsgid \"Notifications\"\nmsgstr \"Varsler\"\n\n#: lib/solaar/ui/window.py:588\nmsgid \"No device paired.\"\nmsgstr \"Ingen enhet paret.\"\n\n#: lib/solaar/ui/window.py:597\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"Inntil %(max_count)s enhet kan bli paret med denne mottakeren.\"\nmsgstr[1] \"Inntil %(max_count)s enheter kan bli paret med denne mottakeren.\"\n\n#: lib/solaar/ui/window.py:608\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"Denne mottakeren har %d gjenstående paring.\"\nmsgstr[1] \"Denne mottakeren har %d gjenstående paringer.\"\n\n#: lib/solaar/ui/window.py:665\nmsgid \"Battery Voltage\"\nmsgstr \"Batterispenning\"\n\n#: lib/solaar/ui/window.py:667\nmsgid \"Voltage reported by battery\"\nmsgstr \"Spenning rapportert av batteri\"\n\n#: lib/solaar/ui/window.py:669\nmsgid \"Battery Level\"\nmsgstr \"Batterinivå\"\n\n#: lib/solaar/ui/window.py:671\nmsgid \"Approximate level reported by battery\"\nmsgstr \"Omtrentlig nivå rapportert fra batteri\"\n\n#: lib/solaar/ui/window.py:678 lib/solaar/ui/window.py:680\nmsgid \"next reported \"\nmsgstr \"neste rapportert \"\n\n#: lib/solaar/ui/window.py:681\nmsgid \" and next level to be reported.\"\nmsgstr \" og neste nivå som blir rapportert.\"\n\n#: lib/solaar/ui/window.py:697\nmsgid \"encrypted\"\nmsgstr \"kryptert\"\n\n#: lib/solaar/ui/window.py:699\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"Den trådløse tilkoblingen mellom enheten og mottakeren er kryptert.\"\n\n#: lib/solaar/ui/window.py:701\nmsgid \"not encrypted\"\nmsgstr \"ukryptert\"\n\n#: lib/solaar/ui/window.py:705\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"Den trådløse koblingen mellom denne enheten og mottakeren er ikke kryptert.\\n\"\n\"Dette er et sikkerhetsproblem for pekeenheter, og et stort sikkerhetsproblem \"\n\"for enheter for tekstinndata.\"\n\n#: lib/solaar/ui/window.py:721\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d lux\"\n\n#~ msgid \"\"\n#~ \"\\n\"\n#~ \"\\n\"\n#~ \"This receiver has %d pairing(s) remaining.\"\n#~ msgstr \"\"\n#~ \"\\n\"\n#~ \"\\n\"\n#~ \"Denne mottakeren har %d gjenstående paringer.\"\n\n#, python-format\n#~ msgid \"%(rate)d ms (%(rate_hz)dHz)\"\n#~ msgstr \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#~ msgid \"Actions\"\n#~ msgstr \"Handlinger\"\n\n#~ msgid \"Add action\"\n#~ msgstr \"Legg til handling\"\n\n#~ msgid \"\"\n#~ \"Adjust the DPI by sliding the mouse horizontally while holding the button \"\n#~ \"down.\"\n#~ msgstr \"\"\n#~ \"Juster DPI ved å skyve musen horisontalt mens du holder knappen nede.\"\n\n#~ msgid \"\"\n#~ \"Automatically switch the mouse wheel between ratchet and freespin mode.\\n\"\n#~ \"The mouse wheel is always free at 0, and always locked at 50\"\n#~ msgstr \"\"\n#~ \"Bytt mushjulet automatisk mellom sperre- og frispinnmodus.\\n\"\n#~ \"Mushjulet er alltid fritt på 0, og låses alltid på 50\"\n\n#~ msgid \"\"\n#~ \"Automatically switch the mouse wheel between ratchet and freespin mode.\\n\"\n#~ \"The mouse wheel is always free at 0, and always ratcheted at 50\"\n#~ msgstr \"\"\n#~ \"Bytt automatisk rullehjulet mellom skralle- og frispinn-modus.\\n\"\n#~ \"Rullehjulet er alltid fritt ved 0, og med skralle ved 50\"\n\n#~ msgid \"Battery information unknown.\"\n#~ msgstr \"Ukjent batteriinformasjon\"\n\n#, python-format\n#~ msgid \"Battery: %(level)s\"\n#~ msgstr \"Batteri: %(level)s\"\n\n#, python-format\n#~ msgid \"Battery: %(percent)d%%\"\n#~ msgstr \"Batteri: %(percent)d%%\"\n\n#~ msgid \"Count\"\n#~ msgstr \"Antall\"\n\n#~ msgid \"DPI Sliding Adjustment\"\n#~ msgstr \"DPI-glidejustering\"\n\n#~ msgid \"Divert G Keys\"\n#~ msgstr \"Omdiriger G-taster\"\n\n#~ msgid \"\"\n#~ \"Diverted key or button depressed or released.\\n\"\n#~ \"Use the Key/Button Diversion setting to divert keys and buttons.\"\n#~ msgstr \"\"\n#~ \"Omdirigert tast eller knapp, trykket eller sluppet.\\n\"\n#~ \"Bruk innstillingen for omdirigering av tast/knapp for å viderekoble \"\n#~ \"taster og knapper.\"\n\n#~ msgid \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr \"Slår i praksis av tommelrulling i Linux.\"\n\n#~ msgid \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr \"Slår i praksis av hjulrulling i Linux.\"\n\n#~ msgid \"\"\n#~ \"Enable onboard profiles, which often control report rate and keyboard \"\n#~ \"lighting\"\n#~ msgstr \"\"\n#~ \"Aktiver innebygde profiler, som ofte kontrollerer rapporthastighet og \"\n#~ \"tastaturbelysning\"\n\n#~ msgid \"\"\n#~ \"For more information see the Solaar installation directions\\n\"\n#~ \"at https://pwr-solaar.github.io/Solaar/installation\"\n#~ msgstr \"\"\n#~ \"For mer informasjon, se Solaar-installasjonsanvisningene\\n\"\n#~ \"på https://pwr-solaar.github.io/Solaar/installation\"\n\n#, python-format\n#~ msgid \"\"\n#~ \"Found a Logitech Receiver (%s), but did not have permission to open it.\"\n#~ msgstr \"\"\n#~ \"Fant en Logitech-mottaker (%s), men mangler rettigheter til å åpne den.\"\n\n#~ msgid \"Frequency of device polling, in milliseconds\"\n#~ msgstr \"Frekvens på enhetsspørring, i millisekunder\"\n\n#~ msgid \"HID++ Scrolling\"\n#~ msgstr \"HID++ rulling\"\n\n#~ msgid \"HID++ Thumb Scrolling\"\n#~ msgstr \"HID++ tommelrulling\"\n\n#~ msgid \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr \"HID++ modus for horisontal rulling med tommelhjulet.\"\n\n#~ msgid \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr \"HID++ modus for vertikal rulling med hjulet.\"\n\n#~ msgid \"High Resolution Scrolling\"\n#~ msgstr \"Høyoppløselig rulling\"\n\n#~ msgid \"High Resolution Wheel Invert\"\n#~ msgstr \"Inverter høy rulleoppløsning\"\n\n#~ msgid \"High-sensitivity wheel invert direction for vertical scroll.\"\n#~ msgstr \"Inverter retning for høy vertikal rulleoppløsning.\"\n\n#~ msgid \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr \"Hvis enheten allerede er slått på, slå den av og på igjen.\"\n\n#~ msgid \"\"\n#~ \"If you've just installed Solaar, try removing the receiver and plugging \"\n#~ \"it back in.\"\n#~ msgstr \"\"\n#~ \"Hvis du nettopp har installert Solaar, forsøk å fjerne mottakeren og \"\n#~ \"plugg den inn igjen.\"\n\n#~ msgid \"Invert thumb scroll direction.\"\n#~ msgstr \"Inverter retning på tommelrulling.\"\n\n#, python-format\n#~ msgid \"Lighting: %(level)s lux\"\n#~ msgstr \"Belysning: %(level)s lux\"\n\n#~ msgid \"\"\n#~ \"Make G keys send GKEY HID++ notifications (which trigger Solaar rules but \"\n#~ \"are otherwise ignored).\"\n#~ msgstr \"\"\n#~ \"Få G-taster til å sende GKEY HID++-varsler (som utløser Solaar-regler, \"\n#~ \"men som ellers ignoreres).\"\n\n#~ msgid \"\"\n#~ \"Make the key or button send HID++ notifications (which trigger Solaar \"\n#~ \"rules but are otherwise ignored).\"\n#~ msgstr \"\"\n#~ \"Få tasten eller knappen til å sende HID++-varsler (som utløser Solaar-\"\n#~ \"regler, men ellers ignoreres).\"\n\n#~ msgid \"May also make M keys and MR key send HID++ notifications\"\n#~ msgstr \"Kan også få M-taster og MR-taster til å sende HID++-varsler\"\n\n#~ msgid \"No Logitech device found\"\n#~ msgstr \"Finner ingen Logitech-enhet\"\n\n#~ msgid \"No Logitech receiver found\"\n#~ msgstr \"Ingen Logitech-mottaker funnet\"\n\n#~ msgid \"Only one device can be paired to this receiver.\"\n#~ msgstr \"Kun én enhet kan pares med denne mottakeren.\"\n\n#~ msgid \"Polling Rate (ms)\"\n#~ msgstr \"Spørrerate (ms)\"\n\n#~ msgid \"Report number  of notification triggering rule processing.\"\n#~ msgstr \"Rapportnummer på varsel som utløste regelbehandling.\"\n\n#~ msgid \"Scroll Wheel Rachet\"\n#~ msgstr \"Skrallen for rullehjulet\"\n\n#~ msgid \"Send a gesture by sliding the mouse while holding the button down.\"\n#~ msgstr \"Send en bevegelse ved å skyve musen mens du holder knappen nede.\"\n\n#~ msgid \"\"\n#~ \"Shows status of devices connected\\n\"\n#~ \"through wireless Logitech receivers.\"\n#~ msgstr \"\"\n#~ \"Viser status for enheter tilkoblet\\n\"\n#~ \"via trådløse Logitech-mottakere.\"\n\n#~ msgid \"Smooth Scrolling\"\n#~ msgstr \"Myk rulling\"\n\n#~ msgid \"Solaar depends on a udev file that is not present\"\n#~ msgstr \"Solaar er avhengig av en udev-fil som ikke finnes\"\n\n#~ msgid \"The receiver only supports %d paired device(s).\"\n#~ msgstr \"Mottakeren kan kun støtte %d parede enhet(er).\"\n\n#~ msgid \"The receiver was unplugged.\"\n#~ msgstr \"Mottakeren ble fjernet.\"\n\n#~ msgid \"\"\n#~ \"The wireless link between this device and its receiver is not encrypted.\\n\"\n#~ \"\\n\"\n#~ \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~ \"security issue.\\n\"\n#~ \"\\n\"\n#~ \"It is, however, a major security issue for text-input devices (keyboards, \"\n#~ \"numpads),\\n\"\n#~ \"because typed text can be sniffed inconspicuously by 3rd parties within \"\n#~ \"range.\"\n#~ msgstr \"\"\n#~ \"Den trådløse koblingen mellom denne enheten og mottakeren er ukryptert.\\n\"\n#~ \"\\n\"\n#~ \"For pekeenheter (mus, styrekuler, styreflater) er dette en mindre \"\n#~ \"sikkerhetsproblem.\\n\"\n#~ \"\\n\"\n#~ \"Det er imidlertid et viktig sikkerhetsproblem for tekstinndataenheter \"\n#~ \"(tastaturer, numpads),\\n\"\n#~ \"fordi maskinskrevet tekst kan bli sniffet ubemerket av tredjeparter innen \"\n#~ \"rekkevidde.\"\n\n#~ msgid \"This receiver has %d pairing(s) remaining.\"\n#~ msgstr \"Denne mottakeren har %d gjenstående paring(er).\"\n\n#~ msgid \"Thumb Scroll Invert\"\n#~ msgstr \"Inverter tommelrulling\"\n\n#~ msgid \"Top-most coordinate.\"\n#~ msgstr \"Koordinat lengst oppe.\"\n\n#~ msgid \"\"\n#~ \"Try removing the device and plugging it back in or turning it off and \"\n#~ \"then on.\"\n#~ msgstr \"\"\n#~ \"Prøv å fjerne enheten og koble den til igjen eller slå den av og på.\"\n\n#~ msgid \"Turn illumination on or off on keyboard.\"\n#~ msgstr \"Slå på eller av belysning for tastaturet.\"\n\n#~ msgid \"Turn on the device you want to pair.\"\n#~ msgstr \"Slå på enheten du ønsker å pare.\"\n\n#~ msgid \"USB id\"\n#~ msgstr \"USB-id\"\n\n#~ msgid \"Unexpected device number (%s) in notification %s.\"\n#~ msgstr \"Uventet enhetsnummer (%s) i varsel %s.\"\n\n#~ msgid \"Wheel Resolution\"\n#~ msgstr \"Hjuloppløsning\"\n\n#~ msgid \"You may have to first turn the device off and on again.\"\n#~ msgstr \"Først må du kanskje slå enheten av og på igjen.\"\n\n#~ msgid \"height\"\n#~ msgstr \"høyde\"\n\n#~ msgid \"last known\"\n#~ msgstr \"sist kjent\"\n\n#~ msgid \"next \"\n#~ msgstr \"neste \"\n\n#~ msgid \"none\"\n#~ msgstr \"ingen\"\n\n#~ msgid \"top\"\n#~ msgstr \"top\"\n\n#~ msgid \"unknown\"\n#~ msgstr \"ukjent\"\n\n#~ msgid \"width\"\n#~ msgstr \"bredde\"\n"
  },
  {
    "path": "po/nl.po",
    "content": "# Dutch translations for solaar package\n# Copyright (C) 2021 SOLAAR'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the Solaar package.\n#\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 1.0.1\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n        \"PO-Revision-Date: 2021-01-15 22:03+0100\\n\"\n        \"Last-Translator: Heimen Stoffels <vistausss@outlook.com>\\n\"\n        \"Language-Team: \\n\"\n        \"Language: nl\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n        \"X-Generator: Poedit 2.4.2\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid   \"Bolt Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid   \"Unifying Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid   \"Nano Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"empty\"\nmsgstr  \"leeg\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"critical\"\nmsgstr  \"bijna leeg\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"low\"\nmsgstr  \"laag\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"average\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid   \"good\"\nmsgstr  \"goed\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"full\"\nmsgstr  \"opgeladen\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"discharging\"\nmsgstr  \"bezig met ontladen\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"recharging\"\nmsgstr  \"bezig met opladen\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid   \"charging\"\nmsgstr  \"bezig met opladen\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"not charging\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"almost full\"\nmsgstr  \"bijna opgeladen\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"charged\"\nmsgstr  \"opgeladen\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"slow recharge\"\nmsgstr  \"langzaam opladen\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"invalid battery\"\nmsgstr  \"verkeerde batterij\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"thermal error\"\nmsgstr  \"temperatuurfout\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"error\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid   \"standard\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"fast\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid   \"device timeout\"\nmsgstr  \"time-out opgetreden\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid   \"device not supported\"\nmsgstr  \"apparaat wordt niet ondersteund\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"too many devices\"\nmsgstr  \"te veel apparaten\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"sequence timeout\"\nmsgstr  \"meerdere time-outs\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid   \"Firmware\"\nmsgstr  \"Firmware\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Bootloader\"\nmsgstr  \"Opstartlader\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Hardware\"\nmsgstr  \"Hardware\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Other\"\nmsgstr  \"Overig\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Smart Shift\"\nmsgstr  \"Slim schakelen\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"DPI Switch\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Left Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Right Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Left Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Right Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"Mouse Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid   \"pressed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid   \"released\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is closed\"\nmsgstr  \"koppelvergendeling ingeschakeld\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is open\"\nmsgstr  \"koppelvergendeling uitgeschakeld\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid   \"connected\"\nmsgstr  \"verbonden\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid   \"disconnected\"\nmsgstr  \"verbinding verbroken\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid   \"unpaired\"\nmsgstr  \"niet gekoppeld\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid   \"powered on\"\nmsgstr  \"ingeschakeld\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid   \"register\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid   \"feature\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid   \"Swap Fx function\"\nmsgstr  \"Fx-functies omdraaien\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"Schakel dit in om de speciale functies van F1-F12 te gebruiken -\\n\"\n        \"de standaard functies kunnen worden geactiveerd met Fn + F1-F12.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"Schakel dit in om de standaard functies van F1-F12 te gebruiken -\\n\"\n        \"de speciale functies kunnen worden geactiveerd met Fn + F1-F12.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid   \"Hand Detection\"\nmsgstr  \"Handpalmdetectie\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"Schakelt de verlichting in als u beide handen boven het toetsenbord \"\n        \"houdt.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"Vloeiend scrollen\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"Hogegevoeligheidsmodus voor verticaal scrollen.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid   \"Side Scrolling\"\nmsgstr  \"Zijwaarts scrollen\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"Schakel dit uit om aangepaste knopgebeurtenissen te versturen als u \"\n        \"het scrollwiel\\n\"\n        \"opzijduwt in plaats van de standaard gebeurtenissen.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"Muisgevoeligheid\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid   \"Backlight\"\nmsgstr  \"Achtergrondverlichting\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid   \"Turn illumination on or off on keyboard.\"\nmsgstr  \"Schakel de toetsenbordverlichting in of uit.\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"Scrollen met hoge resolutie\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"Scrollrichting\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"Keer de modus van verticaal scrollen met het scrollwiel om.\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"Scrollresolutie\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"Gevoeligheid (cursorsnelheid)\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"Muisversnelling (256 is de standaard versnelling).\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"Duimwielrichting\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"Keer de scrollrichting van het duimwiel om.\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid   \"Onboard Profiles\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid   \"Enable onboard profiles, which often control report rate and \"\n        \"keyboard lighting\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid   \"Polling Rate (ms)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid   \"Frequency of device polling, in milliseconds\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid   \"Divert crown events\"\nmsgstr  \"Kroongebeurtenissen omleiden\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Laat de kroon een HID++-melding versturen (welke Solaar's regels \"\n        \"volgen, maar verder genegeerd worden).\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid   \"Divert G Keys\"\nmsgstr  \"G-toetsen omleiden\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid   \"Make G keys send GKEY HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Laat de G-toetsen een HID++-melding versturen (welke Solaar's regels \"\n        \"volgen, maar verder genegeerd worden).\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid   \"May also make M keys and MR key send HID++ notifications\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Freespinning\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid   \"Key/Button Actions\"\nmsgstr  \"Toets-/Knopacties\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"Pas de actie van een toets of knop aan.\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"Let op: het aanpassen van belangrijke acties (zoals die van de \"\n        \"linkermuisknop) kan leiden tot een onbruikbaar systeem.\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"Toets-/Knopomleiding\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Diverted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid   \"Mouse Gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Regular\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid   \"Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"Gevoeligheid (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid   \"Off\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid   \"Disable keys\"\nmsgstr  \"Toetsen uitschakelen\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"Schakel specifieke toetsen op het toetsenbord uit.\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"Schakelt de %s-toets uit.\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid   \"Set OS\"\nmsgstr  \"Besturingssysteem instellen\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"Pas de toetsen aan aan het besturingssysteem.\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid   \"Change Host\"\nmsgstr  \"Host veranderen\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"Schakel over naar een andere host.\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Performs a left click.\"\nmsgstr  \"Voert een linkermuisklik uit.\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Single tap\"\nmsgstr  \"Eenmaal tikken\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Performs a right click.\"\nmsgstr  \"Voert een rechtermuisklik uit.\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"Eenmaal tikken met twee vingers\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"Eenmaal tikken met drie vingers\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Double tap\"\nmsgstr  \"Dubbeltikken\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Performs a double click.\"\nmsgstr  \"Voert een dubbele klik uit.\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"Dubbeltikken met twee vingers\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"Dubbeltikken met drie vingers\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"Verplaats items door na het dubbeltikken uw vinger te verplaatsen.\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Tap and drag\"\nmsgstr  \"Tikken-en-slepen\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"Verplaats items door na het dubbeltikken uw vingers te verplaatsen.\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"Tikken-en-slepen met twee vingers\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"Tikken-en-slepen met drie vingers\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"Schakel tik- en randgebaren uit (gelijk aan Fn+linkermuisklik).\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"Tik- en randgebaren uitschakelen\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid   \"Scroll with one finger\"\nmsgstr  \"Scrollen met één vinger\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scrolls.\"\nmsgstr  \"Scrollt.\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"Scrollen met twee vingers\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"Horizontaal scrollen met twee vingers\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"Scrollt horizontaal.\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"Verticaal scrollen met twee vingers\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"Scrollt verticaal.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"Draai de scrollrichting om.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Natural scrolling\"\nmsgstr  \"Natuurlijk scrollen\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"Schakel het duimwiel in.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Thumbwheel\"\nmsgstr  \"Duimwiel\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"Vegen vanaf bovenkant\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"Vegen vanaf linkerkant\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"Vegen vanaf rechterkant\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"Vegen vanaf onderkant\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"Vegen vanaf linkerkant (twee vingers)\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"Vegen vanaf rechterkant (twee vingers)\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"Vegen vanaf onderkant (twee vingers)\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"Vegen vanaf bovenkant (twee vingers)\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"Knijp om uit te zoomen; spreid om in te zoomen.\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"Zoomen met twee vingers.\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"Knijp om uit te zoomen.\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"Spreid om in te zoomen.\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"Zoomen met drie vingers.\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"Zoomen met twee vingers\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid   \"Pixel zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid   \"Ratio zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Scale factor\"\nmsgstr  \"Schaalfactor\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left\"\nmsgstr  \"Links\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"Het meest linker coördinaat.\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width\"\nmsgstr  \"Breedte\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width.\"\nmsgstr  \"Breedte.\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height\"\nmsgstr  \"Hoogte\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height.\"\nmsgstr  \"Hoogte.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Cursor speed.\"\nmsgstr  \"Cursorsnelheid.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Scale\"\nmsgstr  \"Schaal\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid   \"Gestures\"\nmsgstr  \"Gebaren\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"Pas het gedrag van het trackpad/de muis aan.\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid   \"Gestures Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid   \"Gesture params\"\nmsgstr  \"Gebarenwaarden\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"Pas de numerieke waarden van het trackpad/de muis aan.\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid   \"M-Key LEDs\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid   \"MR-Key LED\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Sidetone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid   \"Set sidetone level.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid   \"Equalizer\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid   \"Hz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid   \"Power Management\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid   \"No paired devices.\"\nmsgstr  \"Geen apparaten gekoppeld.\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"%(count)s gekoppeld apparaat.\"\nmsgstr[1]       \"%(count)s gekoppelde apparaten.\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid   \"Battery: %(level)s\"\nmsgstr  \"Batterijniveau: %(level)s\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid   \"Battery: %(percent)d%%\"\nmsgstr  \"Batterijniveau: %(percent)d%%\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid   \"Lighting: %(level)s lux\"\nmsgstr  \"Verlichting: %(level)s lux\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"Batterijniveau: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"Batterijniveau: %(percent)d%% (%(status)s)\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid   \"Permissions error\"\nmsgstr  \"Machtigingsfout\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid   \"Unpairing failed\"\nmsgstr  \"Loskoppelen mislukt\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"'%{device}' kan niet worden losgekoppeld van '%{receiver}'.\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"Er is een fout opgetreden zonder nadere informatie.\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:44\nmsgid   \"Additional Programming\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:45\nmsgid   \"GUI design\"\nmsgstr  \"Toepassingsontwerp\"\n\n#: lib/solaar/ui/about.py:47\nmsgid   \"Testing\"\nmsgstr  \"Testen\"\n\n#: lib/solaar/ui/about.py:54\nmsgid   \"Logitech documentation\"\nmsgstr  \"Logitech-documentatie\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid   \"Unpair\"\nmsgstr  \"Loskoppelen\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid   \"Cancel\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Incomplete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"%d waarde\"\nmsgstr[1]       \"%d waarden\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid   \"Changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid   \"No changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid   \"Ignore this setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid   \"Working\"\nmsgstr  \"Aan het werk\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"Uitlezen/Wegschrijven mislukt.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"Built-in rules\"\nmsgstr  \"Meegeleverde regels\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"User-defined rules\"\nmsgstr  \"Eigen regels\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid   \"Rule\"\nmsgstr  \"Regel\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid   \"Sub-rule\"\nmsgstr  \"Aanvullende regel\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid   \"[empty]\"\nmsgstr  \"[leeg]\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"Solaar-regelbewerker\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Make changes permanent?\"\nmsgstr  \"Wilt u de wijzigingen permanent opslaan?\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid   \"Yes\"\nmsgstr  \"Ja\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid   \"No\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"Als u 'Nee' kiest, dan worden ze verworpen nadat Solaar is \"\n        \"afgesloten.\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid   \"Save changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid   \"Discard changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid   \"Insert here\"\nmsgstr  \"Hier invoegen\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid   \"Insert above\"\nmsgstr  \"Hierboven invoegen\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid   \"Insert below\"\nmsgstr  \"Hieronder invoegen\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid   \"Insert new rule here\"\nmsgstr  \"Nieuwe regel hier invoegen\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid   \"Insert new rule above\"\nmsgstr  \"Nieuwe regel hierboven invoegen\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Insert new rule below\"\nmsgstr  \"Nieuwe regel hieronder invoegen\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid   \"Paste here\"\nmsgstr  \"Hier plakken\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid   \"Paste above\"\nmsgstr  \"Hierboven plakken\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid   \"Paste below\"\nmsgstr  \"Hieronder plakken\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid   \"Paste rule here\"\nmsgstr  \"Regel hier plakken\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid   \"Paste rule above\"\nmsgstr  \"Regel hierboven plakken\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Paste rule below\"\nmsgstr  \"Regel hieronder plakken\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid   \"Paste rule\"\nmsgstr  \"Regel plakken\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid   \"Flatten\"\nmsgstr  \"Vlakmaken\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Insert\"\nmsgstr  \"Invoegen\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Or\"\nmsgstr  \"Of\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid   \"And\"\nmsgstr  \"En\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid   \"Condition\"\nmsgstr  \"Omstandigheid\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid   \"Feature\"\nmsgstr  \"Functie\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid   \"Report\"\nmsgstr  \"Melden\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid   \"Process\"\nmsgstr  \"Proces\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid   \"Mouse process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid   \"Modifiers\"\nmsgstr  \"Sneltoetsen\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid   \"Key\"\nmsgstr  \"Toets\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid   \"KeyIsDown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid   \"Active\"\nmsgstr  \"Actief\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid   \"Device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid   \"Setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid   \"Test\"\nmsgstr  \"Testen\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid   \"Test bytes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid   \"Mouse Gesture\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid   \"Action\"\nmsgstr  \"Actie\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid   \"Key press\"\nmsgstr  \"Toetsaanslag\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid   \"Mouse scroll\"\nmsgstr  \"Scrollbeweging\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid   \"Mouse click\"\nmsgstr  \"Muisklik\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Set\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid   \"Execute\"\nmsgstr  \"Uitvoeren\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Later\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Insert new rule\"\nmsgstr  \"Nieuwe regel invoegen\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid   \"Delete\"\nmsgstr  \"Verwijderen\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid   \"Negate\"\nmsgstr  \"Negeren\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid   \"Wrap with\"\nmsgstr  \"Omslaan met\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid   \"Cut\"\nmsgstr  \"Knippen\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid   \"Paste\"\nmsgstr  \"Plakken\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid   \"Copy\"\nmsgstr  \"Kopiëren\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"Deze bewerker heeft nog geen ondersteuning voor het geselecteerde \"\n        \"onderdeel.\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid   \"Number of seconds to delay.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid   \"Not\"\nmsgstr  \"Niet\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid   \"MouseProcess\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid   \"Key down\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid   \"Key up\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid   \"Parameter\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid   \"begin (inclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid   \"end (exclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid   \"range\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid   \"minimum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid   \"maximum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid   \"mask\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid   \"type\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid   \"Add movement\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid   \"Add key\"\nmsgstr  \"Toets toevoegen\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid   \"Click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid   \"Depress\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid   \"Release\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid   \"Button\"\nmsgstr  \"Knop\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid   \"Count and Action\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid   \"Add argument\"\nmsgstr  \"Aanvullende optie toevoegen\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"Toggle\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"True\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid   \"False\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid   \"Unsupported setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid   \"Originating device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid   \"Name of host computer.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid   \"Value\"\nmsgstr  \"Waarde\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid   \"Item\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid   \"Change setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid   \"Setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid   \"offline\"\nmsgstr  \"offline\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"%(receiver_name)s: nieuw apparaat aankoppelen\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"left\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"right\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid   \"Pairing failed\"\nmsgstr  \"Koppelen mislukt\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"Zorg er voor dat het apparaat binnen handbereik is en voldoende is \"\n        \"opgeladen.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"Er is een nieuw apparaat aangetroffen dat niet compatibel is met \"\n        \"deze ontvanger.\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"Er zijn meer gekoppelde apparaten dan de ontvanger aankan.\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"Er is een fout opgetreden zonder nadere informatie.\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid   \"Found a new device:\"\nmsgstr  \"Nieuw apparaat aangetroffen:\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"De draadloze verbinding is onversleuteld\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid   \"You may have to first turn the device off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid   \"Turn on the device you want to pair.\"\nmsgstr  \"Schakel het te koppelen apparaat in.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\\n\"\n        \"\\n\"\n        \"Er kan nog %d apparaat worden gekoppeld aan deze ontvanger.\"\nmsgstr[1]       \"\\n\"\n        \"\\n\"\n        \"Er kunnen nog %d apparaten worden gekoppeld aan deze ontvanger.\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\\n\"\n        \"Als u nu afbreekt, kunt u nog steeds iets koppelen.\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid   \"No supported device found\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"Info %s\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"%s afsluiten\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid   \"no receiver\"\nmsgstr  \"geen ontvanger\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid   \"no status\"\nmsgstr  \"geen status\"\n\n#: lib/solaar/ui/window.py:96\nmsgid   \"Scanning\"\nmsgstr  \"Bezig met zoeken...\"\n\n#: lib/solaar/ui/window.py:129\nmsgid   \"Battery\"\nmsgstr  \"Batterij\"\n\n#: lib/solaar/ui/window.py:132\nmsgid   \"Wireless Link\"\nmsgstr  \"Draadloze verbinding\"\n\n#: lib/solaar/ui/window.py:136\nmsgid   \"Lighting\"\nmsgstr  \"Verlichting\"\n\n#: lib/solaar/ui/window.py:170\nmsgid   \"Show Technical Details\"\nmsgstr  \"Technische informatie tonen\"\n\n#: lib/solaar/ui/window.py:186\nmsgid   \"Pair new device\"\nmsgstr  \"Nieuw apparaat aankoppelen\"\n\n#: lib/solaar/ui/window.py:205\nmsgid   \"Select a device\"\nmsgstr  \"Kies een apparaat\"\n\n#: lib/solaar/ui/window.py:322\nmsgid   \"Rule Editor\"\nmsgstr  \"Regelbewerker\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Path\"\nmsgstr  \"Pad\"\n\n#: lib/solaar/ui/window.py:536\nmsgid   \"USB ID\"\nmsgstr  \"USB-id\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid   \"Serial\"\nmsgstr  \"Serie\"\n\n#: lib/solaar/ui/window.py:545\nmsgid   \"Index\"\nmsgstr  \"Index\"\n\n#: lib/solaar/ui/window.py:547\nmsgid   \"Wireless PID\"\nmsgstr  \"Draadloze pid\"\n\n#: lib/solaar/ui/window.py:549\nmsgid   \"Product ID\"\nmsgstr  \"Product-id\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Protocol\"\nmsgstr  \"Protocol\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Unknown\"\nmsgstr  \"Onbekend\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid   \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr  \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#: lib/solaar/ui/window.py:554\nmsgid   \"Polling rate\"\nmsgstr  \"Controlesnelheid\"\n\n#: lib/solaar/ui/window.py:565\nmsgid   \"Unit ID\"\nmsgstr  \"Apparaat-id\"\n\n#: lib/solaar/ui/window.py:576\nmsgid   \"none\"\nmsgstr  \"geen\"\n\n#: lib/solaar/ui/window.py:577\nmsgid   \"Notifications\"\nmsgstr  \"Meldingen\"\n\n#: lib/solaar/ui/window.py:621\nmsgid   \"No device paired.\"\nmsgstr  \"Geen apparaat gekoppeld.\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"Er kan slechts %(max_count)s apparaat worden gekoppeld aan \"\n        \"deze ontvanger.\"\nmsgstr[1]       \"Er kunnen slechts %(max_count)s apparaten worden gekoppeld \"\n        \"aan deze ontvanger.\"\n\n#: lib/solaar/ui/window.py:634\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"Er kan slechts één apparaat worden gekoppeld aan deze ontvanger.\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"Er kan nog %d apparaat worden gekoppeld aan deze ontvanger.\"\nmsgstr[1]       \"Er kunnen nog %d apparaten worden gekoppeld aan deze \"\n        \"ontvanger.\"\n\n#: lib/solaar/ui/window.py:692\nmsgid   \"Battery Voltage\"\nmsgstr  \"Batterijvoltage\"\n\n#: lib/solaar/ui/window.py:694\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"Het door de batterij gemelde voltage\"\n\n#: lib/solaar/ui/window.py:696\nmsgid   \"Battery Level\"\nmsgstr  \"Batterijniveau\"\n\n#: lib/solaar/ui/window.py:698\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"Het door de batterij geschatte niveau\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid   \"next reported \"\nmsgstr  \"volgende melding \"\n\n#: lib/solaar/ui/window.py:708\nmsgid   \" and next level to be reported.\"\nmsgstr  \" en het volgende te melden niveau.\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"last known\"\nmsgstr  \"laatst bekend\"\n\n#: lib/solaar/ui/window.py:724\nmsgid   \"encrypted\"\nmsgstr  \"versleuteld\"\n\n#: lib/solaar/ui/window.py:726\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"De draadloze verbinding tussen dit apparaat en de ontvanger is \"\n        \"versleuteld.\"\n\n#: lib/solaar/ui/window.py:728\nmsgid   \"not encrypted\"\nmsgstr  \"onversleuteld\"\n\n#: lib/solaar/ui/window.py:732\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"%(light_level)d lux\"\n\n#, python-format\n#~ msgid        \"%(battery_level)s\"\n#~ msgstr       \"%(battery_level)s\"\n\n#, python-format\n#~ msgid        \"%(battery_percent)d%%\"\n#~ msgstr       \"%(battery_percent)d%%\"\n\n#~ msgid        \"About\"\n#~ msgstr       \"Over\"\n\n#~ msgid        \"Adjust the DPI by sliding the mouse horizontally while \"\n#~      \"holding the DPI button.\"\n#~ msgstr       \"Pas het aantal dpi aan door de dpi-knop ingedrukt te houden \"\n#~      \"en de muis horizontaal te verplaatsen.\"\n\n#~ msgid        \"Automatically switch the mouse wheel between ratchet and \"\n#~      \"freespin mode.\\n\"\n#~      \"The mouse wheel is always free at 0, and always ratcheted at 50\"\n#~ msgstr       \"Schakel het scrollwiel automatisch over van regel-voor-\"\n#~      \"regelmodus naar vrij scrollen.\\n\"\n#~      \"Bij een waarde van 0 is vrij scrollen altijd ingeschakeld; bij een \"\n#~      \"waarde van 50 nooit.\"\n\n#~ msgid        \"Battery information unknown.\"\n#~ msgstr       \"Geen batterij-informatie beschikbaar.\"\n\n#~ msgid        \"Click to allow changes.\"\n#~ msgstr       \"Klik om wijzigingen toe te staan.\"\n\n#~ msgid        \"Click to prevent changes.\"\n#~ msgstr       \"Klik om wijzigingen te voorkomen.\"\n\n#~ msgid        \"Count\"\n#~ msgstr       \"Teller\"\n\n#~ msgid        \"DPI Sliding Adjustment\"\n#~ msgstr       \"DPI aanpassen middels verplaatsen\"\n\n#~ msgid        \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr       \"Schakelt scrollen met het duimwiel op Linux uit.\"\n\n#~ msgid        \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr       \"Schakelt scrollen met het scrollwiel op Linux uit.\"\n\n#~ msgid        \"For more information see the Solaar installation directions\\n\"\n#~      \"at https://pwr-solaar.github.io/Solaar/installation\"\n#~ msgstr       \"Bekijk voor meer informatie de installatiehulp op https://\"\n#~      \"pwr-solaar.github.io/Solaar/installation\"\n\n#, python-format\n#~ msgid        \"Found a Logitech Receiver (%s), but did not have permission \"\n#~      \"to open it.\"\n#~ msgstr       \"Er is een Logitech-ontvanger aangetroffen ('%s'), maar \"\n#~      \"Solaar is niet gemachtigd om deze te tonen.\"\n\n#~ msgid        \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr       \"HID++-modus voor horizontaal scrollen met het duimwiel.\"\n\n#~ msgid        \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr       \"HID++-modus voor verticaal scrollen.\"\n\n#~ msgid        \"High Resolution Scrolling\"\n#~ msgstr       \"Scrollen met hoge resolutie\"\n\n#~ msgid        \"High Resolution Wheel Invert\"\n#~ msgstr       \"Andersom scrollen met hoge resolutie\"\n\n#~ msgid        \"High-sensitivity wheel invert mode for vertical scroll.\"\n#~ msgstr       \"Hogegevoeligheidsmodus voor andersom verticaal scrollen.\"\n\n#~ msgid        \"If the device is already turned on,\\n\"\n#~      \"turn if off and on again.\"\n#~ msgstr       \"Als het apparaat reeds is ingeschakeld,\\n\"\n#~      \"schakel het dan uit en weer in.\"\n\n#~ msgid        \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr       \"Als het apparaat al is ingeschakeld, schakel het dan uit en \"\n#~      \"weer in.\"\n\n#~ msgid        \"If you've just installed Solaar, try removing the receiver \"\n#~      \"and plugging it back in.\"\n#~ msgstr       \"Als u Solaar nét heeft geïnstalleerd, plug dan de ontvanger \"\n#~      \"opnieuw in.\"\n\n#~ msgid        \"Make the key or button send HID++ notifications (which \"\n#~      \"trigger Solaar rules but are otherwise ignored).\"\n#~ msgstr       \"Laat de toets of knop een HID++-melding versturen (welke \"\n#~      \"Solaar's regels volgen, maar verder genegeerd worden).\"\n\n#~ msgid        \"No Logitech receiver found\"\n#~ msgstr       \"Geen Logitech-ontvanger aangetroffen\"\n\n#~ msgid        \"Quit\"\n#~ msgstr       \"Afsluiten\"\n\n#~ msgid        \"Scroll Wheel HID++ Scrolling\"\n#~ msgstr       \"HID++-scrollen\"\n\n#~ msgid        \"Scroll Wheel Rachet\"\n#~ msgstr       \"Vrij scrollen\"\n\n#~ msgid        \"Shows status of devices connected\\n\"\n#~      \"through wireless Logitech receivers.\"\n#~ msgstr       \"Toont de status van apparaten die verbonden\\n\"\n#~      \"zijn middels draadloze Logitech-ontvangers.\"\n\n#~ msgid        \"Solaar depends on a udev file that is not present\"\n#~ msgstr       \"Solaar is afhankelijk van een udev-bestand dat niet aanwezig \"\n#~      \"is\"\n\n#, python-format\n#~ msgid        \"The receiver only supports %d paired device(s).\"\n#~ msgstr       \"Dit apparaat ondersteunt slechts %d gekoppeld apparaat/\"\n#~      \"apparaten.\"\n\n#~ msgid        \"The receiver was unplugged.\"\n#~ msgstr       \"De ontvanger is niet meer aanwezig.\"\n\n#~ msgid        \"The wireless link between this device and its receiver is \"\n#~      \"not encrypted.\\n\"\n#~      \"\\n\"\n#~      \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~      \"security issue.\\n\"\n#~      \"\\n\"\n#~      \"It is, however, a major security issue for text-input devices \"\n#~      \"(keyboards, numpads),\\n\"\n#~      \"because typed text can be sniffed inconspicuously by 3rd parties \"\n#~      \"within range.\"\n#~ msgstr       \"De draadloze verbinding tussen dit apparaat en de ontvanger \"\n#~      \"is onversleuteld.\\n\"\n#~      \"\\n\"\n#~      \"Bij aanwijsapparaten (zoals muizen, trackballs en trackpads) vormt \"\n#~      \"dit een heel klein veiligheidsrisico.\\n\"\n#~      \"\\n\"\n#~      \"Echter, bij tekstinvoerapparaten (zoals (numerieke) toetsenborden) \"\n#~      \"vormt dit een groot probleem\\n\"\n#~      \"omdat ingevoerde tekst stiekem kan worden uitgelezen door derden \"\n#~      \"binnen handbereik.\"\n\n#~ msgid        \"Thumb Wheel HID++ Scrolling\"\n#~ msgstr       \"HID++-scrollen met duimwiel\"\n\n#~ msgid        \"Top-most coordinate.\"\n#~ msgstr       \"Het bovenste coördinaat.\"\n\n#~ msgid        \"height\"\n#~ msgstr       \"hoogte\"\n\n#~ msgid        \"top\"\n#~ msgstr       \"boven\"\n\n#~ msgid        \"unknown\"\n#~ msgstr       \"onbekend\"\n\n#~ msgid        \"width\"\n#~ msgstr       \"breedte\"\n"
  },
  {
    "path": "po/nn.po",
    "content": "# Norwegian Nynorsk translations for solaar package.\n# Copyright (C) 2020 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2020.\n# John Erling Blad <jeblad@gmail.com>, 2020-2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 1.0.3\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-10-31 01:42+0100\\n\"\n\"PO-Revision-Date: 2024-10-31 02:20+0100\\n\"\n\"Last-Translator: John Erling Blad <jeblad@gmail.com>\\n\"\n\"Language-Team:  <gnome-no@gnome.org>\\n\"\n\"Language: nb\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n!=1)\\n\"\n\"X-Generator: Gtranslator 47.0\\n\"\n\n#: lib/logitech_receiver/base_usb.py:48\nmsgid \"Bolt Receiver\"\nmsgstr \"Bolt mottakar\"\n\n#: lib/logitech_receiver/base_usb.py:60\nmsgid \"Unifying Receiver\"\nmsgstr \"Unifying mottakar\"\n\n#: lib/logitech_receiver/base_usb.py:71 lib/logitech_receiver/base_usb.py:83\n#: lib/logitech_receiver/base_usb.py:96 lib/logitech_receiver/base_usb.py:109\nmsgid \"Nano Receiver\"\nmsgstr \"Nano mottakar\"\n\n#: lib/logitech_receiver/base_usb.py:121\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Lightspeed mottakar\"\n\n#: lib/logitech_receiver/base_usb.py:131\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"EX100 27 Mhz mottakar\"\n\n#: lib/logitech_receiver/common.py:648\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"Batteri: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:651\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"Batteri: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:962\n#: lib/logitech_receiver/settings_templates.py:294\nmsgid \"Disabled\"\nmsgstr \"Avslått\"\n\n#: lib/logitech_receiver/hidpp20.py:963\nmsgid \"Static\"\nmsgstr \"Statisk\"\n\n#: lib/logitech_receiver/hidpp20.py:964\nmsgid \"Pulse\"\nmsgstr \"Puls\"\n\n#: lib/logitech_receiver/hidpp20.py:965\nmsgid \"Cycle\"\nmsgstr \"Syklus\"\n\n#: lib/logitech_receiver/hidpp20.py:966\nmsgid \"Boot\"\nmsgstr \"Boot\"\n\n#: lib/logitech_receiver/hidpp20.py:967\nmsgid \"Demo\"\nmsgstr \"Demo\"\n\n#: lib/logitech_receiver/hidpp20.py:969\nmsgid \"Breathe\"\nmsgstr \"Pust\"\n\n#: lib/logitech_receiver/hidpp20.py:972\nmsgid \"Ripple\"\nmsgstr \"Krusning\"\n\n#: lib/logitech_receiver/hidpp20.py:973\nmsgid \"Decomposition\"\nmsgstr \"Dekomponering\"\n\n#: lib/logitech_receiver/hidpp20.py:974\nmsgid \"Signature1\"\nmsgstr \"Signatur1\"\n\n#: lib/logitech_receiver/hidpp20.py:975\nmsgid \"Signature2\"\nmsgstr \"Signatur2\"\n\n#: lib/logitech_receiver/hidpp20.py:976\nmsgid \"CycleS\"\nmsgstr \"SyklusS\"\n\n#: lib/logitech_receiver/hidpp20.py:1040\nmsgid \"Unknown Location\"\nmsgstr \"Ukjend lokasjon\"\n\n#: lib/logitech_receiver/hidpp20.py:1041\nmsgid \"Primary\"\nmsgstr \"Primær\"\n\n#: lib/logitech_receiver/hidpp20.py:1042\nmsgid \"Logo\"\nmsgstr \"Logo\"\n\n#: lib/logitech_receiver/hidpp20.py:1043\nmsgid \"Left Side\"\nmsgstr \"Venstre side\"\n\n#: lib/logitech_receiver/hidpp20.py:1044\nmsgid \"Right Side\"\nmsgstr \"Høgre side\"\n\n#: lib/logitech_receiver/hidpp20.py:1045\nmsgid \"Combined\"\nmsgstr \"Kombinert\"\n\n#: lib/logitech_receiver/hidpp20.py:1046\nmsgid \"Primary 1\"\nmsgstr \"Primær 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1047\nmsgid \"Primary 2\"\nmsgstr \"Primær 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1048\nmsgid \"Primary 3\"\nmsgstr \"Primær 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1049\nmsgid \"Primary 4\"\nmsgstr \"Primær 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1050\nmsgid \"Primary 5\"\nmsgstr \"Primær 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1051\nmsgid \"Primary 6\"\nmsgstr \"Primær 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"tom\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"kritisk\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"låg\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"middels\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"god\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"full\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"utlading\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"opplading\"\n\n#: lib/logitech_receiver/i18n.py:37\nmsgid \"charging\"\nmsgstr \"lader\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"lader ikkje\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"nesten full\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"ladet\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"langsom lading\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"invalid battery\"\nmsgstr \"batterifeil\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"termisk feil\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"feil\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"standard\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"rask\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"langsom\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"eininga svarte ikkje\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"eininga er ikkje støtta\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"for mange einingar\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"sekvens timeout\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid \"Firmware\"\nmsgstr \"Fastvare\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"Oppstartslaster\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"Maskinvare\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"Anna\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"Venstreknapp\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"Høgreknapp\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"Midtknapp\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"Tlbakeknapp\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"Framoverknapp\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"Rørsleknapp\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"Smart skift\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"DPI-bryter\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"Venstre-tilt\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"Høgre-tilt\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"Venstre-klikk\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"Høgre-klikk\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"Midtknapp for mus\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"Tilbakeknapp for mus\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"Framoverknapp for mus\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"Navigering med rørsleknapp\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"Venstre rulleknapp for mus\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"Høgre rulleknapp for mus\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"nedtrykt\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"utløyst\"\n\n#: lib/logitech_receiver/notifications.py:86\n#: lib/logitech_receiver/notifications.py:138\nmsgid \"pairing lock is closed\"\nmsgstr \"parlåsen er lukka\"\n\n#: lib/logitech_receiver/notifications.py:86\n#: lib/logitech_receiver/notifications.py:138\nmsgid \"pairing lock is open\"\nmsgstr \"parlåsen er open\"\n\n#: lib/logitech_receiver/notifications.py:103\nmsgid \"discovery lock is closed\"\nmsgstr \"oppdagelseslåsen er lukka\"\n\n#: lib/logitech_receiver/notifications.py:103\nmsgid \"discovery lock is open\"\nmsgstr \"oppdagelseslåsen er open\"\n\n#: lib/logitech_receiver/notifications.py:232 lib/solaar/listener.py:247\nmsgid \"connected\"\nmsgstr \"tilkopla\"\n\n#: lib/logitech_receiver/notifications.py:232 lib/solaar/listener.py:247\nmsgid \"disconnected\"\nmsgstr \"fråkopla\"\n\n#: lib/logitech_receiver/notifications.py:258\nmsgid \"unpaired\"\nmsgstr \"upara\"\n\n#: lib/logitech_receiver/notifications.py:305\nmsgid \"powered on\"\nmsgstr \"påslått\"\n\n#: lib/logitech_receiver/receiver.py:383\nmsgid \"No paired devices.\"\nmsgstr \"Inga para eining.\"\n\n#: lib/logitech_receiver/receiver.py:385 lib/solaar/ui/window.py:590\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s para eining.\"\nmsgstr[1] \"%(count)s para einingar.\"\n\n#: lib/logitech_receiver/settings.py:614\nmsgid \"register\"\nmsgstr \"register\"\n\n#: lib/logitech_receiver/settings.py:628 lib/logitech_receiver/settings.py:663\nmsgid \"feature\"\nmsgstr \"karakteristikk\"\n\n#: lib/logitech_receiver/settings_templates.py:133\nmsgid \"Swap Fx function\"\nmsgstr \"Bytt Fx-funksjon\"\n\n#: lib/logitech_receiver/settings_templates.py:136\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"Viss aktivert, vil F1–F12-tastane aktivera sin spesialfunksjon,\\n\"\n\"og du må halda FN-tasten nede for å aktivera deira standardfunksjon.\"\n\n#: lib/logitech_receiver/settings_templates.py:141\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"Viss deaktivert, vil F1–F12-tastane aktivera sin standardfunksjon,\\n\"\n\"og du må holde FN-tasten nede for å aktivere deira spesialfunksjon.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid \"Hand Detection\"\nmsgstr \"Håndpåvisning\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"Slå på belysning når hendene er over tastaturet.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"Mjuk rulling med rullehjul\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:405\n#: lib/logitech_receiver/settings_templates.py:434\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"Høgsensitiv modus for vertikal rulling med hjulet.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid \"Side Scrolling\"\nmsgstr \"Siderulling\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"Viss deaktivert; blir trykt hjula sidevegs så sendast ein tilpassa \"\n\"knapphending\\n\"\n\"i staden for standard siderulling.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"Følsomhet (DPI – eldre mus)\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:977\n#: lib/logitech_receiver/settings_templates.py:1005\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"Sensibilitet for musrørsler\"\n\n#: lib/logitech_receiver/settings_templates.py:251\nmsgid \"Backlight Timed\"\nmsgstr \"Tidfesta bakgrunnslys\"\n\n#: lib/logitech_receiver/settings_templates.py:252\n#: lib/logitech_receiver/settings_templates.py:392\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"Still inn belysningstid for tastatur.\"\n\n#: lib/logitech_receiver/settings_templates.py:263\nmsgid \"Backlight\"\nmsgstr \"Bakbelysning\"\n\n#: lib/logitech_receiver/settings_templates.py:264\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"\"\n\"Lysnivå på tastaturet. Endringar som er gjorde, blir berre brukte i manuell \"\n\"modus.\"\n\n#: lib/logitech_receiver/settings_templates.py:296\nmsgid \"Automatic\"\nmsgstr \"Automatisk\"\n\n#: lib/logitech_receiver/settings_templates.py:298\nmsgid \"Manual\"\nmsgstr \"Manuell\"\n\n#: lib/logitech_receiver/settings_templates.py:300\nmsgid \"Enabled\"\nmsgstr \"Påslått\"\n\n#: lib/logitech_receiver/settings_templates.py:306\nmsgid \"Backlight Level\"\nmsgstr \"Bakgrunnslysnivå\"\n\n#: lib/logitech_receiver/settings_templates.py:307\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"Lysnivå på tastaturet i manuell modus.\"\n\n#: lib/logitech_receiver/settings_templates.py:364\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"Forseinking på bakgrunnsbelysning når hendene blir fjerna\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"\"\n\"Forseinking i sekund til bakgrunnsbelysninga tonar ut når hendene er borte \"\n\"frå tastaturet.\"\n\n#: lib/logitech_receiver/settings_templates.py:373\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"Forseinking på bakgrunnsbelysning når hendene er nære\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"\"\n\"Forseinking i sekund til bakgrunnsbelysninga tonar ut når hendene er nære \"\n\"tastaturet.\"\n\n#: lib/logitech_receiver/settings_templates.py:382\nmsgid \"Backlight Delay Powered\"\nmsgstr \"Forseinking på bakgrunnsbelysning når straumforsynt\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"\"\n\"Forseinking i sekund til bakgrunnsbelysninga tonar ut med ekstern \"\n\"straumforsyning.\"\n\n#: lib/logitech_receiver/settings_templates.py:391\nmsgid \"Backlight (Seconds)\"\nmsgstr \"Bakgrunnslys (sekund)\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"Høgopplausleg rullehjul\"\n\n#: lib/logitech_receiver/settings_templates.py:407\n#: lib/logitech_receiver/settings_templates.py:436\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"Sett til å ignorera viss rullinga er unormalt rask eller sakte\"\n\n#: lib/logitech_receiver/settings_templates.py:414\n#: lib/logitech_receiver/settings_templates.py:445\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"Omdirigering for rullehjul\"\n\n#: lib/logitech_receiver/settings_templates.py:416\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Få rullehjulet til å senda LOWRES_WHEEL HID++-varslar (som utløyser Solaar-\"\n\"reglar, men som elles blir ignorert).\"\n\n#: lib/logitech_receiver/settings_templates.py:423\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"Retning på rullehjul\"\n\n#: lib/logitech_receiver/settings_templates.py:424\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"Inverter retning for vertikal rulling med hjul.\"\n\n#: lib/logitech_receiver/settings_templates.py:432\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"Oppløysing på rullehjul\"\n\n#: lib/logitech_receiver/settings_templates.py:447\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Få rullehjulet til å senda HIRS_WHEEL HID++-varslar (som utløyser Solaar-\"\n\"reglar, men som elles blir ignorert).\"\n\n#: lib/logitech_receiver/settings_templates.py:456\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"Følsomhet (pekerfart)\"\n\n#: lib/logitech_receiver/settings_templates.py:457\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"Fartsmultiplikator for mus (256 er normal multiplikator).\"\n\n#: lib/logitech_receiver/settings_templates.py:467\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"Omdirigering for tommelhjul\"\n\n#: lib/logitech_receiver/settings_templates.py:469\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Få tommelhjulet til å senda THUMB_WHEEL HID++-varslar (som utløyser Solaar-\"\n\"reglar, men som elles blir ignorert).\"\n\n#: lib/logitech_receiver/settings_templates.py:478\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"Retning på tommelhjul\"\n\n#: lib/logitech_receiver/settings_templates.py:479\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"Inverter rulleretning for tommelhjul.\"\n\n#: lib/logitech_receiver/settings_templates.py:499\nmsgid \"Onboard Profiles\"\nmsgstr \"Innebygde profilar\"\n\n#: lib/logitech_receiver/settings_templates.py:500\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"\"\n\"Aktiver ein innebygd profil, som kontrollerer rapporthyppigheit, \"\n\"sensibilitet og knappehandlingar\"\n\n#: lib/logitech_receiver/settings_templates.py:544\n#: lib/logitech_receiver/settings_templates.py:577\nmsgid \"Report Rate\"\nmsgstr \"Rapporthyppigheit\"\n\n#: lib/logitech_receiver/settings_templates.py:546\n#: lib/logitech_receiver/settings_templates.py:579\nmsgid \"Frequency of device movement reports\"\nmsgstr \"Frekvensen til rapportar om einingsrørsler\"\n\n#: lib/logitech_receiver/settings_templates.py:546\n#: lib/logitech_receiver/settings_templates.py:579\n#: lib/logitech_receiver/settings_templates.py:1005\n#: lib/logitech_receiver/settings_templates.py:1379\n#: lib/logitech_receiver/settings_templates.py:1410\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"\"\n\"Kan trenga at innebygde profilar blir sette til avslått for å vera effektive.\"\n\n#: lib/logitech_receiver/settings_templates.py:607\nmsgid \"Divert crown events\"\nmsgstr \"Omdiriger krone-hendingar\"\n\n#: lib/logitech_receiver/settings_templates.py:608\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Få krona til å senda CROWN HID++-varslar (som utløyser Solaar-reglar, men \"\n\"som elles blir ignorert).\"\n\n#: lib/logitech_receiver/settings_templates.py:616\nmsgid \"Crown smooth scroll\"\nmsgstr \"Glatt krone-rulling\"\n\n#: lib/logitech_receiver/settings_templates.py:617\nmsgid \"Set crown smooth scroll\"\nmsgstr \"Still inn glatt krone-rulling\"\n\n#: lib/logitech_receiver/settings_templates.py:625\nmsgid \"Divert G and M Keys\"\nmsgstr \"Omdiriger G- og M-tastar\"\n\n#: lib/logitech_receiver/settings_templates.py:626\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Få G- og M-tastane til å senda HID++-varslar (som utløyser Solaar-reglar, \"\n\"men som elles blir ignorerte).\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"Rullehjul sperrehaka\"\n\n#: lib/logitech_receiver/settings_templates.py:641\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"\"\n\"Byt musehjulet mellom fartskontrollert sperrehake og alltid frittløpende.\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid \"Freespinning\"\nmsgstr \"Frittløpende\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid \"Ratcheted\"\nmsgstr \"Sperrehake\"\n\n#: lib/logitech_receiver/settings_templates.py:650\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"Rullehjul sperrehakefart\"\n\n#: lib/logitech_receiver/settings_templates.py:652\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"Bruk musehjulfarten til å byta mellom sperrehake og frittløpende.\\n\"\n\"Musehjulet er alltid sett til 50.\"\n\n#: lib/logitech_receiver/settings_templates.py:701\nmsgid \"Key/Button Actions\"\nmsgstr \"Taste-/knappehandling\"\n\n#: lib/logitech_receiver/settings_templates.py:703\nmsgid \"Change the action for the key or button.\"\nmsgstr \"Endre handlinga for ein tast eller knapp.\"\n\n#: lib/logitech_receiver/settings_templates.py:705\nmsgid \"Overridden by diversion.\"\nmsgstr \"Overstyrt av omdirigering.\"\n\n#: lib/logitech_receiver/settings_templates.py:707\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"\"\n\"Endring av viktige handlingar (til dømes venstre musknapp) kan resultera i \"\n\"eit ubrukande system.\"\n\n#: lib/logitech_receiver/settings_templates.py:882\nmsgid \"Key/Button Diversion\"\nmsgstr \"Taste-/knappeomdirigering\"\n\n#: lib/logitech_receiver/settings_templates.py:883\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse \"\n\"Gestures or Sliding DPI\"\nmsgstr \"\"\n\"Få nøkkelen eller knappen til å senda HID++-varslar (omdirigert) eller \"\n\"initier muserørsler eller glidande Dpi\"\n\n#: lib/logitech_receiver/settings_templates.py:886\n#: lib/logitech_receiver/settings_templates.py:887\n#: lib/logitech_receiver/settings_templates.py:888\nmsgid \"Diverted\"\nmsgstr \"Omdirigert\"\n\n#: lib/logitech_receiver/settings_templates.py:886\n#: lib/logitech_receiver/settings_templates.py:887\nmsgid \"Mouse Gestures\"\nmsgstr \"Muserørsler\"\n\n#: lib/logitech_receiver/settings_templates.py:886\n#: lib/logitech_receiver/settings_templates.py:887\n#: lib/logitech_receiver/settings_templates.py:888\nmsgid \"Regular\"\nmsgstr \"Vanleg\"\n\n#: lib/logitech_receiver/settings_templates.py:886\nmsgid \"Sliding DPI\"\nmsgstr \"Glidande DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:976\n#: lib/logitech_receiver/settings_templates.py:1004\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"Følsomheit (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:1081\nmsgid \"Sensitivity Switching\"\nmsgstr \"Følsomheitsbyte\"\n\n#: lib/logitech_receiver/settings_templates.py:1083\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key \"\n\"or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\"Byt gjeldande følsomheit og tidlegare følsomheit når tasten eller knappen \"\n\"blir trykt.\\n\"\n\"Viss det ikkje er nokon tidlegare følsomheit, sett berre gjeldande følsomheit\"\n\n#: lib/logitech_receiver/settings_templates.py:1087\nmsgid \"Off\"\nmsgstr \"Av\"\n\n#: lib/logitech_receiver/settings_templates.py:1118\nmsgid \"Disable keys\"\nmsgstr \"Slå av tastar\"\n\n#: lib/logitech_receiver/settings_templates.py:1119\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"Slå av spesifikke tastaturtastar.\"\n\n#: lib/logitech_receiver/settings_templates.py:1122\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"Slår av %s-tasten.\"\n\n#: lib/logitech_receiver/settings_templates.py:1135\n#: lib/logitech_receiver/settings_templates.py:1192\nmsgid \"Set OS\"\nmsgstr \"Sett OS\"\n\n#: lib/logitech_receiver/settings_templates.py:1136\n#: lib/logitech_receiver/settings_templates.py:1193\nmsgid \"Change keys to match OS.\"\nmsgstr \"Endre tastar så dei stemmer med OS-et.\"\n\n#: lib/logitech_receiver/settings_templates.py:1205\nmsgid \"Change Host\"\nmsgstr \"Endre tjener\"\n\n#: lib/logitech_receiver/settings_templates.py:1206\nmsgid \"Switch connection to a different host\"\nmsgstr \"Endre koplinga til ein annan tenar\"\n\n#: lib/logitech_receiver/settings_templates.py:1230\nmsgid \"Performs a left click.\"\nmsgstr \"Utfører eit venstreklikk.\"\n\n#: lib/logitech_receiver/settings_templates.py:1230\nmsgid \"Single tap\"\nmsgstr \"Enkeltklikk\"\n\n#: lib/logitech_receiver/settings_templates.py:1231\nmsgid \"Performs a right click.\"\nmsgstr \"Utfører eit høgreklikk.\"\n\n#: lib/logitech_receiver/settings_templates.py:1231\nmsgid \"Single tap with two fingers\"\nmsgstr \"Enkelt trykk med to fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1232\nmsgid \"Single tap with three fingers\"\nmsgstr \"Enkelt trykk med tre fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1236\nmsgid \"Double tap\"\nmsgstr \"Dobbeltklikk\"\n\n#: lib/logitech_receiver/settings_templates.py:1236\nmsgid \"Performs a double click.\"\nmsgstr \"Utfører eit dobbeltklikk\"\n\n#: lib/logitech_receiver/settings_templates.py:1237\nmsgid \"Double tap with two fingers\"\nmsgstr \"Dobbeltklikk med to fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1238\nmsgid \"Double tap with three fingers\"\nmsgstr \"Dobbeltklikk med to fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1241\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"Dra element med fingeren etter dobbeltklikk.\"\n\n#: lib/logitech_receiver/settings_templates.py:1241\nmsgid \"Tap and drag\"\nmsgstr \"Klikk og dra\"\n\n#: lib/logitech_receiver/settings_templates.py:1243\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"Klikk og dra med to fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1244\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"Dra element med fingrane etter dobbeltklikk.\"\n\n#: lib/logitech_receiver/settings_templates.py:1246\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"Klikk og dra med tre fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1249\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"Undertrykk klikk- og kantrørsler\"\n\n#: lib/logitech_receiver/settings_templates.py:1250\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"Slår av klikk- og kantrørsler (svarer til å trykkja Fn+Venstreklikk).\"\n\n#: lib/logitech_receiver/settings_templates.py:1252\nmsgid \"Scroll with one finger\"\nmsgstr \"Rull med ein finger\"\n\n#: lib/logitech_receiver/settings_templates.py:1252\n#: lib/logitech_receiver/settings_templates.py:1253\n#: lib/logitech_receiver/settings_templates.py:1256\nmsgid \"Scrolls.\"\nmsgstr \"Rullar\"\n\n#: lib/logitech_receiver/settings_templates.py:1253\n#: lib/logitech_receiver/settings_templates.py:1256\nmsgid \"Scroll with two fingers\"\nmsgstr \"Rull med to fingre\"\n\n#: lib/logitech_receiver/settings_templates.py:1254\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"Rull horisontalt med to fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1254\nmsgid \"Scrolls horizontally.\"\nmsgstr \"Rull horisontalt.\"\n\n#: lib/logitech_receiver/settings_templates.py:1255\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"Rull vertikalt med to fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1255\nmsgid \"Scrolls vertically.\"\nmsgstr \"Rull vertikalt.\"\n\n#: lib/logitech_receiver/settings_templates.py:1257\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"Inverterer rulleretninga.\"\n\n#: lib/logitech_receiver/settings_templates.py:1257\nmsgid \"Natural scrolling\"\nmsgstr \"Naturleg rulling\"\n\n#: lib/logitech_receiver/settings_templates.py:1258\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"Aktiverer tommelhjulet.\"\n\n#: lib/logitech_receiver/settings_templates.py:1258\nmsgid \"Thumbwheel\"\nmsgstr \"Tommelhjul\"\n\n#: lib/logitech_receiver/settings_templates.py:1269\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Swipe from the top edge\"\nmsgstr \"Sveip frå øvre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1270\nmsgid \"Swipe from the left edge\"\nmsgstr \"Sveip frå venstre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1271\nmsgid \"Swipe from the right edge\"\nmsgstr \"Sveip frå høgre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"Sveip frå nedre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1274\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"Sveip to fingrar frå venstre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1275\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"Sveip to fingrar frå høgre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1276\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"Sveip to fingrar frå nedre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1277\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"Sveip to fingrar frå øvre kant\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\n#: lib/logitech_receiver/settings_templates.py:1282\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"Knip for å zooma ut; sprei for å zooma inn.\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Zoom with two fingers.\"\nmsgstr \"Zoom med to fingrar.\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid \"Pinch to zoom out.\"\nmsgstr \"Knip for å zooma ut.\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Spread to zoom in.\"\nmsgstr \"Sprei for å zooma inn.\"\n\n#: lib/logitech_receiver/settings_templates.py:1281\nmsgid \"Zoom with three fingers.\"\nmsgstr \"Zoom med tre fingrar.\"\n\n#: lib/logitech_receiver/settings_templates.py:1282\nmsgid \"Zoom with two fingers\"\nmsgstr \"Zoom med to fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Pixel zone\"\nmsgstr \"Pikselsone\"\n\n#: lib/logitech_receiver/settings_templates.py:1301\nmsgid \"Ratio zone\"\nmsgstr \"Forholdssone\"\n\n#: lib/logitech_receiver/settings_templates.py:1302\nmsgid \"Scale factor\"\nmsgstr \"Skalafaktor\"\n\n#: lib/logitech_receiver/settings_templates.py:1302\nmsgid \"Sets the cursor speed.\"\nmsgstr \"Still inn markørfarten.\"\n\n#: lib/logitech_receiver/settings_templates.py:1306\nmsgid \"Left\"\nmsgstr \"Venstre\"\n\n#: lib/logitech_receiver/settings_templates.py:1306\nmsgid \"Left-most coordinate.\"\nmsgstr \"Koordinat lengst til venstre.\"\n\n#: lib/logitech_receiver/settings_templates.py:1307\nmsgid \"Bottom\"\nmsgstr \"Nederst\"\n\n#: lib/logitech_receiver/settings_templates.py:1307\nmsgid \"Bottom coordinate.\"\nmsgstr \"Nederste koordinat.\"\n\n#: lib/logitech_receiver/settings_templates.py:1308\nmsgid \"Width\"\nmsgstr \"Breidde\"\n\n#: lib/logitech_receiver/settings_templates.py:1308\nmsgid \"Width.\"\nmsgstr \"Breidde.\"\n\n#: lib/logitech_receiver/settings_templates.py:1309\nmsgid \"Height\"\nmsgstr \"Høgde\"\n\n#: lib/logitech_receiver/settings_templates.py:1309\nmsgid \"Height.\"\nmsgstr \"Høgde.\"\n\n#: lib/logitech_receiver/settings_templates.py:1310\nmsgid \"Cursor speed.\"\nmsgstr \"Markørhastigheit.\"\n\n#: lib/logitech_receiver/settings_templates.py:1310\nmsgid \"Scale\"\nmsgstr \"Skala\"\n\n#: lib/logitech_receiver/settings_templates.py:1316\nmsgid \"Gestures\"\nmsgstr \"Rørsler\"\n\n#: lib/logitech_receiver/settings_templates.py:1317\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"Juster musas/berøringsplata åtferd.\"\n\n#: lib/logitech_receiver/settings_templates.py:1333\nmsgid \"Gestures Diversion\"\nmsgstr \"Omdirigering av rørsler\"\n\n#: lib/logitech_receiver/settings_templates.py:1334\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"Omdiriger musas/berøringsflatas rørsler.\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Gesture params\"\nmsgstr \"Parametrar for rørsler\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"Endre numeriske parametrar for ei mus/berøringsplate.\"\n\n#: lib/logitech_receiver/settings_templates.py:1375\nmsgid \"M-Key LEDs\"\nmsgstr \"M-tast LED-ene\"\n\n#: lib/logitech_receiver/settings_templates.py:1377\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"Kontroller M-tast LED-ene.\"\n\n#: lib/logitech_receiver/settings_templates.py:1381\n#: lib/logitech_receiver/settings_templates.py:1412\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"Kan trenga omdirigering av G-tastar for å vera effektivt.\"\n\n#: lib/logitech_receiver/settings_templates.py:1387\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"Lyser opp %s-tasten.\"\n\n#: lib/logitech_receiver/settings_templates.py:1406\nmsgid \"MR-Key LED\"\nmsgstr \"MR-tast LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1408\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"Kontroller MR-tast LED.\"\n\n#: lib/logitech_receiver/settings_templates.py:1429\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"Vedvarande tast-/knapptilordning\"\n\n#: lib/logitech_receiver/settings_templates.py:1431\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"Endre tilordninga for tasten eller knappen permanent.\"\n\n#: lib/logitech_receiver/settings_templates.py:1433\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"\"\n\"Endring av viktige tastar eller knappar (som venstre museknapp) kan \"\n\"resultera i eit ubrukeleg system.\"\n\n#: lib/logitech_receiver/settings_templates.py:1490\nmsgid \"Sidetone\"\nmsgstr \"Sidetone\"\n\n#: lib/logitech_receiver/settings_templates.py:1491\nmsgid \"Set sidetone level.\"\nmsgstr \"Still inn sidetone nivå.\"\n\n#: lib/logitech_receiver/settings_templates.py:1500\nmsgid \"Equalizer\"\nmsgstr \"Equalizer\"\n\n#: lib/logitech_receiver/settings_templates.py:1501\nmsgid \"Set equalizer levels.\"\nmsgstr \"Still inn equalizer nivå.\"\n\n#: lib/logitech_receiver/settings_templates.py:1523\nmsgid \"Hz\"\nmsgstr \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1529\nmsgid \"Power Management\"\nmsgstr \"Strømstyring\"\n\n#: lib/logitech_receiver/settings_templates.py:1530\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"Slå av i minutt (0 for aldri).\"\n\n#: lib/logitech_receiver/settings_templates.py:1541\nmsgid \"Brightness Control\"\nmsgstr \"Lysstyrkekontroll\"\n\n#: lib/logitech_receiver/settings_templates.py:1542\nmsgid \"Control overall brightness\"\nmsgstr \"Kontroller den generelle lysstyrken\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\n#: lib/logitech_receiver/settings_templates.py:1639\nmsgid \"LED Control\"\nmsgstr \"LED-kontroll\"\n\n#: lib/logitech_receiver/settings_templates.py:1586\n#: lib/logitech_receiver/settings_templates.py:1640\nmsgid \"Switch control of LED zones between device and Solaar\"\nmsgstr \"Byt kontroll av LED-soner mellom eining og Solaar\"\n\n#: lib/logitech_receiver/settings_templates.py:1601\n#: lib/logitech_receiver/settings_templates.py:1650\nmsgid \"LED Zone Effects\"\nmsgstr \"LED-soneeffektar\"\n\n#: lib/logitech_receiver/settings_templates.py:1602\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr \"LED-kontroll må setjast til Solaar for å vera effektiv.\"\n\n#: lib/logitech_receiver/settings_templates.py:1602\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid \"Set effect for LED Zone\"\nmsgstr \"Still inn effekt for LED-sone\"\n\n#: lib/logitech_receiver/settings_templates.py:1605\nmsgid \"Speed\"\nmsgstr \"Fart\"\n\n#: lib/logitech_receiver/settings_templates.py:1606\nmsgid \"Period\"\nmsgstr \"Periode\"\n\n#: lib/logitech_receiver/settings_templates.py:1607\nmsgid \"Intensity\"\nmsgstr \"Intensitet\"\n\n#: lib/logitech_receiver/settings_templates.py:1608\nmsgid \"Ramp\"\nmsgstr \"Stigning\"\n\n#: lib/logitech_receiver/settings_templates.py:1624\nmsgid \"LEDs\"\nmsgstr \"LEDs\"\n\n#: lib/logitech_receiver/settings_templates.py:1661\nmsgid \"Per-key Lighting\"\nmsgstr \"Lys for kvar tast\"\n\n#: lib/logitech_receiver/settings_templates.py:1662\nmsgid \"Control per-key lighting.\"\nmsgstr \"Kontrollar lys for kvar tast.\"\n\n#: lib/solaar/ui/__init__.py:117\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"Ein annan Solaar-prosess køyrer allereie, så berre vis vindauget\"\n\n#: lib/solaar/ui/about/model.py:36\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"Administrerer Logitech-mottakarar,\\n\"\n\"tastatur, mus og nettbrett.\"\n\n#: lib/solaar/ui/about/model.py:62\nmsgid \"Additional Programming\"\nmsgstr \"Ekstra programmering\"\n\n#: lib/solaar/ui/about/model.py:63\nmsgid \"GUI design\"\nmsgstr \"GUI utsjånad\"\n\n#: lib/solaar/ui/about/model.py:65\nmsgid \"Testing\"\nmsgstr \"Testing\"\n\n#: lib/solaar/ui/about/model.py:73\nmsgid \"Logitech documentation\"\nmsgstr \"Logitech dokumentasjon\"\n\n#: lib/solaar/ui/action.py:83 lib/solaar/ui/action.py:87\n#: lib/solaar/ui/window.py:188\nmsgid \"Unpair\"\nmsgstr \"Fjern paring\"\n\n#: lib/solaar/ui/action.py:86 lib/solaar/ui/diversion_rules.py:107\nmsgid \"Cancel\"\nmsgstr \"Avbryt\"\n\n#: lib/solaar/ui/common.py:35\nmsgid \"Permissions error\"\nmsgstr \"Rettighetsfeil\"\n\n#: lib/solaar/ui/common.py:37\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"\"\n\"Fann ein Logitech-mottakar eller eining (%s), men hadde ikkje løyve til å \"\n\"opna han.\"\n\n#: lib/solaar/ui/common.py:39\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"\"\n\"Viss du nettopp har installert Solaar, kan du prøva å kopla frå mottakaren \"\n\"eller eininga og deretter kopla ho til igjen.\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Cannot connect to device error\"\nmsgstr \"Kan ikkje kopla til eining-feil\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"Fann ein Logitech-mottakar eller -eining på %s, men oppdaga ein feil når han \"\n\"vart tilkopla.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"\"\n\"Prøv å kopla frå eininga og deretter kopla ho til igjen eller slå ho av og \"\n\"på igjen.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Unpairing failed\"\nmsgstr \"Kunne ikkje bryta paringa\"\n\n#: lib/solaar/ui/common.py:51\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"Mislykkast med å bryta paret %{device} og %{receiver}.\"\n\n#: lib/solaar/ui/common.py:56\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"Mottakaren rapporterte ein feil, utan fleire detaljar.\"\n\n#: lib/solaar/ui/config_panel.py:228\nmsgid \"Complete - ENTER to change\"\nmsgstr \"Fullfør - ENTER for å endra\"\n\n#: lib/solaar/ui/config_panel.py:228\nmsgid \"Incomplete\"\nmsgstr \"Ufullstendig\"\n\n#: lib/solaar/ui/config_panel.py:475 lib/solaar/ui/config_panel.py:527\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d verdi\"\nmsgstr[1] \"%d verdiar\"\n\n#: lib/solaar/ui/config_panel.py:609\nmsgid \"Changes allowed\"\nmsgstr \"Endringar tillatne\"\n\n#: lib/solaar/ui/config_panel.py:610\nmsgid \"No changes allowed\"\nmsgstr \"Ingen endringar tillatne\"\n\n#: lib/solaar/ui/config_panel.py:611\nmsgid \"Ignore this setting\"\nmsgstr \"Ignorer denne innstillinga\"\n\n#: lib/solaar/ui/config_panel.py:655\nmsgid \"Working\"\nmsgstr \"Suksess\"\n\n#: lib/solaar/ui/config_panel.py:658\nmsgid \"Read/write operation failed.\"\nmsgstr \"Lese-/skriveoperasjonen mislykkast.\"\n\n#: lib/solaar/ui/desktop_notifications.py:114\nmsgid \"unspecified reason\"\nmsgstr \"uspesifisert årsak\"\n\n#: lib/solaar/ui/diversion_rules.py:69\nmsgid \"Built-in rules\"\nmsgstr \"Faste reglar\"\n\n#: lib/solaar/ui/diversion_rules.py:69\nmsgid \"User-defined rules\"\nmsgstr \"Brukardefinerte reglar\"\n\n#: lib/solaar/ui/diversion_rules.py:71 lib/solaar/ui/diversion_rules.py:1089\nmsgid \"Rule\"\nmsgstr \"Regel\"\n\n#: lib/solaar/ui/diversion_rules.py:72 lib/solaar/ui/diversion_rules.py:348\n#: lib/solaar/ui/diversion_rules.py:475\nmsgid \"Sub-rule\"\nmsgstr \"Underregel\"\n\n#: lib/solaar/ui/diversion_rules.py:74\nmsgid \"[empty]\"\nmsgstr \"[tom]\"\n\n#: lib/solaar/ui/diversion_rules.py:98\nmsgid \"Make changes permanent?\"\nmsgstr \"Gjera endringar permanente?\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"Yes\"\nmsgstr \"Ja\"\n\n#: lib/solaar/ui/diversion_rules.py:105\nmsgid \"No\"\nmsgstr \"Nei\"\n\n#: lib/solaar/ui/diversion_rules.py:110\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"Viss du vel Nei, vil endringar gå tapt når Solaar blir lukka.\"\n\n#: lib/solaar/ui/diversion_rules.py:239\nmsgid \"Paste here\"\nmsgstr \"Lim inn her\"\n\n#: lib/solaar/ui/diversion_rules.py:241\nmsgid \"Paste above\"\nmsgstr \"Lim inn ovanfor\"\n\n#: lib/solaar/ui/diversion_rules.py:243\nmsgid \"Paste below\"\nmsgstr \"Lim inn nedanfor\"\n\n#: lib/solaar/ui/diversion_rules.py:249\nmsgid \"Paste rule here\"\nmsgstr \"Lim inn regel her\"\n\n#: lib/solaar/ui/diversion_rules.py:251\nmsgid \"Paste rule above\"\nmsgstr \"Lim inn regel ovanfor\"\n\n#: lib/solaar/ui/diversion_rules.py:253\nmsgid \"Paste rule below\"\nmsgstr \"Lim inn regel nedanfor\"\n\n#: lib/solaar/ui/diversion_rules.py:257\nmsgid \"Paste rule\"\nmsgstr \"Lim inn regel\"\n\n#: lib/solaar/ui/diversion_rules.py:272\nmsgid \"Insert here\"\nmsgstr \"Set inn her\"\n\n#: lib/solaar/ui/diversion_rules.py:274\nmsgid \"Insert above\"\nmsgstr \"Set inn ovanfor\"\n\n#: lib/solaar/ui/diversion_rules.py:276\nmsgid \"Insert below\"\nmsgstr \"Set inn nedanfor\"\n\n#: lib/solaar/ui/diversion_rules.py:282\nmsgid \"Insert new rule here\"\nmsgstr \"Set inn ny regel her\"\n\n#: lib/solaar/ui/diversion_rules.py:284\nmsgid \"Insert new rule above\"\nmsgstr \"Set inn ny regel ovanfor\"\n\n#: lib/solaar/ui/diversion_rules.py:286\nmsgid \"Insert new rule below\"\nmsgstr \"Set inn ny regel nedanfor\"\n\n#: lib/solaar/ui/diversion_rules.py:313\nmsgid \"Flatten\"\nmsgstr \"Utfalte\"\n\n#: lib/solaar/ui/diversion_rules.py:346\nmsgid \"Insert\"\nmsgstr \"Set inn\"\n\n#: lib/solaar/ui/diversion_rules.py:349 lib/solaar/ui/diversion_rules.py:477\n#: lib/solaar/ui/diversion_rules.py:1121\nmsgid \"Or\"\nmsgstr \"Eller\"\n\n#: lib/solaar/ui/diversion_rules.py:350 lib/solaar/ui/diversion_rules.py:476\n#: lib/solaar/ui/diversion_rules.py:1107\nmsgid \"And\"\nmsgstr \"Og\"\n\n#: lib/solaar/ui/diversion_rules.py:352\nmsgid \"Condition\"\nmsgstr \"Vilkår\"\n\n#: lib/solaar/ui/diversion_rules.py:354 lib/solaar/ui/rule_conditions.py:145\nmsgid \"Feature\"\nmsgstr \"Karakteristikk\"\n\n#: lib/solaar/ui/diversion_rules.py:355 lib/solaar/ui/rule_conditions.py:179\nmsgid \"Report\"\nmsgstr \"Rapport\"\n\n#: lib/solaar/ui/diversion_rules.py:356 lib/solaar/ui/rule_conditions.py:60\nmsgid \"Process\"\nmsgstr \"Prosess\"\n\n#: lib/solaar/ui/diversion_rules.py:357\nmsgid \"Mouse process\"\nmsgstr \"Musprosess\"\n\n#: lib/solaar/ui/diversion_rules.py:358 lib/solaar/ui/rule_conditions.py:216\nmsgid \"Modifiers\"\nmsgstr \"Modifikatorer\"\n\n#: lib/solaar/ui/diversion_rules.py:359 lib/solaar/ui/rule_conditions.py:268\nmsgid \"Key\"\nmsgstr \"Tast\"\n\n#: lib/solaar/ui/diversion_rules.py:360 lib/solaar/ui/rule_conditions.py:309\nmsgid \"KeyIsDown\"\nmsgstr \"TastErNede\"\n\n#: lib/solaar/ui/diversion_rules.py:361 lib/solaar/ui/diversion_rules.py:1414\nmsgid \"Active\"\nmsgstr \"Aktiv\"\n\n#: lib/solaar/ui/diversion_rules.py:362 lib/solaar/ui/diversion_rules.py:1372\n#: lib/solaar/ui/diversion_rules.py:1423 lib/solaar/ui/diversion_rules.py:1470\nmsgid \"Device\"\nmsgstr \"Eining\"\n\n#: lib/solaar/ui/diversion_rules.py:363 lib/solaar/ui/diversion_rules.py:1449\nmsgid \"Host\"\nmsgstr \"Vert\"\n\n#: lib/solaar/ui/diversion_rules.py:364 lib/solaar/ui/diversion_rules.py:1489\nmsgid \"Setting\"\nmsgstr \"Innstilling\"\n\n#: lib/solaar/ui/diversion_rules.py:365 lib/solaar/ui/rule_conditions.py:324\n#: lib/solaar/ui/rule_conditions.py:373\nmsgid \"Test\"\nmsgstr \"Test\"\n\n#: lib/solaar/ui/diversion_rules.py:366 lib/solaar/ui/rule_conditions.py:498\nmsgid \"Test bytes\"\nmsgstr \"Test bytes\"\n\n#: lib/solaar/ui/diversion_rules.py:367 lib/solaar/ui/rule_conditions.py:599\nmsgid \"Mouse Gesture\"\nmsgstr \"Muserørsle\"\n\n#: lib/solaar/ui/diversion_rules.py:371\nmsgid \"Action\"\nmsgstr \"Handling\"\n\n#: lib/solaar/ui/diversion_rules.py:373 lib/solaar/ui/rule_actions.py:131\nmsgid \"Key press\"\nmsgstr \"Tastetrykk\"\n\n#: lib/solaar/ui/diversion_rules.py:374 lib/solaar/ui/rule_actions.py:182\nmsgid \"Mouse scroll\"\nmsgstr \"Muserulling\"\n\n#: lib/solaar/ui/diversion_rules.py:375 lib/solaar/ui/rule_actions.py:243\nmsgid \"Mouse click\"\nmsgstr \"Museklikk\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid \"Set\"\nmsgstr \"Still inn\"\n\n#: lib/solaar/ui/diversion_rules.py:377 lib/solaar/ui/rule_actions.py:313\nmsgid \"Execute\"\nmsgstr \"Utfør\"\n\n#: lib/solaar/ui/diversion_rules.py:378 lib/solaar/ui/diversion_rules.py:1152\nmsgid \"Later\"\nmsgstr \"Seinare\"\n\n#: lib/solaar/ui/diversion_rules.py:407\nmsgid \"Insert new rule\"\nmsgstr \"Set inn ny regel\"\n\n#: lib/solaar/ui/diversion_rules.py:427 lib/solaar/ui/rule_actions.py:74\n#: lib/solaar/ui/rule_actions.py:272 lib/solaar/ui/rule_conditions.py:546\nmsgid \"Delete\"\nmsgstr \"Slett\"\n\n#: lib/solaar/ui/diversion_rules.py:449\nmsgid \"Negate\"\nmsgstr \"Omvendt\"\n\n#: lib/solaar/ui/diversion_rules.py:473\nmsgid \"Wrap with\"\nmsgstr \"Pakk inn med\"\n\n#: lib/solaar/ui/diversion_rules.py:503\nmsgid \"Cut\"\nmsgstr \"KLipp ut\"\n\n#: lib/solaar/ui/diversion_rules.py:519\nmsgid \"Paste\"\nmsgstr \"Lim inn\"\n\n#: lib/solaar/ui/diversion_rules.py:525\nmsgid \"Copy\"\nmsgstr \"Kopier\"\n\n#: lib/solaar/ui/diversion_rules.py:534\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Solaar regel editor\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid \"Save changes\"\nmsgstr \"Lagre endringar\"\n\n#: lib/solaar/ui/diversion_rules.py:639\nmsgid \"Discard changes\"\nmsgstr \"Forkast endringar\"\n\n#: lib/solaar/ui/diversion_rules.py:1070\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"Denne editoren støttar førebels ikkje den valde regelkomponenten.\"\n\n#: lib/solaar/ui/diversion_rules.py:1132\nmsgid \"\"\n\"Number of seconds to delay.  Delay between 0 and 1 is done with higher \"\n\"precision.\"\nmsgstr \"\"\n\"Talet på sekund med forseinking. Forseinking mellom 0 og 1 blir gjort med \"\n\"høgare presisjon.\"\n\n#: lib/solaar/ui/diversion_rules.py:1170\nmsgid \"Not\"\nmsgstr \"Ikkje\"\n\n#: lib/solaar/ui/diversion_rules.py:1201\nmsgid \"Toggle\"\nmsgstr \"Veksle\"\n\n#: lib/solaar/ui/diversion_rules.py:1202\nmsgid \"True\"\nmsgstr \"Sann\"\n\n#: lib/solaar/ui/diversion_rules.py:1203\nmsgid \"False\"\nmsgstr \"Falsk\"\n\n#: lib/solaar/ui/diversion_rules.py:1216\nmsgid \"Unsupported setting\"\nmsgstr \"Innstillinga blir ikkje støtta\"\n\n#: lib/solaar/ui/diversion_rules.py:1378 lib/solaar/ui/diversion_rules.py:1397\n#: lib/solaar/ui/diversion_rules.py:1476 lib/solaar/ui/diversion_rules.py:1731\n#: lib/solaar/ui/diversion_rules.py:1749\nmsgid \"Originating device\"\nmsgstr \"Kildeeining\"\n\n#: lib/solaar/ui/diversion_rules.py:1410\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"Eininga er aktiv og innstillingane kan endrast.\"\n\n#: lib/solaar/ui/diversion_rules.py:1419\nmsgid \"Device that originated the current notification.\"\nmsgstr \"Eininga som gav det gjeldande varselet.\"\n\n#: lib/solaar/ui/diversion_rules.py:1432\nmsgid \"Name of host computer.\"\nmsgstr \"Namn på vertsmaskin.\"\n\n#: lib/solaar/ui/diversion_rules.py:1503\nmsgid \"Value\"\nmsgstr \"Verdi\"\n\n#: lib/solaar/ui/diversion_rules.py:1512\nmsgid \"Item\"\nmsgstr \"Punkt\"\n\n#: lib/solaar/ui/diversion_rules.py:1791\nmsgid \"Change setting on device\"\nmsgstr \"Endre innstilling på eining\"\n\n#: lib/solaar/ui/diversion_rules.py:1807\nmsgid \"Setting on device\"\nmsgstr \"Innstilling på eining\"\n\n#: lib/solaar/ui/pair_window.py:37 lib/solaar/ui/pair_window.py:165\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: par ny eining\"\n\n#: lib/solaar/ui/pair_window.py:39\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Bolt-mottakarar er berre kompatible med Bolt-einingar.\"\n\n#: lib/solaar/ui/pair_window.py:41\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"\"\n\"Trykk på samankoplingsknappen eller -tasten til samankoplingslampa blinkar \"\n\"raskt.\"\n\n#: lib/solaar/ui/pair_window.py:44\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"Unifying-mottakarar er berre kompatible med Unifying-einingar.\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"Andre mottakarar er berre kompatible med nokre få einingar.\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid \"For most devices, turn on the device you want to pair.\"\nmsgstr \"For dei fleste einingar slår du på eininga du vil para.\"\n\n#: lib/solaar/ui/pair_window.py:49\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"Viss eininga allereie er pålått, slå ho av og på igjen.\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"Eininga må ikkje parast med ein pålått mottakar i nærleiken.\"\n\n#: lib/solaar/ui/pair_window.py:54\nmsgid \"\"\n\"For devices with multiple channels, press, hold, and release the button for \"\n\"the channel you wish to pair\\n\"\n\"or use the channel switch button to select a channel and then press, hold, \"\n\"and release the channel switch button.\"\nmsgstr \"\"\n\"For einingar med fleire kanalar, trykk, hald og slipp knappen for kanalen du \"\n\"ønskjer å para\\n\"\n\"eller bruk kanalbrytarknappen for å velja ein kanal og trykk, hald og slepp \"\n\"kanalbrytarknappen.\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid \"The channel indicator light should be blinking rapidly.\"\nmsgstr \"Kanalindikatorlampa skal blinka raskt.\"\n\n#: lib/solaar/ui/pair_window.py:65\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"Denne mottakaren har %d gjenståande paring.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"Denne mottakaren har %d gjenståande paringar.\"\n\n#: lib/solaar/ui/pair_window.py:71\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"Kansellering no vil ikkje bruka opp ein paring.\"\n\n#: lib/solaar/ui/pair_window.py:166\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"Skriv inn passordet på %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:169\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"Skriv inn %(passcode)s og trykk deretter på enter-tasten.\"\n\n#: lib/solaar/ui/pair_window.py:174\nmsgid \"left\"\nmsgstr \"venstre\"\n\n#: lib/solaar/ui/pair_window.py:174\nmsgid \"right\"\nmsgstr \"høgre\"\n\n#: lib/solaar/ui/pair_window.py:176\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"Trykk %(code)s\\n\"\n\"og trykk deretter på venstre og høgre knapp samtidig.\"\n\n#: lib/solaar/ui/pair_window.py:219\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"Den trådlause koplinga er ukryptert\"\n\n#: lib/solaar/ui/pair_window.py:224\nmsgid \"Found a new device:\"\nmsgstr \"Fant ny eining:\"\n\n#: lib/solaar/ui/pair_window.py:245\nmsgid \"Pairing failed\"\nmsgstr \"Paringa feila\"\n\n#: lib/solaar/ui/pair_window.py:247\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"\"\n\"Forsikre deg om at eininga er innan rekkevidde, og at den er tilstrekkeleg \"\n\"opplada.\"\n\n#: lib/solaar/ui/pair_window.py:249\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"\"\n\"Ei ny eining vart påvist, men ho er ikkje kompatibel med denne mottakaren.\"\n\n#: lib/solaar/ui/pair_window.py:251\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"Fleir para einingar enn mottakaren kan støtte.\"\n\n#: lib/solaar/ui/pair_window.py:253\nmsgid \"No further details are available about the error.\"\nmsgstr \"Ingen ytterligare detaljar er tilgjengeleg om feilen.\"\n\n#: lib/solaar/ui/rule_actions.py:48\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simuler ein chorded (?) tast, klikk eller trykk ned eller slipp.\\n\"\n\"På Wayland krev dette skrivetilgang til /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:53\nmsgid \"Add key\"\nmsgstr \"Legg til tast\"\n\n#: lib/solaar/ui/rule_actions.py:56\nmsgid \"Click\"\nmsgstr \"Klikk\"\n\n#: lib/solaar/ui/rule_actions.py:59\nmsgid \"Depress\"\nmsgstr \"Nedtrykk\"\n\n#: lib/solaar/ui/rule_actions.py:62\nmsgid \"Release\"\nmsgstr \"Utløs\"\n\n#: lib/solaar/ui/rule_actions.py:146\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simuler ei muserulling.\\n\"\n\"På Wayland krev dette skrivetilgang til /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:202\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simuler eit museklikk.\\n\"\n\"På Wayland krev dette skrivetilgang til /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:205\nmsgid \"Button\"\nmsgstr \"Knapp\"\n\n#: lib/solaar/ui/rule_actions.py:206\nmsgid \"Count and Action\"\nmsgstr \"Antall og handling\"\n\n#: lib/solaar/ui/rule_actions.py:255\nmsgid \"Execute a command with arguments.\"\nmsgstr \"Utfør ein kommando med argument.\"\n\n#: lib/solaar/ui/rule_actions.py:258\nmsgid \"Add argument\"\nmsgstr \"Legg til argument\"\n\n#: lib/solaar/ui/rule_conditions.py:43\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"X11 aktiv prosess. Berre til bruk i X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:73\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"X11-museprosess. Berre til bruk i X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:90\nmsgid \"MouseProcess\"\nmsgstr \"MusProsess\"\n\n#: lib/solaar/ui/rule_conditions.py:114\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"Funksjonsnamn på varsel som utløyste regelbehandling.\"\n\n#: lib/solaar/ui/rule_conditions.py:160\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"Rapportnummer for varsling som utløyser regelbehandling.\"\n\n#: lib/solaar/ui/rule_conditions.py:192\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"Aktive tastaturmodifikatorer. Ikkje alltid tilgjengeleg i Wayland.\"\n\n#: lib/solaar/ui/rule_conditions.py:232\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Omdirigert tast eller knapp som er trykt eller sleppt.\\n\"\n\"Bruk innstillingane for omdirigering av tast/knapp og omdiriger G-tastar for \"\n\"å vidaresenda tastar og knappar.\"\n\n#: lib/solaar/ui/rule_conditions.py:241\nmsgid \"Key down\"\nmsgstr \"Tast ned\"\n\n#: lib/solaar/ui/rule_conditions.py:244\nmsgid \"Key up\"\nmsgstr \"Tast opp\"\n\n#: lib/solaar/ui/rule_conditions.py:284\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Omdirigert tast eller knapp er nede.\\n\"\n\"Bruk innstillingane for omdirigering av tast/knapp og omdirigerte G-tastar \"\n\"for å vidaresenda tastar og knappar.\"\n\n#: lib/solaar/ui/rule_conditions.py:322\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"Testvilkår på varsel som utløyser regelbehandling.\"\n\n#: lib/solaar/ui/rule_conditions.py:326\nmsgid \"Parameter\"\nmsgstr \"Parameter\"\n\n#: lib/solaar/ui/rule_conditions.py:399\nmsgid \"begin (inclusive)\"\nmsgstr \"byrj (inklusiv)\"\n\n#: lib/solaar/ui/rule_conditions.py:400\nmsgid \"end (exclusive)\"\nmsgstr \"slutt (eksklusiv)\"\n\n#: lib/solaar/ui/rule_conditions.py:408\nmsgid \"range\"\nmsgstr \"område\"\n\n#: lib/solaar/ui/rule_conditions.py:411\nmsgid \"minimum\"\nmsgstr \"minimum\"\n\n#: lib/solaar/ui/rule_conditions.py:412\nmsgid \"maximum\"\nmsgstr \"maksimum\"\n\n#: lib/solaar/ui/rule_conditions.py:414\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"byte %(0)d til %(1)d, fra %(2)d til %(3)d\"\n\n#: lib/solaar/ui/rule_conditions.py:417 lib/solaar/ui/rule_conditions.py:418\nmsgid \"mask\"\nmsgstr \"maske\"\n\n#: lib/solaar/ui/rule_conditions.py:419\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"byte %(0)d til %(1)d, maske %(2)d\"\n\n#: lib/solaar/ui/rule_conditions.py:428\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\"Bit- eller områdetest på bytes i varselmelding som utløyste regelbehandling.\"\n\n#: lib/solaar/ui/rule_conditions.py:438\nmsgid \"type\"\nmsgstr \"type\"\n\n#: lib/solaar/ui/rule_conditions.py:526\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"\"\n\"Muserørsle med valfri startknapp etterfølgd av null eller fleire muserørsler.\"\n\n#: lib/solaar/ui/rule_conditions.py:531\nmsgid \"Add movement\"\nmsgstr \"Legg til rørsle\"\n\n#: lib/solaar/ui/tray.py:49\nmsgid \"No supported device found\"\nmsgstr \"Ingen støtta einingar er funne\"\n\n#: lib/solaar/ui/tray.py:54 lib/solaar/ui/window.py:308\n#, python-format\nmsgid \"About %s\"\nmsgstr \"Om %s\"\n\n#: lib/solaar/ui/tray.py:55 lib/solaar/ui/window.py:306\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"Avslutt %s\"\n\n#: lib/solaar/ui/tray.py:270 lib/solaar/ui/tray.py:278\nmsgid \"no receiver\"\nmsgstr \"ingen mottakar\"\n\n#: lib/solaar/ui/tray.py:291 lib/solaar/ui/tray.py:296\nmsgid \"offline\"\nmsgstr \"avslått\"\n\n#: lib/solaar/ui/tray.py:294\nmsgid \"no status\"\nmsgstr \"ingen status\"\n\n#: lib/solaar/ui/window.py:90\nmsgid \"Scanning\"\nmsgstr \"Søker\"\n\n#: lib/solaar/ui/window.py:121\nmsgid \"Battery\"\nmsgstr \"Batteri\"\n\n#: lib/solaar/ui/window.py:124\nmsgid \"Wireless Link\"\nmsgstr \"Trådlaus kopling\"\n\n#: lib/solaar/ui/window.py:128\nmsgid \"Lighting\"\nmsgstr \"Belysning\"\n\n#: lib/solaar/ui/window.py:162\nmsgid \"Show Technical Details\"\nmsgstr \"Vis tekniske detaljar\"\n\n#: lib/solaar/ui/window.py:178\nmsgid \"Pair new device\"\nmsgstr \"Par ny eining\"\n\n#: lib/solaar/ui/window.py:196\nmsgid \"Select a device\"\nmsgstr \"Vel ei eining\"\n\n#: lib/solaar/ui/window.py:311\nmsgid \"Rule Editor\"\nmsgstr \"Regel editor\"\n\n#: lib/solaar/ui/window.py:504\nmsgid \"Path\"\nmsgstr \"Sti\"\n\n#: lib/solaar/ui/window.py:506\nmsgid \"USB ID\"\nmsgstr \"USB-ID\"\n\n#: lib/solaar/ui/window.py:509 lib/solaar/ui/window.py:511\n#: lib/solaar/ui/window.py:526 lib/solaar/ui/window.py:528\nmsgid \"Serial\"\nmsgstr \"Seriell\"\n\n#: lib/solaar/ui/window.py:515\nmsgid \"Index\"\nmsgstr \"Indeks\"\n\n#: lib/solaar/ui/window.py:517\nmsgid \"Wireless PID\"\nmsgstr \"Trådlaus-PID\"\n\n#: lib/solaar/ui/window.py:519\nmsgid \"Product ID\"\nmsgstr \"Produkt-ID\"\n\n#: lib/solaar/ui/window.py:521\nmsgid \"Protocol\"\nmsgstr \"Protokoll\"\n\n#: lib/solaar/ui/window.py:521\nmsgid \"Unknown\"\nmsgstr \"Ukjend\"\n\n#: lib/solaar/ui/window.py:523\nmsgid \"Polling rate\"\nmsgstr \"Spørjarate\"\n\n#: lib/solaar/ui/window.py:530\nmsgid \"Unit ID\"\nmsgstr \"Einings-ID\"\n\n#: lib/solaar/ui/window.py:544\nmsgid \"Notifications\"\nmsgstr \"Varslar\"\n\n#: lib/solaar/ui/window.py:588\nmsgid \"No device paired.\"\nmsgstr \"Inga eining para.\"\n\n#: lib/solaar/ui/window.py:597\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"Inntil %(max_count)s eining kan bli para med denne mottakaren.\"\nmsgstr[1] \"Inntil %(max_count)s einingar kan bli para med denne mottakaren.\"\n\n#: lib/solaar/ui/window.py:608\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"Denne mottakaren har %d gjenståande paring.\"\nmsgstr[1] \"Denne mottakaren har %d gjenståande paringer.\"\n\n#: lib/solaar/ui/window.py:665\nmsgid \"Battery Voltage\"\nmsgstr \"Batterispenning\"\n\n#: lib/solaar/ui/window.py:667\nmsgid \"Voltage reported by battery\"\nmsgstr \"Spenning rapportert av batteri\"\n\n#: lib/solaar/ui/window.py:669\nmsgid \"Battery Level\"\nmsgstr \"Batterinivå\"\n\n#: lib/solaar/ui/window.py:671\nmsgid \"Approximate level reported by battery\"\nmsgstr \"Omtrentleg nivå rapportert frå batteri\"\n\n#: lib/solaar/ui/window.py:678 lib/solaar/ui/window.py:680\nmsgid \"next reported \"\nmsgstr \"neste rapportert \"\n\n#: lib/solaar/ui/window.py:681\nmsgid \" and next level to be reported.\"\nmsgstr \" og neste nivå som blir rapportert.\"\n\n#: lib/solaar/ui/window.py:697\nmsgid \"encrypted\"\nmsgstr \"kryptert\"\n\n#: lib/solaar/ui/window.py:699\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"Den trådlause tilkoplinga mellom eininga og mottakaren er kryptert.\"\n\n#: lib/solaar/ui/window.py:701\nmsgid \"not encrypted\"\nmsgstr \"ikkje kryptert\"\n\n#: lib/solaar/ui/window.py:705\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"Den trådlause koplinga mellom denne eininga og mottakaren er ikkje \"\n\"kryptert.\\n\"\n\"Dette er eit tryggingsproblem for peikeeiningar, og eit stort \"\n\"tryggingsproblem for einingar for tekstinndata.\"\n\n#: lib/solaar/ui/window.py:721\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d lux\"\n\n#~ msgid \"\"\n#~ \"\\n\"\n#~ \"\\n\"\n#~ \"This receiver has %d pairing(s) remaining.\"\n#~ msgstr \"\"\n#~ \"\\n\"\n#~ \"\\n\"\n#~ \"Denne mottakaren har %d gjenståande paringar.\"\n\n#, python-format\n#~ msgid \"%(rate)d ms (%(rate_hz)dHz)\"\n#~ msgstr \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#~ msgid \"Actions\"\n#~ msgstr \"Handlingar\"\n\n#~ msgid \"\"\n#~ \"Automatically switch the mouse wheel between ratchet and freespin mode.\\n\"\n#~ \"The mouse wheel is always free at 0, and always locked at 50\"\n#~ msgstr \"\"\n#~ \"Byt mushjulet automatisk mellom sperre- og frispinnmodus.\\n\"\n#~ \"Mushjulet er alltid fritt på 0, og blir alltid låste på 50\"\n\n#, python-format\n#~ msgid \"Battery: %(level)s\"\n#~ msgstr \"Batteri: %(level)s\"\n\n#, python-format\n#~ msgid \"Battery: %(percent)d%%\"\n#~ msgstr \"Batteri: %(percent)d%%\"\n\n#~ msgid \"Divert G Keys\"\n#~ msgstr \"Omdiriger G tastar\"\n\n#~ msgid \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr \"Slår i praksis av tommelrulling i Linux.\"\n\n#~ msgid \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr \"Slår i praksis av hjulrulling i Linux.\"\n\n#~ msgid \"\"\n#~ \"Enable onboard profiles, which often control report rate and keyboard \"\n#~ \"lighting\"\n#~ msgstr \"\"\n#~ \"Aktiver ein innebygd profil, som kontrollerer rapporthyppigheit, \"\n#~ \"følsomheit, og knappehandlingar\"\n\n#~ msgid \"\"\n#~ \"For more information see the Solaar installation directions\\n\"\n#~ \"at https://pwr-solaar.github.io/Solaar/installation\"\n#~ msgstr \"\"\n#~ \"For meir informasjon, sjå Solaar-installasjonsanvisningene\\n\"\n#~ \"på https://pwr-solaar.github.io/Solaar/installation\"\n\n#, python-format\n#~ msgid \"\"\n#~ \"Found a Logitech Receiver (%s), but did not have permission to open it.\"\n#~ msgstr \"Fant ein Logitech-mottakar (%s), men manglar rettar til å opna den.\"\n\n#~ msgid \"Frequency of device polling, in milliseconds\"\n#~ msgstr \"Frekvensen til rapportar om einingsrørsler\"\n\n#~ msgid \"HID++ Scrolling\"\n#~ msgstr \"HID++ rulling\"\n\n#~ msgid \"HID++ Thumb Scrolling\"\n#~ msgstr \"HID++ tommelrulling\"\n\n#~ msgid \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr \"HID++ modus for horisontal rulling med tommelhjulet.\"\n\n#~ msgid \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr \"HID++ modus for vertikal rulling med hjulet.\"\n\n#~ msgid \"High Resolution Scrolling\"\n#~ msgstr \"Høgoppløyseleg rulling\"\n\n#~ msgid \"High Resolution Wheel Invert\"\n#~ msgstr \"Inverter høg rulleoppløysning\"\n\n#~ msgid \"High-sensitivity wheel invert direction for vertical scroll.\"\n#~ msgstr \"Inverter retning for høg vertikal rulleoppløysning.\"\n\n#~ msgid \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr \"Viss eininga allereie er slått på, slå ho av og på igjen.\"\n\n#~ msgid \"\"\n#~ \"If you've just installed Solaar, try removing the receiver and plugging \"\n#~ \"it back in.\"\n#~ msgstr \"\"\n#~ \"Viss du nettopp har installert Solaar, forsøk å fjerna mottakaren og \"\n#~ \"plugg den inn igjen.\"\n\n#~ msgid \"Invert thumb scroll direction.\"\n#~ msgstr \"Inverter retning på tommelrulling.\"\n\n#, python-format\n#~ msgid \"Lighting: %(level)s lux\"\n#~ msgstr \"Belysning: %(level)s lux\"\n\n#~ msgid \"\"\n#~ \"Make G keys send GKEY HID++ notifications (which trigger Solaar rules but \"\n#~ \"are otherwise ignored).\"\n#~ msgstr \"\"\n#~ \"Få G-tastane til å senda HID++-varslar (som utløyser Solaar-reglar, men \"\n#~ \"som elles blir ignorerte).\"\n\n#~ msgid \"No Logitech receiver found\"\n#~ msgstr \"Ingen Logitech-mottakar funnet\"\n\n#~ msgid \"Number of seconds to delay.\"\n#~ msgstr \"Talet på sekund med forseinking.\"\n\n#~ msgid \"Only one device can be paired to this receiver.\"\n#~ msgstr \"Berre éi eining kan parast med denne mottakaren.\"\n\n#~ msgid \"Polling Rate (ms)\"\n#~ msgstr \"Rapporthyppigheit\"\n\n#~ msgid \"\"\n#~ \"Shows status of devices connected\\n\"\n#~ \"through wireless Logitech receivers.\"\n#~ msgstr \"\"\n#~ \"Viser status for einingar tilkopla\\n\"\n#~ \"via trådlause Logitech-mottakere.\"\n\n#~ msgid \"Smooth Scrolling\"\n#~ msgstr \"Mjuk rulling\"\n\n#~ msgid \"Solaar depends on a udev file that is not present\"\n#~ msgstr \"Solaar er avhengig av ein udev-fil som ikkje finnast\"\n\n#~ msgid \"The receiver only supports %d paired device(s).\"\n#~ msgstr \"Mottakaren kan kun støtte %d para eining(er).\"\n\n#~ msgid \"The receiver was unplugged.\"\n#~ msgstr \"Mottakaren vart fjerna.\"\n\n#~ msgid \"\"\n#~ \"The wireless link between this device and its receiver is not encrypted.\\n\"\n#~ \"\\n\"\n#~ \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~ \"security issue.\\n\"\n#~ \"\\n\"\n#~ \"It is, however, a major security issue for text-input devices (keyboards, \"\n#~ \"numpads),\\n\"\n#~ \"because typed text can be sniffed inconspicuously by 3rd parties within \"\n#~ \"range.\"\n#~ msgstr \"\"\n#~ \"Den trådlause koplinga mellom denne eininga og mottakaren er ukryptert.\\n\"\n#~ \"\\n\"\n#~ \"For peikeeeiningar (mus, styrekuler, styreflater) er dette eit mindre \"\n#~ \"tryggingsproblem.\\n\"\n#~ \"\\n\"\n#~ \"Det er likevel eit viktig tryggingsproblem for tekstinndataeiningar \"\n#~ \"(tastatur, numpads),\\n\"\n#~ \"fordi maskinskriven tekst kan bli sniffa umerka av tredjepartar innan \"\n#~ \"rekkevidde.\"\n\n#~ msgid \"This receiver has %d pairing(s) remaining.\"\n#~ msgstr \"Denne mottakaren har %d gjenståande paring(er).\"\n\n#~ msgid \"Thumb Scroll Invert\"\n#~ msgstr \"Inverter tommelrulling\"\n\n#~ msgid \"Turn illumination on or off on keyboard.\"\n#~ msgstr \"Slå belysning på eller av for tastaturet.\"\n\n#~ msgid \"Turn on the device you want to pair.\"\n#~ msgstr \"Slå på eininga du ynsker å pare.\"\n\n#~ msgid \"USB id\"\n#~ msgstr \"USB-id\"\n\n#~ msgid \"Unexpected device number (%s) in notification %s.\"\n#~ msgstr \"Uventa einingsnummer (%s) i varsel %s.\"\n\n#~ msgid \"Wheel Resolution\"\n#~ msgstr \"Hjuloppløysning\"\n\n#~ msgid \"height\"\n#~ msgstr \"høgde\"\n\n#~ msgid \"last known\"\n#~ msgstr \"sist kjend\"\n\n#~ msgid \"next \"\n#~ msgstr \"neste \"\n\n#~ msgid \"none\"\n#~ msgstr \"ingen\"\n\n#~ msgid \"unknown\"\n#~ msgstr \"ukjend\"\n\n#~ msgid \"width\"\n#~ msgstr \"breidde\"\n"
  },
  {
    "path": "po/pl.po",
    "content": "# Polish translations for solaar package.\n# Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2013.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 1.1.17\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-01 19:29+0100\\n\"\n\"PO-Revision-Date: 2025-12-01 19:46+0100\\n\"\n\"Last-Translator: Matthaiks\\n\"\n\"Language-Team: none\\n\"\n\"Language: pl\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 \"\n\"|| n%100>=20) ? 1 : 2);\\n\"\n\"X-Generator: Poedit 3.8\\n\"\n\n#: lib/logitech_receiver/base_usb.py:52\nmsgid \"Bolt Receiver\"\nmsgstr \"Odbiornik Bolt\"\n\n#: lib/logitech_receiver/base_usb.py:64\nmsgid \"Unifying Receiver\"\nmsgstr \"Odbiornik Unifying\"\n\n#: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87\n#: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113\nmsgid \"Nano Receiver\"\nmsgstr \"Odbiornik Nano\"\n\n#: lib/logitech_receiver/base_usb.py:125\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Odbiornik Lightspeed\"\n\n#: lib/logitech_receiver/base_usb.py:135\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"Odbiornik EX100 27 MHz\"\n\n#: lib/logitech_receiver/common.py:649\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"Akumulator: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:652\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"Akumulator: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:1048\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid \"Disabled\"\nmsgstr \"Wyłączone\"\n\n#: lib/logitech_receiver/hidpp20.py:1049\nmsgid \"Static\"\nmsgstr \"Statyczny\"\n\n#: lib/logitech_receiver/hidpp20.py:1050\nmsgid \"Pulse\"\nmsgstr \"Puls\"\n\n#: lib/logitech_receiver/hidpp20.py:1051\nmsgid \"Cycle\"\nmsgstr \"Cykl\"\n\n#: lib/logitech_receiver/hidpp20.py:1052\nmsgid \"Boot\"\nmsgstr \"Rozruch\"\n\n#: lib/logitech_receiver/hidpp20.py:1053\nmsgid \"Demo\"\nmsgstr \"Demo\"\n\n#: lib/logitech_receiver/hidpp20.py:1055\nmsgid \"Breathe\"\nmsgstr \"Oddech\"\n\n#: lib/logitech_receiver/hidpp20.py:1058\nmsgid \"Ripple\"\nmsgstr \"Plusk\"\n\n#: lib/logitech_receiver/hidpp20.py:1059\nmsgid \"Decomposition\"\nmsgstr \"Dekompozycja\"\n\n#: lib/logitech_receiver/hidpp20.py:1060\nmsgid \"Signature1\"\nmsgstr \"Podpis1\"\n\n#: lib/logitech_receiver/hidpp20.py:1061\nmsgid \"Signature2\"\nmsgstr \"Podpis2\"\n\n#: lib/logitech_receiver/hidpp20.py:1062\nmsgid \"CycleS\"\nmsgstr \"Cykle\"\n\n#: lib/logitech_receiver/hidpp20.py:1126\nmsgid \"Unknown Location\"\nmsgstr \"Nieznana lokalizacja\"\n\n#: lib/logitech_receiver/hidpp20.py:1127\nmsgid \"Primary\"\nmsgstr \"Podstawowy\"\n\n#: lib/logitech_receiver/hidpp20.py:1128\nmsgid \"Logo\"\nmsgstr \"Logo\"\n\n#: lib/logitech_receiver/hidpp20.py:1129\nmsgid \"Left Side\"\nmsgstr \"Lewa strona\"\n\n#: lib/logitech_receiver/hidpp20.py:1130\nmsgid \"Right Side\"\nmsgstr \"Prawa strona\"\n\n#: lib/logitech_receiver/hidpp20.py:1131\nmsgid \"Combined\"\nmsgstr \"Łączony\"\n\n#: lib/logitech_receiver/hidpp20.py:1132\nmsgid \"Primary 1\"\nmsgstr \"Podstawowy 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1133\nmsgid \"Primary 2\"\nmsgstr \"Podstawowy 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1134\nmsgid \"Primary 3\"\nmsgstr \"Podstawowy 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1135\nmsgid \"Primary 4\"\nmsgstr \"Podstawowy 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1136\nmsgid \"Primary 5\"\nmsgstr \"Podstawowy 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1137\nmsgid \"Primary 6\"\nmsgstr \"Podstawowy 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"pusty\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"krytyczny\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"niski\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"przeciętny\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"dobry\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"pełny\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"rozładowywanie\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"ładowanie\"\n\n#: lib/logitech_receiver/i18n.py:37\nmsgid \"charging\"\nmsgstr \"ładowanie\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"brak ładowania\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"prawie pełny\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"naładowany\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"powolne ładowanie\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"invalid battery\"\nmsgstr \"nieodpowiedni akumulator\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"błąd termiczny\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"błąd\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"standardowe\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"szybkie\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"powolne\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"upłynął limit czasu urządzenia\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"urządzenie nie jest obsługiwane\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"za dużo urządzeń\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"upłynął limit czasu sekwencji\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid \"Firmware\"\nmsgstr \"Firmware\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"Bootloader\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"Sprzęt\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"Inne\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"Przycisk lewy\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"Przycisk prawy\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"Przycisk środkowy\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"Przycisk wstecz\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"Przycisk dalej\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"Przycisk gestów myszy\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"SmartShift\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"Przełącznik DPI\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"Pochylenie w lewo\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"Pochylenie w prawo\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"Kliknięcie LPM\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"Kliknięcie PPM\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"Przycisk środkowy myszy\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"Przycisk wstecz myszy\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"Przycisk dalej myszy\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"Nawigacja przyciskiem gestów\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"Lewy przycisk kółka myszy\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"Prawy przycisk kółka myszy\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"wciśnięty\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"zwolniony\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"connected\"\nmsgstr \"podłączone\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"disconnected\"\nmsgstr \"rozłączone\"\n\n#: lib/logitech_receiver/notifications.py:182\nmsgid \"unpaired\"\nmsgstr \"niesparowane\"\n\n#: lib/logitech_receiver/notifications.py:231\nmsgid \"powered on\"\nmsgstr \"włączone\"\n\n#: lib/logitech_receiver/notifications.py:283\nmsgid \"ADC measurement notification\"\nmsgstr \"powiadomienie o pomiarze ADC\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:483\nmsgid \"pairing lock is closed\"\nmsgstr \"blokada sparowania jest zamknięta\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:483\nmsgid \"pairing lock is open\"\nmsgstr \"blokada sparowania jest otwarta\"\n\n#: lib/logitech_receiver/notifications.py:446\nmsgid \"discovery lock is closed\"\nmsgstr \"blokada wykrywania jest zamknięta\"\n\n#: lib/logitech_receiver/notifications.py:446\nmsgid \"discovery lock is open\"\nmsgstr \"blokada wykrywania jest otwarta\"\n\n#: lib/logitech_receiver/receiver.py:437\nmsgid \"No paired devices.\"\nmsgstr \"Brak sparowanych urządzeń.\"\n\n#: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s sparowane urządzenie.\"\nmsgstr[1] \"%(count)s sparowane urządzenia.\"\nmsgstr[2] \"%(count)s sparowanych urządzeń.\"\n\n#: lib/logitech_receiver/settings.py:602\nmsgid \"register\"\nmsgstr \"rejestr\"\n\n#: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654\nmsgid \"feature\"\nmsgstr \"funkcja\"\n\n#: lib/logitech_receiver/settings_templates.py:138\nmsgid \"Swap Fx function\"\nmsgstr \"Zamień funkcję Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:141\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"Gdy włączona, po wciśnięciu klawiszy F1..F12 aktywowana zostanie\\n\"\n\"ich funkcja pomocnicza. Aby aktywować funkcję standardową, należy\\n\"\n\"przytrzymać klawisz FN.\"\n\n#: lib/logitech_receiver/settings_templates.py:146\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"Gdy wyłączona, po wciśnięciu klawiszy F1..F12 aktywowana zostanie\\n\"\n\"ich funkcja standardowa. Aby aktywować funkcję pomocniczą, należy\\n\"\n\"przytrzymać klawisz FN.\"\n\n#: lib/logitech_receiver/settings_templates.py:154\nmsgid \"Hand Detection\"\nmsgstr \"Wykrywanie dłoni\"\n\n#: lib/logitech_receiver/settings_templates.py:155\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"Włącz podświetlenie, gdy dłonie znajdą się nad klawiaturą.\"\n\n#: lib/logitech_receiver/settings_templates.py:162\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"Płynne przewijanie kółkiem przewijania\"\n\n#: lib/logitech_receiver/settings_templates.py:163\n#: lib/logitech_receiver/settings_templates.py:410\n#: lib/logitech_receiver/settings_templates.py:439\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"\"\n\"Tryb wysokiej rozdzielczości do przewijania pionowego\\n\"\n\"przy użyciu kółka myszy.\"\n\n#: lib/logitech_receiver/settings_templates.py:170\nmsgid \"Side Scrolling\"\nmsgstr \"Przewijanie na boki\"\n\n#: lib/logitech_receiver/settings_templates.py:172\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"Gdy wyłączone, przesuwanie kółka na boki powoduje wysyłanie \"\n\"niestandardowych\\n\"\n\"zdarzeń przycisków zamiast standardowych zdarzeń przewijania na boki.\"\n\n#: lib/logitech_receiver/settings_templates.py:182\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"Czułość (DPI - starsze myszy)\"\n\n#: lib/logitech_receiver/settings_templates.py:183\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"Czułość ruchu myszy\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid \"Backlight Timed\"\nmsgstr \"Podświetlenie czasowe\"\n\n#: lib/logitech_receiver/settings_templates.py:257\n#: lib/logitech_receiver/settings_templates.py:397\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"Ustaw czas podświetlenia klawiatury.\"\n\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid \"Backlight\"\nmsgstr \"Podświetlenie\"\n\n#: lib/logitech_receiver/settings_templates.py:269\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"\"\n\"Poziom podświetlenia klawiatury. Wprowadzone zmiany zostaną zastosowane \"\n\"wyłącznie w trybie ręcznym.\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid \"Automatic\"\nmsgstr \"Automatyczne\"\n\n#: lib/logitech_receiver/settings_templates.py:303\nmsgid \"Manual\"\nmsgstr \"Ręczne\"\n\n#: lib/logitech_receiver/settings_templates.py:305\nmsgid \"Enabled\"\nmsgstr \"Włączone\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid \"Backlight Level\"\nmsgstr \"Poziom podświetlenia\"\n\n#: lib/logitech_receiver/settings_templates.py:312\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"Poziom podświetlenia klawiatury w trybie ręcznym.\"\n\n#: lib/logitech_receiver/settings_templates.py:369\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"Opóźnienie podświetlenia bez rąk\"\n\n#: lib/logitech_receiver/settings_templates.py:370\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"\"\n\"Opóźnienie w sekundach, aż podświetlenie zniknie, gdy ręce będą oddalone od \"\n\"klawiatury.\"\n\n#: lib/logitech_receiver/settings_templates.py:378\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"Opóźnienie podświetlenia z rękoma\"\n\n#: lib/logitech_receiver/settings_templates.py:379\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"\"\n\"Opóźnienie w sekundach, aż podświetlenie zniknie, gdy ręce będą blisko \"\n\"klawiatury.\"\n\n#: lib/logitech_receiver/settings_templates.py:387\nmsgid \"Backlight Delay Powered\"\nmsgstr \"Opóźnienie podświetlenia z zasilanem\"\n\n#: lib/logitech_receiver/settings_templates.py:388\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"\"\n\"Opóźnienie w sekundach, aż podświetlenie zaniknie przy zasilaniu zewnętrznym.\"\n\n#: lib/logitech_receiver/settings_templates.py:396\nmsgid \"Backlight (Seconds)\"\nmsgstr \"Podświetlenie (sekundy)\"\n\n#: lib/logitech_receiver/settings_templates.py:408\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"Wysoka rozdzielczość kółka przewijania\"\n\n#: lib/logitech_receiver/settings_templates.py:412\n#: lib/logitech_receiver/settings_templates.py:441\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"\"\n\"Ustaw, aby ignorować, jeśli przewijanie jest nienormalnie szybkie lub wolne\"\n\n#: lib/logitech_receiver/settings_templates.py:419\n#: lib/logitech_receiver/settings_templates.py:450\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"Przekierowanie kółka przewijania\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Spraw, aby kółko przewijania wysyłało powiadomienia LOWRES_WHEEL HID++ \"\n\"(które wyzwalają reguły Solaar, ale w przeciwnym razie są ignorowane).\"\n\n#: lib/logitech_receiver/settings_templates.py:428\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"Kierunek kółka przewijania\"\n\n#: lib/logitech_receiver/settings_templates.py:429\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"Odwróć kierunek przewijania w pionie za pomocą kółka.\"\n\n#: lib/logitech_receiver/settings_templates.py:437\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"Rozdzielczość kółka przewijania\"\n\n#: lib/logitech_receiver/settings_templates.py:452\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Spraw, aby kółko przewijania wysyłało powiadomienia HIRES_WHEEL HID++ (które \"\n\"wyzwalają reguły Solaar, ale w przeciwnym razie są ignorowane).\"\n\n#: lib/logitech_receiver/settings_templates.py:461\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"Czułość (prędkość wskaźnika)\"\n\n#: lib/logitech_receiver/settings_templates.py:462\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"Mnożnik prędkości myszy (256 to normalny mnożnik).\"\n\n#: lib/logitech_receiver/settings_templates.py:472\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"Przekierowanie kółka obsługiwanego kciukiem\"\n\n#: lib/logitech_receiver/settings_templates.py:474\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Spraw, aby kółko obsługiwane kciukiem wysyłało powiadomienia THUMB_WHEEL HID+\"\n\"+ (które wyzwalają reguły Solaar, ale w przeciwnym razie są ignorowane).\"\n\n#: lib/logitech_receiver/settings_templates.py:483\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"Kierunek kółka obsługiwanego kciukiem\"\n\n#: lib/logitech_receiver/settings_templates.py:484\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"Odwróć kierunek przewijania kółkiem obsługiwanym kciukiem.\"\n\n#: lib/logitech_receiver/settings_templates.py:504\nmsgid \"Onboard Profiles\"\nmsgstr \"Profile wbudowane\"\n\n#: lib/logitech_receiver/settings_templates.py:505\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"\"\n\"Włącz wbudowany profil, który kontroluje częstotliwość raportowania, czułość \"\n\"i czynności przycisków\"\n\n#: lib/logitech_receiver/settings_templates.py:549\n#: lib/logitech_receiver/settings_templates.py:582\nmsgid \"Report Rate\"\nmsgstr \"Szybkość raportów\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\nmsgid \"Frequency of device movement reports\"\nmsgstr \"Częstotliwość raportów o ruchu urządzenia\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1421\n#: lib/logitech_receiver/settings_templates.py:1452\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"Aby działało, może być konieczne wyłączenie profili wbudowanych.\"\n\n#: lib/logitech_receiver/settings_templates.py:612\nmsgid \"Divert crown events\"\nmsgstr \"Przekieruj zdarzenia korony\"\n\n#: lib/logitech_receiver/settings_templates.py:613\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Spraw, aby korona wysyłała powiadomienia CROWN HID++ (które wyzwalają reguły \"\n\"Solaar, ale w przeciwnym razie są ignorowane).\"\n\n#: lib/logitech_receiver/settings_templates.py:621\nmsgid \"Crown smooth scroll\"\nmsgstr \"Płynne przewijanie koroną\"\n\n#: lib/logitech_receiver/settings_templates.py:622\nmsgid \"Set crown smooth scroll\"\nmsgstr \"Ustaw płynne przewijanie koroną\"\n\n#: lib/logitech_receiver/settings_templates.py:630\nmsgid \"Divert G and M Keys\"\nmsgstr \"Przekieruj klawisze G i M\"\n\n#: lib/logitech_receiver/settings_templates.py:631\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Spraw, aby klawisze G i M wysyłały powiadomienia HID++ (które wyzwalają \"\n\"reguły Solaar, ale w przeciwnym razie są ignorowane).\"\n\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"Zapadkowe kółko przewijania\"\n\n#: lib/logitech_receiver/settings_templates.py:646\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"\"\n\"Przełącz kółko myszy między zapadką z kontrolowaną prędkością a zawsze \"\n\"swobodnym obrotem.\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Freespinning\"\nmsgstr \"Obrót swobodny\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Ratcheted\"\nmsgstr \"Obrót zapadkowy\"\n\n#: lib/logitech_receiver/settings_templates.py:655\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"Prędkość zapadki kółka przewijania\"\n\n#: lib/logitech_receiver/settings_templates.py:657\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"Użyj prędkości kółka myszy, aby przełączać się między obrotem zapadkowym a \"\n\"swobodnym.\\n\"\n\"Kółko myszy jest zawsze ustawione na 50.\"\n\n#: lib/logitech_receiver/settings_templates.py:707\nmsgid \"Scroll Wheel Ratchet Torque\"\nmsgstr \"Moment obrotowy zapadki kółka przewijania\"\n\n#: lib/logitech_receiver/settings_templates.py:708\nmsgid \"Change the torque needed to overcome the ratchet.\"\nmsgstr \"Zmień moment obrotowy potrzebny do przejścia zapadki.\"\n\n#: lib/logitech_receiver/settings_templates.py:743\nmsgid \"Key/Button Actions\"\nmsgstr \"Czynności klawiszy/przycisków\"\n\n#: lib/logitech_receiver/settings_templates.py:745\nmsgid \"Change the action for the key or button.\"\nmsgstr \"Zmień czynność klawisza lub przycisku.\"\n\n#: lib/logitech_receiver/settings_templates.py:747\nmsgid \"Overridden by diversion.\"\nmsgstr \"Omijane przez przekierowanie.\"\n\n#: lib/logitech_receiver/settings_templates.py:749\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"\"\n\"Zmiana ważnych czynności (np. lewego przycisku myszy) może spowodować, że \"\n\"system będzie nieużywalny.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid \"Key/Button Diversion\"\nmsgstr \"Przekierowanie klawiszy/przycisków\"\n\n#: lib/logitech_receiver/settings_templates.py:925\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse \"\n\"Gestures or Sliding DPI\"\nmsgstr \"\"\n\"Spraw, aby klawisz lub przycisk wysyłał powiadomienia HID++ (przekierowany) \"\n\"lub inicjował gesty myszy lub przesuwnie DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Diverted\"\nmsgstr \"Przekierowany\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\nmsgid \"Mouse Gestures\"\nmsgstr \"Gesty myszy\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Regular\"\nmsgstr \"Zwykły\"\n\n#: lib/logitech_receiver/settings_templates.py:928\nmsgid \"Sliding DPI\"\nmsgstr \"Przesuwnie DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"Czułość (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:1123\nmsgid \"Sensitivity Switching\"\nmsgstr \"Przełączanie czułości\"\n\n#: lib/logitech_receiver/settings_templates.py:1125\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key \"\n\"or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\"Przełącz bieżącą czułość i zapamiętaną czułość po naciśnięciu klawisza lub \"\n\"przycisku.\\n\"\n\"Jeśli nie ma zapamiętanej czułości, po prostu zapamiętaj bieżącą czułość\"\n\n#: lib/logitech_receiver/settings_templates.py:1129\nmsgid \"Off\"\nmsgstr \"Wyłączone\"\n\n#: lib/logitech_receiver/settings_templates.py:1160\nmsgid \"Disable keys\"\nmsgstr \"Wyłącz klawisze\"\n\n#: lib/logitech_receiver/settings_templates.py:1161\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"Wyłącz określone klawisze klawiatury.\"\n\n#: lib/logitech_receiver/settings_templates.py:1164\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"Wyłącza klawisz %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1177\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid \"Set OS\"\nmsgstr \"Ustaw system operacyjny\"\n\n#: lib/logitech_receiver/settings_templates.py:1178\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid \"Change keys to match OS.\"\nmsgstr \"Zmień klawisze, aby pasowały do systemu operacyjnego.\"\n\n#: lib/logitech_receiver/settings_templates.py:1247\nmsgid \"Change Host\"\nmsgstr \"Zmiana hosta\"\n\n#: lib/logitech_receiver/settings_templates.py:1248\nmsgid \"Switch connection to a different host\"\nmsgstr \"Przełącz połączenie na innego hosta\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Performs a left click.\"\nmsgstr \"Wykonuje kliknięcie lewym przyciskiem myszy.\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Single tap\"\nmsgstr \"Pojedyncze stuknięcie\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Performs a right click.\"\nmsgstr \"Wykonuje kliknięcie prawym przyciskiem myszy.\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Single tap with two fingers\"\nmsgstr \"Pojedyncze stuknięcie dwoma palcami\"\n\n#: lib/logitech_receiver/settings_templates.py:1274\nmsgid \"Single tap with three fingers\"\nmsgstr \"Pojedyncze stuknięcie trzema palcami\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Double tap\"\nmsgstr \"Podwójne stuknięcie\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Performs a double click.\"\nmsgstr \"Wykonuje podwójne kliknięcie.\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid \"Double tap with two fingers\"\nmsgstr \"Podwójne stuknięcie dwoma palcami\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Double tap with three fingers\"\nmsgstr \"Podwójne stuknięcie trzema palcami\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"\"\n\"Przeciąga elementy poprzez przeciąganie palcem po dwukrotnym stuknięciu.\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Tap and drag\"\nmsgstr \"Stuknięcie i przeciągnięcie\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"Stuknięcie i przeciągnięcie dwoma palcami\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"\"\n\"Przeciąga elementy poprzez przeciąganie palcami po dwukrotnym stuknięciu.\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"Stuknięcie i przeciągnięcie trzema palcami\"\n\n#: lib/logitech_receiver/settings_templates.py:1291\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"Stłumienie gestów stukania i krawędziowych\"\n\n#: lib/logitech_receiver/settings_templates.py:1292\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"\"\n\"Wyłącza gesty stukania i krawędziowe (odpowiednik naciśnięcia Fn + lewy \"\n\"przycisk myszy).\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\nmsgid \"Scroll with one finger\"\nmsgstr \"Przewijanie jednym palcem\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scrolls.\"\nmsgstr \"Przewija.\"\n\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scroll with two fingers\"\nmsgstr \"Przewijanie dwoma palcami\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"Przewijanie w poziomie dwoma palcami\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scrolls horizontally.\"\nmsgstr \"Przewija w poziomie.\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"Przewijanie w pionie dwoma palcami\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scrolls vertically.\"\nmsgstr \"Przewija w pionie.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"Odwraca kierunek przewijania.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Natural scrolling\"\nmsgstr \"Przewijanie naturalne\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"Włącza kółko obsługiwane kciukiem.\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Thumbwheel\"\nmsgstr \"Kółko obsługiwane kciukiem\"\n\n#: lib/logitech_receiver/settings_templates.py:1311\n#: lib/logitech_receiver/settings_templates.py:1315\nmsgid \"Swipe from the top edge\"\nmsgstr \"Przesuwanie od górnej krawędzi\"\n\n#: lib/logitech_receiver/settings_templates.py:1312\nmsgid \"Swipe from the left edge\"\nmsgstr \"Przesuwanie od lewej krawędzi\"\n\n#: lib/logitech_receiver/settings_templates.py:1313\nmsgid \"Swipe from the right edge\"\nmsgstr \"Przesuwanie od prawej krawędzi\"\n\n#: lib/logitech_receiver/settings_templates.py:1314\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"Przesuwanie od dolnej krawędzi\"\n\n#: lib/logitech_receiver/settings_templates.py:1316\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"Przesuwanie dwoma palcami od lewej krawędzi\"\n\n#: lib/logitech_receiver/settings_templates.py:1317\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"Przesuwanie dwoma palcami od prawej krawędzi\"\n\n#: lib/logitech_receiver/settings_templates.py:1318\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"Przesuwanie dwoma palcami od dolnej krawędzi\"\n\n#: lib/logitech_receiver/settings_templates.py:1319\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"Przesuwanie dwoma palcami od górnej krawędzi\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"Ściśnięcie, aby pomniejszyć; rozłożenie, aby powiększyć.\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\nmsgid \"Zoom with two fingers.\"\nmsgstr \"Zoom dwoma palcami.\"\n\n#: lib/logitech_receiver/settings_templates.py:1321\nmsgid \"Pinch to zoom out.\"\nmsgstr \"Ściśnięcie, aby pomniejszyć.\"\n\n#: lib/logitech_receiver/settings_templates.py:1322\nmsgid \"Spread to zoom in.\"\nmsgstr \"Rozłożenie, aby powiększyć.\"\n\n#: lib/logitech_receiver/settings_templates.py:1323\nmsgid \"Zoom with three fingers.\"\nmsgstr \"Zoom trzema palcami.\"\n\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Zoom with two fingers\"\nmsgstr \"Zoom dwoma palcami\"\n\n#: lib/logitech_receiver/settings_templates.py:1342\nmsgid \"Pixel zone\"\nmsgstr \"Strefa pikseli\"\n\n#: lib/logitech_receiver/settings_templates.py:1343\nmsgid \"Ratio zone\"\nmsgstr \"Strefa współczynnika\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Scale factor\"\nmsgstr \"Współczynnik skalowania\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Sets the cursor speed.\"\nmsgstr \"Ustawia szybkość kursora.\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left\"\nmsgstr \"Lewo\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left-most coordinate.\"\nmsgstr \"Współrzędna najbardziej z lewej.\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom\"\nmsgstr \"Dół\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom coordinate.\"\nmsgstr \"Współrzędna dolna.\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width\"\nmsgstr \"Szerokość\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width.\"\nmsgstr \"Szerokość.\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height\"\nmsgstr \"Wysokość\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height.\"\nmsgstr \"Wysokość.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Cursor speed.\"\nmsgstr \"Prędkość kursora.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Scale\"\nmsgstr \"Skala\"\n\n#: lib/logitech_receiver/settings_templates.py:1358\nmsgid \"Gestures\"\nmsgstr \"Gesty\"\n\n#: lib/logitech_receiver/settings_templates.py:1359\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"Dostosuj zachowania myszy/panelu dotykowego.\"\n\n#: lib/logitech_receiver/settings_templates.py:1375\nmsgid \"Gestures Diversion\"\nmsgstr \"Przekierowanie gestów\"\n\n#: lib/logitech_receiver/settings_templates.py:1376\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"Przekieruj gesty myszy/panelu dotykowego.\"\n\n#: lib/logitech_receiver/settings_templates.py:1392\nmsgid \"Gesture params\"\nmsgstr \"Parametry gestu\"\n\n#: lib/logitech_receiver/settings_templates.py:1393\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"Zmień parametry numeryczne myszy/panelu dotykowego.\"\n\n#: lib/logitech_receiver/settings_templates.py:1417\nmsgid \"M-Key LEDs\"\nmsgstr \"Diody LED klawiszy M\"\n\n#: lib/logitech_receiver/settings_templates.py:1419\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"Kontroluj diody LED klawiszy M.\"\n\n#: lib/logitech_receiver/settings_templates.py:1423\n#: lib/logitech_receiver/settings_templates.py:1454\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"Aby działało, może być konieczne włączenie przekierowania klawiszy G.\"\n\n#: lib/logitech_receiver/settings_templates.py:1429\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"Zapala klawisz %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1448\nmsgid \"MR-Key LED\"\nmsgstr \"Dioda LED klawisza MR\"\n\n#: lib/logitech_receiver/settings_templates.py:1450\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"Kontroluj diody LED klawiszy MR.\"\n\n#: lib/logitech_receiver/settings_templates.py:1471\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"Trwałe mapowanie klawiszy/przycisków\"\n\n#: lib/logitech_receiver/settings_templates.py:1473\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"Trwale zmień mapowania klawisza lub przycisku.\"\n\n#: lib/logitech_receiver/settings_templates.py:1475\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"\"\n\"Zmiana ważnych klawiszy lub przycisków (takich jak lewy przycisk myszy) może \"\n\"spowodować, że system stanie się bezużyteczny.\"\n\n#: lib/logitech_receiver/settings_templates.py:1532\nmsgid \"Sidetone\"\nmsgstr \"Efekt lokalny\"\n\n#: lib/logitech_receiver/settings_templates.py:1533\nmsgid \"Set sidetone level.\"\nmsgstr \"Ustaw poziom efektu lokalnego.\"\n\n#: lib/logitech_receiver/settings_templates.py:1542\nmsgid \"Equalizer\"\nmsgstr \"Korektor\"\n\n#: lib/logitech_receiver/settings_templates.py:1543\nmsgid \"Set equalizer levels.\"\nmsgstr \"Ustaw poziomy korektora.\"\n\n#: lib/logitech_receiver/settings_templates.py:1565\nmsgid \"Hz\"\nmsgstr \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1571\nmsgid \"Power Management\"\nmsgstr \"Zarządzanie energią\"\n\n#: lib/logitech_receiver/settings_templates.py:1572\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"Wyłączenie zasilania w minutach (0 oznacza nigdy).\"\n\n#: lib/logitech_receiver/settings_templates.py:1584\nmsgid \"Brightness Control\"\nmsgstr \"Sterowanie jasnością\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\nmsgid \"Control overall brightness\"\nmsgstr \"Steruj ogólną jasnością\"\n\n#: lib/logitech_receiver/settings_templates.py:1628\n#: lib/logitech_receiver/settings_templates.py:1681\nmsgid \"LED Control\"\nmsgstr \"Sterowanie diodami LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1629\n#: lib/logitech_receiver/settings_templates.py:1682\nmsgid \"Switch control of LED zones between device and Solaar\"\nmsgstr \"Przełącz sterowanie strefami LED pomiędzy urządzeniem a Solaar\"\n\n#: lib/logitech_receiver/settings_templates.py:1644\n#: lib/logitech_receiver/settings_templates.py:1692\nmsgid \"LED Zone Effects\"\nmsgstr \"Efekty strefowe diod LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr \"\"\n\"Sterowanie diodami LED musi być ustawione na Solaar, aby było skuteczne.\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"Set effect for LED Zone\"\nmsgstr \"Ustaw efekt dla strefy diod LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1647\nmsgid \"Color\"\nmsgstr \"Kolor\"\n\n#: lib/logitech_receiver/settings_templates.py:1648\nmsgid \"Speed\"\nmsgstr \"Szybkość\"\n\n#: lib/logitech_receiver/settings_templates.py:1649\nmsgid \"Period\"\nmsgstr \"Okres\"\n\n#: lib/logitech_receiver/settings_templates.py:1650\nmsgid \"Intensity\"\nmsgstr \"Intensywność\"\n\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid \"Ramp\"\nmsgstr \"Narastanie\"\n\n#: lib/logitech_receiver/settings_templates.py:1666\nmsgid \"LEDs\"\nmsgstr \"Diody LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1703\nmsgid \"Per-key Lighting\"\nmsgstr \"Podświetlenie poszczególnych klawiszy\"\n\n#: lib/logitech_receiver/settings_templates.py:1704\nmsgid \"Control per-key lighting.\"\nmsgstr \"Steruj podświetleniem poszczególnych klawiszy.\"\n\n#: lib/logitech_receiver/settings_templates.py:1786\nmsgid \"Force Sensing Buttons\"\nmsgstr \"Przyciski wykrywające siłę\"\n\n#: lib/logitech_receiver/settings_templates.py:1787\nmsgid \"Change the force required to activate button.\"\nmsgstr \"Zmień siłę potrzebną do aktywowania przycisku.\"\n\n#: lib/logitech_receiver/settings_templates.py:1804\nmsgid \"Force Sensing Button\"\nmsgstr \"Przycisk wykrywający siłę\"\n\n#: lib/logitech_receiver/settings_templates.py:1814\nmsgid \"Haptic Feeback Level\"\nmsgstr \"Poziom haptycznego sprzężenia zwrotnego\"\n\n#: lib/logitech_receiver/settings_templates.py:1815\nmsgid \"Change power of haptic feedback.  (Zero to turn off.)\"\nmsgstr \"\"\n\"Zmień moc haptycznego sprzężenia zwrotnego. (Zero powoduje wyłączenie.)\"\n\n#: lib/logitech_receiver/settings_templates.py:1857\nmsgid \"Play Haptic Waveform\"\nmsgstr \"Odtwórz falę haptyczną\"\n\n#: lib/logitech_receiver/settings_templates.py:1858\nmsgid \"Tell device to play a haptic waveform.\"\nmsgstr \"Poleć urządzeniu odtworzenie fali haptycznej.\"\n\n#: lib/solaar/ui/__init__.py:120\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"Inny proces programu Solaar już działa, więc po prostu pokaż jego okno\"\n\n#: lib/solaar/ui/about/model.py:36\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"Zarządza odbiornikami, klawiaturami,\\n\"\n\"myszami i tabletami firmy Logitech.\"\n\n#: lib/solaar/ui/about/model.py:63\nmsgid \"Additional Programming\"\nmsgstr \"Dodatkowe programowanie\"\n\n#: lib/solaar/ui/about/model.py:64\nmsgid \"GUI design\"\nmsgstr \"Projekt GUI\"\n\n#: lib/solaar/ui/about/model.py:66\nmsgid \"Testing\"\nmsgstr \"Testowanie\"\n\n#: lib/solaar/ui/about/model.py:74\nmsgid \"Logitech documentation\"\nmsgstr \"Dokumentacja firmy Logitech\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92\n#: lib/solaar/ui/window.py:208\nmsgid \"Unpair\"\nmsgstr \"Usuń sparowanie\"\n\n#: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141\nmsgid \"Cancel\"\nmsgstr \"Anuluj\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Permissions error\"\nmsgstr \"Błąd uprawnień\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"\"\n\"Znaleziono odbiornik lub urządzenie firmy Logitech (%s), ale nie ma \"\n\"uprawnień do jego otwarcia.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"\"\n\"Jeśli właśnie zainstalowano Solaar, spróbuj odłączyć odbiornik lub \"\n\"urządzenie, a następnie podłączyć je ponownie.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Cannot connect to device error\"\nmsgstr \"Błąd łączenia się z urządzeniem\"\n\n#: lib/solaar/ui/common.py:51\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"Znaleziono odbiornik lub urządzenie firmy Logitech w %s, ale wystąpił błąd \"\n\"podczas łączenia się z nim.\"\n\n#: lib/solaar/ui/common.py:53\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"\"\n\"Spróbuj odłączyć urządzenie, a następnie podłączyć je ponownie lub wyłączyć \"\n\"i ponownie włączyć.\"\n\n#: lib/solaar/ui/common.py:56\nmsgid \"Unpairing failed\"\nmsgstr \"Usunięcie sparowania nie powiodło się\"\n\n#: lib/solaar/ui/common.py:58\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"Nie udało się sparować %{device} z %{receiver}.\"\n\n#: lib/solaar/ui/common.py:63\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"Odbiornik zwrócił błąd bez dodatkowych informacji.\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Complete - ENTER to change\"\nmsgstr \"Kompletne - ENTER, aby zmienić\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Incomplete\"\nmsgstr \"Niekompletne\"\n\n#: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d wartość\"\nmsgstr[1] \"%d wartości\"\nmsgstr[2] \"%d wartości\"\n\n#: lib/solaar/ui/config_panel.py:642\nmsgid \"Changes allowed\"\nmsgstr \"Zmiany dozwolone\"\n\n#: lib/solaar/ui/config_panel.py:643\nmsgid \"No changes allowed\"\nmsgstr \"Zmiany niedozwolone\"\n\n#: lib/solaar/ui/config_panel.py:644\nmsgid \"Ignore this setting\"\nmsgstr \"Ignoruj to ustawienie\"\n\n#: lib/solaar/ui/config_panel.py:690\nmsgid \"Working\"\nmsgstr \"Pracuję\"\n\n#: lib/solaar/ui/config_panel.py:693\nmsgid \"Read/write operation failed.\"\nmsgstr \"Operacja odczytu/zapisu nie powiodła się.\"\n\n#: lib/solaar/ui/desktop_notifications.py:112\nmsgid \"unspecified reason\"\nmsgstr \"nieokreślony powód\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"Built-in rules\"\nmsgstr \"Wbudowane reguły\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"User-defined rules\"\nmsgstr \"Reguły zdefiniowane przez użytkownika\"\n\n#: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126\nmsgid \"Rule\"\nmsgstr \"Reguła\"\n\n#: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382\n#: lib/solaar/ui/diversion_rules.py:509\nmsgid \"Sub-rule\"\nmsgstr \"Reguła podrzędna\"\n\n#: lib/solaar/ui/diversion_rules.py:108\nmsgid \"[empty]\"\nmsgstr \"[pusta]\"\n\n#: lib/solaar/ui/diversion_rules.py:132\nmsgid \"Make changes permanent?\"\nmsgstr \"Wprowadzić zmiany na stałe?\"\n\n#: lib/solaar/ui/diversion_rules.py:137\nmsgid \"Yes\"\nmsgstr \"Tak\"\n\n#: lib/solaar/ui/diversion_rules.py:139\nmsgid \"No\"\nmsgstr \"Nie\"\n\n#: lib/solaar/ui/diversion_rules.py:144\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"Jeśli wybierzesz Nie, zmiany zostaną utracone po zamknięciu Solaar.\"\n\n#: lib/solaar/ui/diversion_rules.py:273\nmsgid \"Paste here\"\nmsgstr \"Wklej tutaj\"\n\n#: lib/solaar/ui/diversion_rules.py:275\nmsgid \"Paste above\"\nmsgstr \"Wklej powyżej\"\n\n#: lib/solaar/ui/diversion_rules.py:277\nmsgid \"Paste below\"\nmsgstr \"Wklej poniżej\"\n\n#: lib/solaar/ui/diversion_rules.py:283\nmsgid \"Paste rule here\"\nmsgstr \"Wklej regułę tutaj\"\n\n#: lib/solaar/ui/diversion_rules.py:285\nmsgid \"Paste rule above\"\nmsgstr \"Wklej regułę powyżej\"\n\n#: lib/solaar/ui/diversion_rules.py:287\nmsgid \"Paste rule below\"\nmsgstr \"Wklej regułę poniżej\"\n\n#: lib/solaar/ui/diversion_rules.py:291\nmsgid \"Paste rule\"\nmsgstr \"Wklej regułę\"\n\n#: lib/solaar/ui/diversion_rules.py:306\nmsgid \"Insert here\"\nmsgstr \"Wstaw tutaj\"\n\n#: lib/solaar/ui/diversion_rules.py:308\nmsgid \"Insert above\"\nmsgstr \"Wstaw powyżej\"\n\n#: lib/solaar/ui/diversion_rules.py:310\nmsgid \"Insert below\"\nmsgstr \"Wstaw poniżej\"\n\n#: lib/solaar/ui/diversion_rules.py:316\nmsgid \"Insert new rule here\"\nmsgstr \"Wstaw nową regułę tutaj\"\n\n#: lib/solaar/ui/diversion_rules.py:318\nmsgid \"Insert new rule above\"\nmsgstr \"Wstaw nową regułę powyżej\"\n\n#: lib/solaar/ui/diversion_rules.py:320\nmsgid \"Insert new rule below\"\nmsgstr \"Wstaw nową regułę poniżej\"\n\n#: lib/solaar/ui/diversion_rules.py:347\nmsgid \"Flatten\"\nmsgstr \"Spłaszcz\"\n\n#: lib/solaar/ui/diversion_rules.py:380\nmsgid \"Insert\"\nmsgstr \"Wstaw\"\n\n#: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511\n#: lib/solaar/ui/diversion_rules.py:1158\nmsgid \"Or\"\nmsgstr \"Lub\"\n\n#: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510\n#: lib/solaar/ui/diversion_rules.py:1144\nmsgid \"And\"\nmsgstr \"Oraz\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid \"Condition\"\nmsgstr \"Warunek\"\n\n#: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154\nmsgid \"Feature\"\nmsgstr \"Funkcja\"\n\n#: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188\nmsgid \"Report\"\nmsgstr \"Zgłoszenie\"\n\n#: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69\nmsgid \"Process\"\nmsgstr \"Proces\"\n\n#: lib/solaar/ui/diversion_rules.py:391\nmsgid \"Mouse process\"\nmsgstr \"Proces myszy\"\n\n#: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225\nmsgid \"Modifiers\"\nmsgstr \"Modyfikatory\"\n\n#: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277\nmsgid \"Key\"\nmsgstr \"Klawisz\"\n\n#: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318\nmsgid \"KeyIsDown\"\nmsgstr \"KlawiszJestWciśnięty\"\n\n#: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432\nmsgid \"Active\"\nmsgstr \"Aktywny\"\n\n#: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390\n#: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487\nmsgid \"Device\"\nmsgstr \"Urządzenie\"\n\n#: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467\nmsgid \"Host\"\nmsgstr \"Host\"\n\n#: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506\nmsgid \"Setting\"\nmsgstr \"Ustawienie\"\n\n#: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333\n#: lib/solaar/ui/rule_conditions.py:382\nmsgid \"Test\"\nmsgstr \"Test\"\n\n#: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507\nmsgid \"Test bytes\"\nmsgstr \"Bajty testowe\"\n\n#: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608\nmsgid \"Mouse Gesture\"\nmsgstr \"Gest myszy\"\n\n#: lib/solaar/ui/diversion_rules.py:405\nmsgid \"Action\"\nmsgstr \"Czynność\"\n\n#: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138\nmsgid \"Key press\"\nmsgstr \"Naciśnięcie klawisza\"\n\n#: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191\nmsgid \"Mouse scroll\"\nmsgstr \"Przewijanie myszą\"\n\n#: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256\nmsgid \"Mouse click\"\nmsgstr \"Kliknięcie myszą\"\n\n#: lib/solaar/ui/diversion_rules.py:410\nmsgid \"Set\"\nmsgstr \"Ustaw\"\n\n#: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328\nmsgid \"Execute\"\nmsgstr \"Wykonaj\"\n\n#: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189\nmsgid \"Later\"\nmsgstr \"Później\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid \"Insert new rule\"\nmsgstr \"Wstaw nową regułę\"\n\n#: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82\n#: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556\nmsgid \"Delete\"\nmsgstr \"Usuń\"\n\n#: lib/solaar/ui/diversion_rules.py:483\nmsgid \"Negate\"\nmsgstr \"Neguj\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid \"Wrap with\"\nmsgstr \"Obwiąż\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid \"Cut\"\nmsgstr \"Wytnij\"\n\n#: lib/solaar/ui/diversion_rules.py:553\nmsgid \"Paste\"\nmsgstr \"Wklej\"\n\n#: lib/solaar/ui/diversion_rules.py:559\nmsgid \"Copy\"\nmsgstr \"Skopiuj\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Edytor reguł Solaar\"\n\n#: lib/solaar/ui/diversion_rules.py:668\nmsgid \"Save changes\"\nmsgstr \"Zapisz zmiany\"\n\n#: lib/solaar/ui/diversion_rules.py:673\nmsgid \"Discard changes\"\nmsgstr \"Odrzuć zmiany\"\n\n#: lib/solaar/ui/diversion_rules.py:1104\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"Ten edytor nie obsługuje jeszcze wybranego składnika reguły.\"\n\n#: lib/solaar/ui/diversion_rules.py:1169\nmsgid \"\"\n\"Number of seconds to delay.  Delay between 0 and 1 is done with higher \"\n\"precision.\"\nmsgstr \"\"\n\"Liczba sekund opóźnienia. Opóźnienie pomiędzy 0 i 1 odbywa się z większą \"\n\"precyzją.\"\n\n#: lib/solaar/ui/diversion_rules.py:1207\nmsgid \"Not\"\nmsgstr \"Nie\"\n\n#: lib/solaar/ui/diversion_rules.py:1238\nmsgid \"Toggle\"\nmsgstr \"Przełącz\"\n\n#: lib/solaar/ui/diversion_rules.py:1239\nmsgid \"True\"\nmsgstr \"Prawda\"\n\n#: lib/solaar/ui/diversion_rules.py:1240\nmsgid \"False\"\nmsgstr \"Fałsz\"\n\n#: lib/solaar/ui/diversion_rules.py:1253\nmsgid \"Unsupported setting\"\nmsgstr \"Nieobsługiwane ustawienie\"\n\n#: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415\n#: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748\n#: lib/solaar/ui/diversion_rules.py:1766\nmsgid \"Originating device\"\nmsgstr \"Urządzenie inicjujące\"\n\n#: lib/solaar/ui/diversion_rules.py:1428\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"Urządzenie jest aktywne i można zmienić jego ustawienia.\"\n\n#: lib/solaar/ui/diversion_rules.py:1437\nmsgid \"Device that originated the current notification.\"\nmsgstr \"Urządzenie, z którego pochodzi bieżące powiadomienie.\"\n\n#: lib/solaar/ui/diversion_rules.py:1450\nmsgid \"Name of host computer.\"\nmsgstr \"Nazwa komputera hosta.\"\n\n#: lib/solaar/ui/diversion_rules.py:1520\nmsgid \"Value\"\nmsgstr \"Wartość\"\n\n#: lib/solaar/ui/diversion_rules.py:1529\nmsgid \"Item\"\nmsgstr \"Pozycja\"\n\n#: lib/solaar/ui/diversion_rules.py:1808\nmsgid \"Change setting on device\"\nmsgstr \"Zmień ustawienie w urządzeniu\"\n\n#: lib/solaar/ui/diversion_rules.py:1824\nmsgid \"Setting on device\"\nmsgstr \"Ustawienie w urządzeniu\"\n\n#: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: sparuj nowe urządzenie\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Odbiorniki Bolt są kompatybilne tylko z urządzeniami Bolt.\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"\"\n\"Naciśnij przycisk lub klawisz parowania, aż kontrolka parowania zacznie \"\n\"szybko migać.\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"Odbiorniki Unifying są kompatybilne tylko z urządzeniami Unifying.\"\n\n#: lib/solaar/ui/pair_window.py:53\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"Inne odbiorniki są kompatybilne tylko z kilkoma urządzeniami.\"\n\n#: lib/solaar/ui/pair_window.py:55\nmsgid \"For most devices, turn on the device you want to pair.\"\nmsgstr \"W przypadku większości urządzeń należy je włączyć do parowania.\"\n\n#: lib/solaar/ui/pair_window.py:56\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"Jeśli urządzenie jest już włączone, wyłącz je i włącz ponownie.\"\n\n#: lib/solaar/ui/pair_window.py:58\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"\"\n\"Urządzenia nie można parować ze znajdującym się w pobliżu włączonym \"\n\"odbiornikiem.\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid \"\"\n\"For devices with multiple channels, press, hold, and release the button for \"\n\"the channel you wish to pair\\n\"\n\"or use the channel switch button to select a channel and then press, hold, \"\n\"and release the channel switch button.\"\nmsgstr \"\"\n\"W przypadku urządzeń z wieloma kanałami naciśnij, przytrzymaj i zwolnij \"\n\"przycisk kanału do parowania\\n\"\n\"lub użyj przycisku przełączania kanałów, aby wybrać kanał, a następnie \"\n\"naciśnij, przytrzymaj i zwolnij przycisk przełączania kanałów.\"\n\n#: lib/solaar/ui/pair_window.py:68\nmsgid \"The channel indicator light should be blinking rapidly.\"\nmsgstr \"Kontrolka kanału powinna szybko migać.\"\n\n#: lib/solaar/ui/pair_window.py:72\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"Ten odbiornik ma jeszcze %d sparowanie.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"Ten odbiornik ma jeszcze %d sparowania.\"\nmsgstr[2] \"\"\n\"\\n\"\n\"\\n\"\n\"Ten odbiornik ma jeszcze %d sparowań.\"\n\n#: lib/solaar/ui/pair_window.py:78\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"Anulowanie w tym momencie nie spowoduje zużycia sparowania.\"\n\n#: lib/solaar/ui/pair_window.py:168\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"Wprowadź kod dostępu do %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:171\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"Wpisz %(passcode)s i naciśnij klawisz Enter.\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"left\"\nmsgstr \"lewo\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"right\"\nmsgstr \"prawo\"\n\n#: lib/solaar/ui/pair_window.py:178\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"Naciśnij %(code)s\\n\"\n\"i przyciśnij jednocześnie lewy i prawy przycisk.\"\n\n#: lib/solaar/ui/pair_window.py:221\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"Połączenie nie jest szyfrowane\"\n\n#: lib/solaar/ui/pair_window.py:226\nmsgid \"Found a new device:\"\nmsgstr \"Znaleziono nowe urządzenie:\"\n\n#: lib/solaar/ui/pair_window.py:247\nmsgid \"Pairing failed\"\nmsgstr \"Sparowanie nie powiodło się\"\n\n#: lib/solaar/ui/pair_window.py:249\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"Upewnij się, że urządzenie jest w zasięgu i ma naładowany akumulator.\"\n\n#: lib/solaar/ui/pair_window.py:251\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"\"\n\"Wykryto nowe urządzenie, jednak nie jest ono kompatybilne z tym odbiornikiem.\"\n\n#: lib/solaar/ui/pair_window.py:253\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"Więcej sparowanych urządzeń niż obsługuje odbiornik.\"\n\n#: lib/solaar/ui/pair_window.py:255\nmsgid \"No further details are available about the error.\"\nmsgstr \"Brak dodatkowych informacji na temat błędu.\"\n\n#: lib/solaar/ui/rule_actions.py:54\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Symuluj akordowe kliknięcie klawisza, wciśnięcie lub zwolnenie.\\n\"\n\"W Wayland wymaga dostępu do zapisu w /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:60\nmsgid \"Add key\"\nmsgstr \"Dodaj klawisz\"\n\n#: lib/solaar/ui/rule_actions.py:63\nmsgid \"Click\"\nmsgstr \"Kliknij\"\n\n#: lib/solaar/ui/rule_actions.py:66\nmsgid \"Depress\"\nmsgstr \"Wciśnij\"\n\n#: lib/solaar/ui/rule_actions.py:69\nmsgid \"Release\"\nmsgstr \"Zwolnij\"\n\n#: lib/solaar/ui/rule_actions.py:153\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Symuluj przewijanie myszy.\\n\"\n\"W Wayland wymaga dostępu do zapisu w /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:211\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Symuluj kliknięcie myszą.\\n\"\n\"W Wayland wymaga dostępu do zapisu w /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:216\nmsgid \"Button\"\nmsgstr \"Przycisk\"\n\n#: lib/solaar/ui/rule_actions.py:218\nmsgid \"Action (and Count, if click)\"\nmsgstr \"Czynność (i liczba, jeśli kliknięcie)\"\n\n#: lib/solaar/ui/rule_actions.py:269\nmsgid \"Execute a command with arguments.\"\nmsgstr \"Wykonaj polecenie z argumentami.\"\n\n#: lib/solaar/ui/rule_actions.py:273\nmsgid \"Add argument\"\nmsgstr \"Dodaj argument\"\n\n#: lib/solaar/ui/rule_conditions.py:52\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"Aktywny proces X11. Do użytku tylko w X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:82\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"Proces myszy X11. Do użytku tylko w X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:99\nmsgid \"MouseProcess\"\nmsgstr \"ProcesMyszy\"\n\n#: lib/solaar/ui/rule_conditions.py:123\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"Nazwa funkcji powiadomienia wyzwalająca przetwarzanie reguły.\"\n\n#: lib/solaar/ui/rule_conditions.py:169\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"Numer zgłoszenia powiadomienia wyzwalającego przetwarzanie reguły.\"\n\n#: lib/solaar/ui/rule_conditions.py:201\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"Aktywne modyfikatory klawiatury. Nie zawsze dostępne w Wayland.\"\n\n#: lib/solaar/ui/rule_conditions.py:241\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Przekierowany klawisz lub przycisk wciśnięto lub zwolniono.\\n\"\n\"Użyj ustawień przekierowania klawiszy/przycisków oraz przekierowania \"\n\"klawiszy G, aby przekierować klawisze i przyciski.\"\n\n#: lib/solaar/ui/rule_conditions.py:250\nmsgid \"Key down\"\nmsgstr \"Klawisz w dół\"\n\n#: lib/solaar/ui/rule_conditions.py:253\nmsgid \"Key up\"\nmsgstr \"Klawisz w górę\"\n\n#: lib/solaar/ui/rule_conditions.py:293\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Przekierowany klawisz lub przycisk jest obecnie wciśnięty.\\n\"\n\"Użyj ustawień przekierowania klawiszy/przycisków oraz przekierowania \"\n\"klawiszy G, aby przekierować klawisze i przyciski.\"\n\n#: lib/solaar/ui/rule_conditions.py:331\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"Warunek testowy przy powiadomieniu wyzwalający przetwarzanie reguły.\"\n\n#: lib/solaar/ui/rule_conditions.py:335\nmsgid \"Parameter\"\nmsgstr \"Parametr\"\n\n#: lib/solaar/ui/rule_conditions.py:408\nmsgid \"begin (inclusive)\"\nmsgstr \"rozpocznij (włącznie)\"\n\n#: lib/solaar/ui/rule_conditions.py:409\nmsgid \"end (exclusive)\"\nmsgstr \"zakończ (wyłącznie)\"\n\n#: lib/solaar/ui/rule_conditions.py:417\nmsgid \"range\"\nmsgstr \"zakres\"\n\n#: lib/solaar/ui/rule_conditions.py:420\nmsgid \"minimum\"\nmsgstr \"minimum\"\n\n#: lib/solaar/ui/rule_conditions.py:421\nmsgid \"maximum\"\nmsgstr \"maksimum\"\n\n#: lib/solaar/ui/rule_conditions.py:423\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"bajty %(0)d do %(1)d, począwszy od %(2)d do %(3)d\"\n\n#: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427\nmsgid \"mask\"\nmsgstr \"maska\"\n\n#: lib/solaar/ui/rule_conditions.py:428\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"bajty %(0)d do %(1)d, maska %(2)d\"\n\n#: lib/solaar/ui/rule_conditions.py:437\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\"Test bitowy lub zakresowy na bajtach w komunikacie powiadomienia \"\n\"uruchamiający przetwarzanie reguł.\"\n\n#: lib/solaar/ui/rule_conditions.py:447\nmsgid \"type\"\nmsgstr \"typ\"\n\n#: lib/solaar/ui/rule_conditions.py:535\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"\"\n\"Gest myszy z opcjonalnym przyciskiem inicjującym, po którym następuje zero \"\n\"lub więcej ruchów myszy.\"\n\n#: lib/solaar/ui/rule_conditions.py:541\nmsgid \"Add movement\"\nmsgstr \"Dodaj ruch\"\n\n#: lib/solaar/ui/tray.py:55\nmsgid \"No supported device found\"\nmsgstr \"Nie znaleziono obsługiwanego urządzenia\"\n\n#: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328\n#, python-format\nmsgid \"About %s\"\nmsgstr \"O programie %s\"\n\n#: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"Zakończ %s\"\n\n#: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281\nmsgid \"no receiver\"\nmsgstr \"brak odbiornika\"\n\n#: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299\nmsgid \"offline\"\nmsgstr \"wyłączone\"\n\n#: lib/solaar/ui/tray.py:297\nmsgid \"no status\"\nmsgstr \"brak statusu\"\n\n#: lib/solaar/ui/window.py:110\nmsgid \"Scanning\"\nmsgstr \"Skanowanie\"\n\n#: lib/solaar/ui/window.py:141\nmsgid \"Battery\"\nmsgstr \"Akumulator\"\n\n#: lib/solaar/ui/window.py:144\nmsgid \"Wireless Link\"\nmsgstr \"Połączenie bezprzewodowe\"\n\n#: lib/solaar/ui/window.py:148\nmsgid \"Lighting\"\nmsgstr \"Podświetlenie\"\n\n#: lib/solaar/ui/window.py:182\nmsgid \"Show Technical Details\"\nmsgstr \"Wyświetl szczegóły techniczne\"\n\n#: lib/solaar/ui/window.py:198\nmsgid \"Pair new device\"\nmsgstr \"Sparuj nowe urządzenie\"\n\n#: lib/solaar/ui/window.py:216\nmsgid \"Select a device\"\nmsgstr \"Wybierz urządzenie\"\n\n#: lib/solaar/ui/window.py:331\nmsgid \"Rule Editor\"\nmsgstr \"Edytor reguł\"\n\n#: lib/solaar/ui/window.py:522\nmsgid \"Path\"\nmsgstr \"Ścieżka\"\n\n#: lib/solaar/ui/window.py:524\nmsgid \"USB ID\"\nmsgstr \"ID USB\"\n\n#: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529\n#: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546\nmsgid \"Serial\"\nmsgstr \"Nr seryjny\"\n\n#: lib/solaar/ui/window.py:533\nmsgid \"Index\"\nmsgstr \"Indeks\"\n\n#: lib/solaar/ui/window.py:535\nmsgid \"Wireless PID\"\nmsgstr \"PID bezprz.\"\n\n#: lib/solaar/ui/window.py:537\nmsgid \"Product ID\"\nmsgstr \"ID produktu\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Protocol\"\nmsgstr \"Protokół\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Unknown\"\nmsgstr \"Nieznany\"\n\n#: lib/solaar/ui/window.py:541\nmsgid \"Polling rate\"\nmsgstr \"Odpytywanie\"\n\n#: lib/solaar/ui/window.py:548\nmsgid \"Unit ID\"\nmsgstr \"ID jednostki\"\n\n#: lib/solaar/ui/window.py:560\nmsgid \"Notifications\"\nmsgstr \"Powiadomienia\"\n\n#: lib/solaar/ui/window.py:604\nmsgid \"No device paired.\"\nmsgstr \"Brak sparowanych urządzeń.\"\n\n#: lib/solaar/ui/window.py:613\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"\"\n\"Można sparować maksymalnie %(max_count)s urządzenie z tym odbiornikiem.\"\nmsgstr[1] \"\"\n\"Można sparować maksymalnie %(max_count)s urządzenia z tym odbiornikiem.\"\nmsgstr[2] \"\"\n\"Można sparować maksymalnie %(max_count)s urządzeń z tym odbiornikiem.\"\n\n#: lib/solaar/ui/window.py:624\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"Ten odbiornik ma jeszcze %d sparowanie.\"\nmsgstr[1] \"Ten odbiornik ma jeszcze %d sparowania.\"\nmsgstr[2] \"Ten odbiornik ma jeszcze %d sparowań.\"\n\n#: lib/solaar/ui/window.py:681\nmsgid \"Battery Voltage\"\nmsgstr \"Napięcie akumulatora\"\n\n#: lib/solaar/ui/window.py:683\nmsgid \"Voltage reported by battery\"\nmsgstr \"Napięcie zgłoszone przez akumulator\"\n\n#: lib/solaar/ui/window.py:685\nmsgid \"Battery Level\"\nmsgstr \"Poziom akumulatora\"\n\n#: lib/solaar/ui/window.py:687\nmsgid \"Approximate level reported by battery\"\nmsgstr \"Przybliżony poziom zgłoszony przez akumulator\"\n\n#: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696\nmsgid \"next reported \"\nmsgstr \"następny zgłoszony \"\n\n#: lib/solaar/ui/window.py:697\nmsgid \" and next level to be reported.\"\nmsgstr \" oraz następny poziom do zgłoszenia.\"\n\n#: lib/solaar/ui/window.py:713\nmsgid \"encrypted\"\nmsgstr \"szyfrowane\"\n\n#: lib/solaar/ui/window.py:715\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"\"\n\"Połączenie bezprzewodowe pomiędzy tym urządzeniem i odbiornikiem jest \"\n\"szyfrowane.\"\n\n#: lib/solaar/ui/window.py:717\nmsgid \"not encrypted\"\nmsgstr \"nieszyfrowane\"\n\n#: lib/solaar/ui/window.py:721\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"Łącze bezprzewodowe między tym urządzeniem a jego odbiornikiem nie jest \"\n\"szyfrowane.\\n\"\n\"Jest to problem dotyczący zabezpieczeń urządzeń wskazujących i poważny \"\n\"problem dotyczący zabezpieczeń urządzeń do wprowadzania tekstu.\"\n\n#: lib/solaar/ui/window.py:737\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d lx\"\n"
  },
  {
    "path": "po/pt.po",
    "content": "# Translation of solaar's ui's messages to European Portuguese\n# Copyright (C) 2014 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n#\n# Américo Monteiro <a_monteiro@gmx.com>, 2014.\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 0.9.2\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n        \"PO-Revision-Date: 2014-09-14 20:57+0100\\n\"\n        \"Last-Translator: Américo Monteiro <a_monteiro@gmx.com>\\n\"\n        \"Language-Team: Portuguese <traduz@debianpt.org>\\n\"\n        \"Language: pt\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n        \"X-Generator: Lokalize 1.4\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid   \"Bolt Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid   \"Unifying Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid   \"Nano Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"empty\"\nmsgstr  \"vazio\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"critical\"\nmsgstr  \"crítico\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"low\"\nmsgstr  \"baixo\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"average\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid   \"good\"\nmsgstr  \"bom\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"full\"\nmsgstr  \"cheio\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"discharging\"\nmsgstr  \"a descarregar\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"recharging\"\nmsgstr  \"a carregar\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid   \"charging\"\nmsgstr  \"a carregar\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"not charging\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"almost full\"\nmsgstr  \"quase cheiro\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"charged\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"slow recharge\"\nmsgstr  \"carga lenta\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"invalid battery\"\nmsgstr  \"bateria inválida\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"thermal error\"\nmsgstr  \"erro térmico\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"error\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid   \"standard\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"fast\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid   \"device timeout\"\nmsgstr  \"tempo limite do dispositivo\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid   \"device not supported\"\nmsgstr  \"dispositivo não suportado\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"too many devices\"\nmsgstr  \"demasiados dispositivos\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"sequence timeout\"\nmsgstr  \"tempo limite da sequência\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid   \"Firmware\"\nmsgstr  \"Firmware\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Bootloader\"\nmsgstr  \"Gestor de arranque\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Hardware\"\nmsgstr  \"Hardware\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Other\"\nmsgstr  \"Outro\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Smart Shift\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"DPI Switch\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Left Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Right Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Left Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Right Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"Mouse Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid   \"pressed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid   \"released\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid   \"connected\"\nmsgstr  \"ligado\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid   \"disconnected\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid   \"unpaired\"\nmsgstr  \"desemparelhado\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid   \"powered on\"\nmsgstr  \"com energia ligada\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid   \"register\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid   \"feature\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid   \"Swap Fx function\"\nmsgstr  \"Trocar função Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"Quando definido, as teclas F1..F12 irão activar as suas funções \"\n        \"especiais,\\n\"\n        \"e você tem manter a tecla FN carregada para activar as suas funções \"\n        \"standard.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"Quando não definido, as teclas F1..F12 irão activar as suas funções \"\n        \"standard,\\n\"\n        \"e você tem manter a tecla FN carregada para activar as suas funções \"\n        \"especiais.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid   \"Hand Detection\"\nmsgstr  \"Detecção de Mão\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"Liga a iluminação quando as mãos estão sobre o teclado.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"Modo de alta-sensibilidade para deslocamento vertical com a roda.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid   \"Side Scrolling\"\nmsgstr  \"Deslocamento Lateral\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"Quando desactivado, premir a roda para os lados envia eventos de \"\n        \"botões personalizados\\n\"\n        \"em vez dos eventos de deslocamento lateral standard.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid   \"Backlight\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid   \"Turn illumination on or off on keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid   \"Onboard Profiles\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid   \"Enable onboard profiles, which often control report rate and \"\n        \"keyboard lighting\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid   \"Polling Rate (ms)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid   \"Frequency of device polling, in milliseconds\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid   \"Divert crown events\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid   \"Divert G Keys\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid   \"Make G keys send GKEY HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid   \"May also make M keys and MR key send HID++ notifications\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Freespinning\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid   \"Key/Button Actions\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Diverted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid   \"Mouse Gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Regular\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid   \"Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"Sensibilidade (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid   \"Off\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid   \"Disable keys\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid   \"Set OS\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid   \"Change Host\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Performs a left click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Single tap\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Performs a right click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Double tap\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Performs a double click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Tap and drag\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid   \"Scroll with one finger\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scrolls.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Natural scrolling\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Thumbwheel\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid   \"Pixel zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid   \"Ratio zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Scale factor\"\nmsgstr  \"Fator de escala\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width\"\nmsgstr  \"Largura\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height\"\nmsgstr  \"Altura\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Cursor speed.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Scale\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid   \"Gestures\"\nmsgstr  \"Gestos\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid   \"Gestures Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid   \"Gesture params\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid   \"M-Key LEDs\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid   \"MR-Key LED\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Sidetone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid   \"Set sidetone level.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid   \"Equalizer\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid   \"Hz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid   \"Power Management\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid   \"No paired devices.\"\nmsgstr  \"Nenhum dispositivo emparelhado.\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid   \"Battery: %(level)s\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid   \"Battery: %(percent)d%%\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid   \"Lighting: %(level)s lux\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid   \"Permissions error\"\nmsgstr  \"Erro de permissões\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid   \"Unpairing failed\"\nmsgstr  \"Desemparelhamento falhado\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"O receptor devolveu um erro, sem mais detalhes.\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:44\nmsgid   \"Additional Programming\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:45\nmsgid   \"GUI design\"\nmsgstr  \"Desenho da GUI\"\n\n#: lib/solaar/ui/about.py:47\nmsgid   \"Testing\"\nmsgstr  \"A testar\"\n\n#: lib/solaar/ui/about.py:54\nmsgid   \"Logitech documentation\"\nmsgstr  \"Documentação da Logitech\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid   \"Unpair\"\nmsgstr  \"Desemparelhar\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid   \"Cancel\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Incomplete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid   \"Changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid   \"No changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid   \"Ignore this setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid   \"Working\"\nmsgstr  \"A funcionar\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"Operação de leitura/escrita falhada.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"Built-in rules\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"User-defined rules\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid   \"Rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid   \"Sub-rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid   \"[empty]\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Make changes permanent?\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid   \"Yes\"\nmsgstr  \"Sim\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid   \"No\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid   \"Save changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid   \"Discard changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid   \"Insert here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid   \"Insert above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid   \"Insert below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid   \"Insert new rule here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid   \"Insert new rule above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Insert new rule below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid   \"Paste here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid   \"Paste above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid   \"Paste below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid   \"Paste rule here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid   \"Paste rule above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Paste rule below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid   \"Paste rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid   \"Flatten\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Insert\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Or\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid   \"And\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid   \"Condition\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid   \"Feature\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid   \"Report\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid   \"Process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid   \"Mouse process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid   \"Modifiers\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid   \"Key\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid   \"KeyIsDown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid   \"Active\"\nmsgstr  \"Ativo\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid   \"Device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid   \"Setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid   \"Test\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid   \"Test bytes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid   \"Mouse Gesture\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid   \"Action\"\nmsgstr  \"Ação\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid   \"Key press\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid   \"Mouse scroll\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid   \"Mouse click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Set\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid   \"Execute\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Later\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Insert new rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid   \"Delete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid   \"Negate\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid   \"Wrap with\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid   \"Cut\"\nmsgstr  \"Cortar\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid   \"Paste\"\nmsgstr  \"Colar\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid   \"Copy\"\nmsgstr  \"Copiar\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid   \"Number of seconds to delay.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid   \"Not\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid   \"MouseProcess\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid   \"Key down\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid   \"Key up\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid   \"Parameter\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid   \"begin (inclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid   \"end (exclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid   \"range\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid   \"minimum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid   \"maximum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid   \"mask\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid   \"type\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid   \"Add movement\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid   \"Add key\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid   \"Click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid   \"Depress\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid   \"Release\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid   \"Button\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid   \"Count and Action\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid   \"Add argument\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"Toggle\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"True\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid   \"False\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid   \"Unsupported setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid   \"Originating device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid   \"Name of host computer.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid   \"Value\"\nmsgstr  \"Valor\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid   \"Item\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid   \"Change setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid   \"Setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid   \"offline\"\nmsgstr  \"offline\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"left\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"right\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid   \"Pairing failed\"\nmsgstr  \"Emparelhamento falhado\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"Certifique-se que o seu dispositivo está dentro do alcance, e tem \"\n        \"uma carga de bateria decente.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"Foi detectado um novo dispositivo, mas não é compatível com este \"\n        \"receptor.\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"Não há mais detalhes disponíveis acerca do erro.\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid   \"Found a new device:\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"A ligação sem fios não está encriptada\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid   \"You may have to first turn the device off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid   \"Turn on the device you want to pair.\"\nmsgstr  \"Ligue o dispositivo que deseja emparelhar.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid   \"No supported device found\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"Acerca de %s\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"Terminar %s\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid   \"no receiver\"\nmsgstr  \"nenhum receptor\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid   \"no status\"\nmsgstr  \"nenhum estado\"\n\n#: lib/solaar/ui/window.py:96\nmsgid   \"Scanning\"\nmsgstr  \"A sondar\"\n\n#: lib/solaar/ui/window.py:129\nmsgid   \"Battery\"\nmsgstr  \"Bateria\"\n\n#: lib/solaar/ui/window.py:132\nmsgid   \"Wireless Link\"\nmsgstr  \"Ligação Sem Fios\"\n\n#: lib/solaar/ui/window.py:136\nmsgid   \"Lighting\"\nmsgstr  \"Iluminação\"\n\n#: lib/solaar/ui/window.py:170\nmsgid   \"Show Technical Details\"\nmsgstr  \"Mostrar Detalhes Técnicos\"\n\n#: lib/solaar/ui/window.py:186\nmsgid   \"Pair new device\"\nmsgstr  \"Emparelhar novo dispositivo\"\n\n#: lib/solaar/ui/window.py:205\nmsgid   \"Select a device\"\nmsgstr  \"Seleccionar um dispositivo\"\n\n#: lib/solaar/ui/window.py:322\nmsgid   \"Rule Editor\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Path\"\nmsgstr  \"Caminho\"\n\n#: lib/solaar/ui/window.py:536\nmsgid   \"USB ID\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid   \"Serial\"\nmsgstr  \"Série\"\n\n#: lib/solaar/ui/window.py:545\nmsgid   \"Index\"\nmsgstr  \"Índice\"\n\n#: lib/solaar/ui/window.py:547\nmsgid   \"Wireless PID\"\nmsgstr  \"PID de ligação sem fios\"\n\n#: lib/solaar/ui/window.py:549\nmsgid   \"Product ID\"\nmsgstr  \"ID do produto\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Protocol\"\nmsgstr  \"Protocolo\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Unknown\"\nmsgstr  \"Desconhecido\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid   \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:554\nmsgid   \"Polling rate\"\nmsgstr  \"Rácio de votações\"\n\n#: lib/solaar/ui/window.py:565\nmsgid   \"Unit ID\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:576\nmsgid   \"none\"\nmsgstr  \"nenhum\"\n\n#: lib/solaar/ui/window.py:577\nmsgid   \"Notifications\"\nmsgstr  \"Notificações\"\n\n#: lib/solaar/ui/window.py:621\nmsgid   \"No device paired.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\n\n#: lib/solaar/ui/window.py:634\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\n\n#: lib/solaar/ui/window.py:692\nmsgid   \"Battery Voltage\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:694\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:696\nmsgid   \"Battery Level\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:698\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid   \"next reported \"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:708\nmsgid   \" and next level to be reported.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"last known\"\nmsgstr  \"último conhecido\"\n\n#: lib/solaar/ui/window.py:724\nmsgid   \"encrypted\"\nmsgstr  \"encriptado\"\n\n#: lib/solaar/ui/window.py:726\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"A ligação sem fios entre este dispositivo e o seu receptor está \"\n        \"encriptada.\"\n\n#: lib/solaar/ui/window.py:728\nmsgid   \"not encrypted\"\nmsgstr  \"não encriptado\"\n\n#: lib/solaar/ui/window.py:732\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"\"\n\n#~ msgid        \" paired devices.\"\n#~ msgstr       \" dispositivos emparelhados.\"\n\n#~ msgid        \"1 paired device.\"\n#~ msgstr       \"1 dispositivo emparelhado.\"\n\n#~ msgid        \"Count\"\n#~ msgstr       \"Contagem\"\n\n#, python-format\n#~ msgid        \"Failed to unpair %s from %s.\"\n#~ msgstr       \"Falha ao desemparelhar %s de %s.\"\n\n#, python-format\n#~ msgid        \"Found a Logitech Receiver (%s), but did not have permission \"\n#~      \"to open it.\"\n#~ msgstr       \"Encontrado um Receptor Logitech (%s), mas não teve \"\n#~      \"permissões para o abrir.\"\n\n#~ msgid        \"Found a new device\"\n#~ msgstr       \"Encontrado um novo dispositivo\"\n\n#~ msgid        \"If the device is already turned on,\\n\"\n#~      \"turn if off and on again.\"\n#~ msgstr       \"Se o dispositivo já está ligado,\\n\"\n#~      \"desligue-o e volte a ligá-lo.\"\n\n#~ msgid        \"If you've just installed Solaar, try removing the receiver \"\n#~      \"and plugging it back in.\"\n#~ msgstr       \"Se você acabou de instalar o Solaar, tente remover o \"\n#~      \"receptor e ligá-lo de novo.\"\n\n#~ msgid        \"No Logitech receiver found\"\n#~ msgstr       \"Nenhum receptor Logitech encontrado\"\n\n#~ msgid        \"No device paired\"\n#~ msgstr       \"Nenhum dispositivo emparelhado\"\n\n#~ msgid        \"Only one device can be paired to this receiver\"\n#~ msgstr       \"Apenas um dispositivo pode ser emparelhado com este receptor\"\n\n#~ msgid        \"Shows status of devices connected\\n\"\n#~      \"through wireless Logitech receivers.\"\n#~ msgstr       \"Mostra o estado dos dispositivos ligados\\n\"\n#~      \"através de receptores sem fio da Logitech.\"\n\n#~ msgid        \"Smooth Scrolling\"\n#~ msgstr       \"Deslocamento de Ecrã Suave\"\n\n#, python-format\n#~ msgid        \"The receiver only supports %d paired device(s).\"\n#~ msgstr       \"O receptor apenas suporta %d dispositivo(s) emparelhados.\"\n\n#~ msgid        \"The receiver was unplugged.\"\n#~ msgstr       \"O receptor foi desligado.\"\n\n#~ msgid        \"The wireless link between this device and its receiver is \"\n#~      \"not encrypted.\\n\"\n#~      \"\\n\"\n#~      \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~      \"security issue.\\n\"\n#~      \"\\n\"\n#~      \"It is, however, a major security issue for text-input devices \"\n#~      \"(keyboards, numpads),\\n\"\n#~      \"because typed text can be sniffed inconspicuously by 3rd parties \"\n#~      \"within range.\"\n#~ msgstr       \"A ligação sem fios entre este dispositivo e o seu receptor \"\n#~      \"não está encriptada.\\n\"\n#~      \"\\n\"\n#~      \"Para dispositivos apontadores (ratos, trackballs, trackpads), este é \"\n#~      \"um problema de segurança menor.\\n\"\n#~      \"\\n\"\n#~      \"No entanto, é um problema de segurança maior para dispositivos de \"\n#~      \"entrada de texto (teclados, teclados numéricos).\\n\"\n#~      \"porque o texto teclado pode ser \\\"cheirado\\\" de modo imperceptível \"\n#~      \"por terceiros que estejam dentro do alcance da ligação.\"\n\n#~ msgid        \"USB id\"\n#~ msgstr       \"id de USB\"\n\n#, python-format\n#~ msgid        \"Up to %d devices can be paired to this receiver\"\n#~ msgstr       \"Podem ser emparelhados até %d dispositivos com este receptor\"\n\n#~ msgid        \"closed\"\n#~ msgstr       \"fechado\"\n\n#~ msgid        \"height\"\n#~ msgstr       \"altura\"\n\n#~ msgid        \"lux\"\n#~ msgstr       \"lux\"\n\n#~ msgid        \"open\"\n#~ msgstr       \"aberto\"\n\n#~ msgid        \"pair new device\"\n#~ msgstr       \"emparelhar o novo dispositivo\"\n\n#~ msgid        \"paired devices\"\n#~ msgstr       \"dispositivos emparelhados\"\n\n#~ msgid        \"pairing lock is \"\n#~ msgstr       \"tranca de emparelhamento é \"\n\n#~ msgid        \"unknown\"\n#~ msgstr       \"desconhecido\"\n\n#~ msgid        \"width\"\n#~ msgstr       \"largura\"\n"
  },
  {
    "path": "po/pt_BR.po",
    "content": "# Portuguese translations for solaar package.\n# Copyright (C) 2015 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2015.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 0.9.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2026-01-08 19:37-0300\\n\"\n\"PO-Revision-Date: 2026-01-08 22:37-0300\\n\"\n\"Last-Translator: Mário Victor Ribeiro Silva <mariovictorrs@gmail.com>\\n\"\n\"Language-Team: Sídnei A. Drovetto Jr.\\n\"\n\"Language: pt_BR\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=n > 1;\\n\"\n\"X-Launchpad-Export-Date: 2020-10-21 16:52+0000\\n\"\n\"X-Generator: Poedit 3.8\\n\"\n\n#: lib/logitech_receiver/base_usb.py:52\nmsgid \"Bolt Receiver\"\nmsgstr \"Receptor Bolt\"\n\n#: lib/logitech_receiver/base_usb.py:64\nmsgid \"Unifying Receiver\"\nmsgstr \"Receptor Unifying\"\n\n#: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87\n#: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113\nmsgid \"Nano Receiver\"\nmsgstr \"Receptor Nano\"\n\n#: lib/logitech_receiver/base_usb.py:125\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Receptor Lightspeed\"\n\n#: lib/logitech_receiver/base_usb.py:136\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"Receptor EX100 27 Mhz\"\n\n#: lib/logitech_receiver/common.py:649\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"Bateria: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:652\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"Bateria: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:1048\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid \"Disabled\"\nmsgstr \"Desativado\"\n\n#: lib/logitech_receiver/hidpp20.py:1049\nmsgid \"Static\"\nmsgstr \"Estático\"\n\n#: lib/logitech_receiver/hidpp20.py:1050\nmsgid \"Pulse\"\nmsgstr \"Pulso\"\n\n#: lib/logitech_receiver/hidpp20.py:1051\nmsgid \"Cycle\"\nmsgstr \"Ciclo\"\n\n#: lib/logitech_receiver/hidpp20.py:1052\nmsgid \"Boot\"\nmsgstr \"Inicialização\"\n\n#: lib/logitech_receiver/hidpp20.py:1053\nmsgid \"Demo\"\nmsgstr \"Demonstração\"\n\n#: lib/logitech_receiver/hidpp20.py:1055\nmsgid \"Breathe\"\nmsgstr \"Respirar\"\n\n#: lib/logitech_receiver/hidpp20.py:1058\nmsgid \"Ripple\"\nmsgstr \"Ondulação\"\n\n#: lib/logitech_receiver/hidpp20.py:1059\nmsgid \"Decomposition\"\nmsgstr \"Decomposição\"\n\n#: lib/logitech_receiver/hidpp20.py:1060\nmsgid \"Signature1\"\nmsgstr \"Assinatura1\"\n\n#: lib/logitech_receiver/hidpp20.py:1061\nmsgid \"Signature2\"\nmsgstr \"Assinatura2\"\n\n#: lib/logitech_receiver/hidpp20.py:1062\nmsgid \"CycleS\"\nmsgstr \"CicloS\"\n\n#: lib/logitech_receiver/hidpp20.py:1126\nmsgid \"Unknown Location\"\nmsgstr \"Localização Desconhecida\"\n\n#: lib/logitech_receiver/hidpp20.py:1127\nmsgid \"Primary\"\nmsgstr \"Primário\"\n\n#: lib/logitech_receiver/hidpp20.py:1128\nmsgid \"Logo\"\nmsgstr \"Logotipo\"\n\n#: lib/logitech_receiver/hidpp20.py:1129\nmsgid \"Left Side\"\nmsgstr \"Lado esquerdo\"\n\n#: lib/logitech_receiver/hidpp20.py:1130\nmsgid \"Right Side\"\nmsgstr \"Lado direito\"\n\n#: lib/logitech_receiver/hidpp20.py:1131\nmsgid \"Combined\"\nmsgstr \"Combinado\"\n\n#: lib/logitech_receiver/hidpp20.py:1132\nmsgid \"Primary 1\"\nmsgstr \"Primário 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1133\nmsgid \"Primary 2\"\nmsgstr \"Primário 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1134\nmsgid \"Primary 3\"\nmsgstr \"Primário 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1135\nmsgid \"Primary 4\"\nmsgstr \"Primário 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1136\nmsgid \"Primary 5\"\nmsgstr \"Primário 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1137\nmsgid \"Primary 6\"\nmsgstr \"Primário 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"vazia\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"crítica\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"fraca\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"média\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"boa\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"cheia\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"descarregando\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"recarregando\"\n\n#: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700\nmsgid \"charging\"\nmsgstr \"carregando\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"não carregando\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"quase cheia\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"carregada\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"recarga lenta\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"invalid battery\"\nmsgstr \"bateria inválida\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"erro térmico\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"erro\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"padrão\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"rápido\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"lento\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"tempo esgotado do dispositivo\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"dispositivo não suportado\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"número excessivo de dispositivos\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"tempo esgotado da sequência\"\n\n#: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555\nmsgid \"Firmware\"\nmsgstr \"Firmware\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"Bootloader\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"Hardware\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"Outro\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"Botão da esquerda\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"Botão da direita\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"Botão do meio\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"Botão Voltar\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"Botão Avançar\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"Botão de gestos do mouse\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"Smart Shift\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"Mudança de DPI\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"Inclinação para a esquerda\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"Inclinação para a direita\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"Clique com o botão esquerdo\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"Clique com o botão direito\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"Botão do meio do mouse\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"Botão de voltar do mouse\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"Botão de avançar do mouse\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"Botão de navegação por gestos\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"Botão de rolagem esquerda do mouse\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"Botão de rolagem direita do mouse\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"pressionada\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"liberada\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"connected\"\nmsgstr \"conectado\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"disconnected\"\nmsgstr \"desconectado\"\n\n#: lib/logitech_receiver/notifications.py:182\nmsgid \"unpaired\"\nmsgstr \"desemparelhado\"\n\n#: lib/logitech_receiver/notifications.py:231\nmsgid \"powered on\"\nmsgstr \"ligado\"\n\n#: lib/logitech_receiver/notifications.py:283\nmsgid \"ADC measurement notification\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:484\nmsgid \"pairing lock is closed\"\nmsgstr \"trava de emparelhamento está fechada\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:484\nmsgid \"pairing lock is open\"\nmsgstr \"trava de emparelhamento está aberta\"\n\n#: lib/logitech_receiver/notifications.py:447\nmsgid \"discovery lock is closed\"\nmsgstr \"bloqueio de descoberta está fechado\"\n\n#: lib/logitech_receiver/notifications.py:447\nmsgid \"discovery lock is open\"\nmsgstr \"bloqueio de descoberta está aberto\"\n\n#: lib/logitech_receiver/receiver.py:437\nmsgid \"No paired devices.\"\nmsgstr \"Nenhum dispositivo emparelhado.\"\n\n#: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s dispositivo emparelhado.\"\nmsgstr[1] \"%(count)s dispositivos emparelhados.\"\n\n#: lib/logitech_receiver/settings.py:602\nmsgid \"register\"\nmsgstr \"register\"\n\n#: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654\nmsgid \"feature\"\nmsgstr \"feature\"\n\n#: lib/logitech_receiver/settings_templates.py:138\nmsgid \"Swap Fx function\"\nmsgstr \"Trocar função de teclas Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:141\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"Quando marcada, as teclas F1..F12 vão acionar sua função especial,\\n\"\n\"e você precisa manter pressionada a tecla FN para acionar sua função padrão.\"\n\n#: lib/logitech_receiver/settings_templates.py:146\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"Quando desmarcada, as teclas F1..F12 vão acionar sua função padrão,\\n\"\n\"e você precisa pressionar a tecla FN para acionar sua função especial.\"\n\n#: lib/logitech_receiver/settings_templates.py:154\nmsgid \"Hand Detection\"\nmsgstr \"Detecção de Mão\"\n\n#: lib/logitech_receiver/settings_templates.py:155\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"Ligar a iluminação quando a mão estiver sobre o telcado.\"\n\n#: lib/logitech_receiver/settings_templates.py:162\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"Rolagem suave com a roda\"\n\n#: lib/logitech_receiver/settings_templates.py:163\n#: lib/logitech_receiver/settings_templates.py:410\n#: lib/logitech_receiver/settings_templates.py:439\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"Modo de alta-sensibilidade para rolagem vertical com a roda.\"\n\n#: lib/logitech_receiver/settings_templates.py:170\nmsgid \"Side Scrolling\"\nmsgstr \"Rolagem Lateral\"\n\n#: lib/logitech_receiver/settings_templates.py:172\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"Quando desabilitado, pressionar a roda lateralmente envia eventos \"\n\"customizados\\n\"\n\"ao invés dos eventos tradicionais de rolagem lateral.\"\n\n#: lib/logitech_receiver/settings_templates.py:182\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"Sensibilidade (DPI - mouses antigos)\"\n\n#: lib/logitech_receiver/settings_templates.py:183\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"Sensibilidade do movimento do mouse\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid \"Backlight Timed\"\nmsgstr \"Temporizador de luz de fundo\"\n\n#: lib/logitech_receiver/settings_templates.py:257\n#: lib/logitech_receiver/settings_templates.py:397\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"Defina o tempo de iluminação do teclado.\"\n\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid \"Backlight\"\nmsgstr \"Luz de fundo\"\n\n#: lib/logitech_receiver/settings_templates.py:269\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"\"\n\"Nível de iluminação do teclado. As alterações feitas só se aplicam no modo \"\n\"Manual.\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid \"Automatic\"\nmsgstr \"Automático\"\n\n#: lib/logitech_receiver/settings_templates.py:303\nmsgid \"Manual\"\nmsgstr \"Manual\"\n\n#: lib/logitech_receiver/settings_templates.py:305\nmsgid \"Enabled\"\nmsgstr \"Habilitado\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid \"Backlight Level\"\nmsgstr \"Nível de luz de fundo\"\n\n#: lib/logitech_receiver/settings_templates.py:312\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"Nível de iluminação do teclado no modo Manual.\"\n\n#: lib/logitech_receiver/settings_templates.py:369\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"Atraso da luz de fundo ao retirar as mãos\"\n\n#: lib/logitech_receiver/settings_templates.py:370\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"\"\n\"Tempo de atraso, em segundos, até que a luz de fundo se apague gradualmente \"\n\"quando as mãos forem retiradas do teclado.\"\n\n#: lib/logitech_receiver/settings_templates.py:378\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"Atraso da luz de fundo ao colocar as mãos\"\n\n#: lib/logitech_receiver/settings_templates.py:379\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"\"\n\"Tempo de atraso, em segundos, até que a luz de fundo se apague com as mãos \"\n\"próximas ao teclado.\"\n\n#: lib/logitech_receiver/settings_templates.py:387\nmsgid \"Backlight Delay Powered\"\nmsgstr \"Atraso da luz de fundo Alimentado\"\n\n#: lib/logitech_receiver/settings_templates.py:388\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"\"\n\"Tempo de atraso, em segundos, até que a luz de fundo se apague com a \"\n\"alimentação externa.\"\n\n#: lib/logitech_receiver/settings_templates.py:396\nmsgid \"Backlight (Seconds)\"\nmsgstr \"Luz de fundo (segundos)\"\n\n#: lib/logitech_receiver/settings_templates.py:408\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"Alta resolução de rolagem com a roda\"\n\n#: lib/logitech_receiver/settings_templates.py:412\n#: lib/logitech_receiver/settings_templates.py:441\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"Configure para ignorar se a rolagem for anormalmente rápida ou lenta\"\n\n#: lib/logitech_receiver/settings_templates.py:419\n#: lib/logitech_receiver/settings_templates.py:450\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"Desvio da roda de rolagem\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:428\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"Direção de rolagem\"\n\n#: lib/logitech_receiver/settings_templates.py:429\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"Inverte a direção da rolagem vertical.\"\n\n#: lib/logitech_receiver/settings_templates.py:437\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"Resolução da roda de rolagem\"\n\n#: lib/logitech_receiver/settings_templates.py:452\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:461\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"Sensibilidade (Velocidade do Ponteiro)\"\n\n#: lib/logitech_receiver/settings_templates.py:462\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"Fator de multiplicação da velocidade do mouse (256 é o fator normal).\"\n\n#: lib/logitech_receiver/settings_templates.py:472\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"Desvio da roda de polegar\"\n\n#: lib/logitech_receiver/settings_templates.py:474\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:483\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"Direção da rolagem com a roda\"\n\n#: lib/logitech_receiver/settings_templates.py:484\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"Inverter a direção da rolagem com o polegar.\"\n\n#: lib/logitech_receiver/settings_templates.py:504\nmsgid \"Onboard Profiles\"\nmsgstr \"Perfis Embarcados\"\n\n#: lib/logitech_receiver/settings_templates.py:505\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:549\n#: lib/logitech_receiver/settings_templates.py:582\nmsgid \"Report Rate\"\nmsgstr \"Taxa de relatório\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\nmsgid \"Frequency of device movement reports\"\nmsgstr \"Frequência de relatórios de movimentação de dispositivos\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1421\n#: lib/logitech_receiver/settings_templates.py:1452\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:612\nmsgid \"Divert crown events\"\nmsgstr \"Desviar eventos da coroa\"\n\n#: lib/logitech_receiver/settings_templates.py:613\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Faz a coroa enviar notificações HID++ CROWN (que desencadeiam regras do \"\n\"Solaar, mas são ignoradas fora disso).\"\n\n#: lib/logitech_receiver/settings_templates.py:621\nmsgid \"Crown smooth scroll\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:622\nmsgid \"Set crown smooth scroll\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:630\nmsgid \"Divert G and M Keys\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:631\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:646\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Freespinning\"\nmsgstr \"Giro livre\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Ratcheted\"\nmsgstr \"Ratcheted\"\n\n#: lib/logitech_receiver/settings_templates.py:655\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:657\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:707\nmsgid \"Scroll Wheel Ratchet Torque\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:708\nmsgid \"Change the torque needed to overcome the ratchet.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:743\nmsgid \"Key/Button Actions\"\nmsgstr \"Ações das teclas/botões\"\n\n#: lib/logitech_receiver/settings_templates.py:745\nmsgid \"Change the action for the key or button.\"\nmsgstr \"Trocar a ação da tecla/botão.\"\n\n#: lib/logitech_receiver/settings_templates.py:747\nmsgid \"Overridden by diversion.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:749\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"\"\n\"Trocar ações importantes (como a do botão esquerdo do mouse) pode tornar o \"\n\"sistema inutilizável.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid \"Key/Button Diversion\"\nmsgstr \"Desvio de Tecla/Botão\"\n\n#: lib/logitech_receiver/settings_templates.py:925\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse \"\n\"Gestures or Sliding DPI\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Diverted\"\nmsgstr \"Desviado\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\nmsgid \"Mouse Gestures\"\nmsgstr \"Gestos do mouse\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Regular\"\nmsgstr \"Regular\"\n\n#: lib/logitech_receiver/settings_templates.py:928\nmsgid \"Sliding DPI\"\nmsgstr \"DPI deslizante\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"Sensibilidade (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:1123\nmsgid \"Sensitivity Switching\"\nmsgstr \"Alternar sensibilidade\"\n\n#: lib/logitech_receiver/settings_templates.py:1125\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key \"\n\"or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1129\nmsgid \"Off\"\nmsgstr \"Desativado\"\n\n#: lib/logitech_receiver/settings_templates.py:1160\nmsgid \"Disable keys\"\nmsgstr \"Desativar teclas\"\n\n#: lib/logitech_receiver/settings_templates.py:1161\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"Desativar teclas específicas do teclado.\"\n\n#: lib/logitech_receiver/settings_templates.py:1164\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"Desativa a tecla %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1177\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid \"Set OS\"\nmsgstr \"Definir SO\"\n\n#: lib/logitech_receiver/settings_templates.py:1178\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid \"Change keys to match OS.\"\nmsgstr \"Trocar as teclas para corresponder ao SO.\"\n\n#: lib/logitech_receiver/settings_templates.py:1247\nmsgid \"Change Host\"\nmsgstr \"Trocar Hospedeiro\"\n\n#: lib/logitech_receiver/settings_templates.py:1248\nmsgid \"Switch connection to a different host\"\nmsgstr \"Trocar a conexão para um hospedeiro diferente\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Performs a left click.\"\nmsgstr \"Executa um clique com botão esquerdo.\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Single tap\"\nmsgstr \"Toque único\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Performs a right click.\"\nmsgstr \"Executa um clique com botão direito.\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Single tap with two fingers\"\nmsgstr \"Toque único com dois dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:1274\nmsgid \"Single tap with three fingers\"\nmsgstr \"Toque único com três dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Double tap\"\nmsgstr \"Toque duplo\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Performs a double click.\"\nmsgstr \"Executa um clique duplo.\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid \"Double tap with two fingers\"\nmsgstr \"Toque duplo com dois dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Double tap with three fingers\"\nmsgstr \"Toque duplo com três dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"Deslizar itens arrastando o dedo após um toque duplo.\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Tap and drag\"\nmsgstr \"Tocar e arrastar\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"Tocar e arrastar com dois dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"Arrasta itens arrastando os dedos após um toque duplo.\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"Tocar e arrastar com três dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:1291\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"Impedir gestos de toque e borda\"\n\n#: lib/logitech_receiver/settings_templates.py:1292\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"\"\n\"Desativa os gestos de toque e borda (equivalente a apertar Fn + clique \"\n\"esquerdo).\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\nmsgid \"Scroll with one finger\"\nmsgstr \"Rolar com um dedo\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scrolls.\"\nmsgstr \"Executa a rolagem.\"\n\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scroll with two fingers\"\nmsgstr \"Rolar com dois dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"Rolar horizontalmente com dois dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scrolls horizontally.\"\nmsgstr \"Faz rolagem horizontal.\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"Rolar verticalmente com dois dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scrolls vertically.\"\nmsgstr \"Faz rolagem vertical.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"Inverte a direção de rolagem.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Natural scrolling\"\nmsgstr \"Rolagem natural\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"Ativa a roda do polegar.\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Thumbwheel\"\nmsgstr \"Roda do polegar\"\n\n#: lib/logitech_receiver/settings_templates.py:1311\n#: lib/logitech_receiver/settings_templates.py:1315\nmsgid \"Swipe from the top edge\"\nmsgstr \"Deslizar da borda superior\"\n\n#: lib/logitech_receiver/settings_templates.py:1312\nmsgid \"Swipe from the left edge\"\nmsgstr \"Deslizar da borda esquerda\"\n\n#: lib/logitech_receiver/settings_templates.py:1313\nmsgid \"Swipe from the right edge\"\nmsgstr \"Deslizar da borda direita\"\n\n#: lib/logitech_receiver/settings_templates.py:1314\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"Deslizar da borda inferior\"\n\n#: lib/logitech_receiver/settings_templates.py:1316\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"Deslizar dois dedos da borda esquerda\"\n\n#: lib/logitech_receiver/settings_templates.py:1317\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"Deslizar dois dedos da borda direita\"\n\n#: lib/logitech_receiver/settings_templates.py:1318\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"Deslizar dois dedos da borda inferior\"\n\n#: lib/logitech_receiver/settings_templates.py:1319\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"Deslizar dois dedos da borda superior\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"Aproximar os dedos para diminuir o zoom; afastá-los para aumentar.\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\nmsgid \"Zoom with two fingers.\"\nmsgstr \"Fazer zoom com dois dedos.\"\n\n#: lib/logitech_receiver/settings_templates.py:1321\nmsgid \"Pinch to zoom out.\"\nmsgstr \"Aproximar os dedos para diminuir o zoom.\"\n\n#: lib/logitech_receiver/settings_templates.py:1322\nmsgid \"Spread to zoom in.\"\nmsgstr \"Afastar os dedos para aumentar o zoom.\"\n\n#: lib/logitech_receiver/settings_templates.py:1323\nmsgid \"Zoom with three fingers.\"\nmsgstr \"Fazer zoom com três dedos.\"\n\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Zoom with two fingers\"\nmsgstr \"Fazer zoom com dois dedos\"\n\n#: lib/logitech_receiver/settings_templates.py:1342\nmsgid \"Pixel zone\"\nmsgstr \"Região de pixels\"\n\n#: lib/logitech_receiver/settings_templates.py:1343\nmsgid \"Ratio zone\"\nmsgstr \"Região de proporção\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Scale factor\"\nmsgstr \"Fator de escala\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Sets the cursor speed.\"\nmsgstr \"Define a velocidade do cursor.\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left\"\nmsgstr \"Esquerda\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left-most coordinate.\"\nmsgstr \"Coordenada do ponto mais à esquerda.\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom\"\nmsgstr \"Fundo\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom coordinate.\"\nmsgstr \"Coordenada inferior.\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width\"\nmsgstr \"Largura\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width.\"\nmsgstr \"Largura.\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height\"\nmsgstr \"Altura\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height.\"\nmsgstr \"Altura.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Cursor speed.\"\nmsgstr \"Velocidade do cursor.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Scale\"\nmsgstr \"Escala\"\n\n#: lib/logitech_receiver/settings_templates.py:1358\nmsgid \"Gestures\"\nmsgstr \"Gestos\"\n\n#: lib/logitech_receiver/settings_templates.py:1359\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"Ajustar o comportamento do mouse/touchpad.\"\n\n#: lib/logitech_receiver/settings_templates.py:1375\nmsgid \"Gestures Diversion\"\nmsgstr \"Desvio de Gesto\"\n\n#: lib/logitech_receiver/settings_templates.py:1376\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1392\nmsgid \"Gesture params\"\nmsgstr \"Parâmetros de gestos\"\n\n#: lib/logitech_receiver/settings_templates.py:1393\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"Alterar parâmetros numéricos de um mouse/touchpad.\"\n\n#: lib/logitech_receiver/settings_templates.py:1417\nmsgid \"M-Key LEDs\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1419\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1423\n#: lib/logitech_receiver/settings_templates.py:1454\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1429\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"Ilumina a tecla %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1448\nmsgid \"MR-Key LED\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1450\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1471\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1473\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"Alterar permanentemente o mapeamento da tecla ou do botão.\"\n\n#: lib/logitech_receiver/settings_templates.py:1475\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"\"\n\"Alterar teclas ou botões importantes (como o botão esquerdo do mouse) pode \"\n\"tornar o sistema inutilizável.\"\n\n#: lib/logitech_receiver/settings_templates.py:1532\nmsgid \"Sidetone\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1533\nmsgid \"Set sidetone level.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1542\nmsgid \"Equalizer\"\nmsgstr \"Equalizador\"\n\n#: lib/logitech_receiver/settings_templates.py:1543\nmsgid \"Set equalizer levels.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1565\nmsgid \"Hz\"\nmsgstr \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1571\nmsgid \"Power Management\"\nmsgstr \"Gerenciamento de energia\"\n\n#: lib/logitech_receiver/settings_templates.py:1572\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"Desligamento em minutos (0 para nunca).\"\n\n#: lib/logitech_receiver/settings_templates.py:1584\nmsgid \"Brightness Control\"\nmsgstr \"Controle de brilho\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\nmsgid \"Control overall brightness\"\nmsgstr \"Controle o brilho geral\"\n\n#: lib/logitech_receiver/settings_templates.py:1628\n#: lib/logitech_receiver/settings_templates.py:1681\nmsgid \"LED Control\"\nmsgstr \"LED Control\"\n\n#: lib/logitech_receiver/settings_templates.py:1629\n#: lib/logitech_receiver/settings_templates.py:1682\nmsgid \"Switch control of LED zones between device and Solaar\"\nmsgstr \"Controle as zonas de LED alternando entre o dispositivo e o Solaar\"\n\n#: lib/logitech_receiver/settings_templates.py:1644\n#: lib/logitech_receiver/settings_templates.py:1692\nmsgid \"LED Zone Effects\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"Set effect for LED Zone\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1647\nmsgid \"Color\"\nmsgstr \"Cor\"\n\n#: lib/logitech_receiver/settings_templates.py:1648\nmsgid \"Speed\"\nmsgstr \"Velocidade\"\n\n#: lib/logitech_receiver/settings_templates.py:1649\nmsgid \"Period\"\nmsgstr \"Período\"\n\n#: lib/logitech_receiver/settings_templates.py:1650\nmsgid \"Intensity\"\nmsgstr \"Intensity\"\n\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid \"Ramp\"\nmsgstr \"Rampa\"\n\n#: lib/logitech_receiver/settings_templates.py:1666\nmsgid \"LEDs\"\nmsgstr \"LEDs\"\n\n#: lib/logitech_receiver/settings_templates.py:1703\nmsgid \"Per-key Lighting\"\nmsgstr \"Iluminação por tecla\"\n\n#: lib/logitech_receiver/settings_templates.py:1704\nmsgid \"Control per-key lighting.\"\nmsgstr \"Control per-key lighting.\"\n\n#: lib/logitech_receiver/settings_templates.py:1786\nmsgid \"Force Sensing Buttons\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1787\nmsgid \"Change the force required to activate button.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1804\nmsgid \"Force Sensing Button\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1814\nmsgid \"Haptic Feeback Level\"\nmsgstr \"Nível de feedback háptico\"\n\n#: lib/logitech_receiver/settings_templates.py:1815\nmsgid \"Change power of haptic feedback.  (Zero to turn off.)\"\nmsgstr \"Alterar a intensidade do feedback tátil. (Zero para desligar.)\"\n\n#: lib/logitech_receiver/settings_templates.py:1857\nmsgid \"Play Haptic Waveform\"\nmsgstr \"Reproduzir forma de onda háptica\"\n\n#: lib/logitech_receiver/settings_templates.py:1858\nmsgid \"Tell device to play a haptic waveform.\"\nmsgstr \"Diga ao dispositivo para reproduzir uma forma de onda háptica.\"\n\n#: lib/solaar/ui/__init__.py:120\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"\"\n\n#: lib/solaar/ui/about/model.py:36\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"Gerencia receptores, teclados,\\n\"\n\"mouses e tablets da Logitech.\"\n\n#: lib/solaar/ui/about/model.py:63\nmsgid \"Additional Programming\"\nmsgstr \"Programação adicional\"\n\n#: lib/solaar/ui/about/model.py:64\nmsgid \"GUI design\"\nmsgstr \"Design da GUI\"\n\n#: lib/solaar/ui/about/model.py:66\nmsgid \"Testing\"\nmsgstr \"Teste\"\n\n#: lib/solaar/ui/about/model.py:74\nmsgid \"Logitech documentation\"\nmsgstr \"Documentação da Logitech\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92\n#: lib/solaar/ui/window.py:208\nmsgid \"Unpair\"\nmsgstr \"Desemparelhar\"\n\n#: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141\nmsgid \"Cancel\"\nmsgstr \"Cancelar\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Permissions error\"\nmsgstr \"Erro de permissão\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"\"\n\"Foi encontrado um receptor ou dispositivo Logitech (%s), mas não tinha \"\n\"permissão para abri-lo.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"\"\n\"Se você acabou de instalar o Solaar, tente desconectar o receptor ou \"\n\"dispositivo e, em seguida, reconectá-lo.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Cannot connect to device error\"\nmsgstr \"Erro - não foi possível conectar-se ao dispositivo\"\n\n#: lib/solaar/ui/common.py:51\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"Foi encontrado um receptor ou dispositivo Logitech em %s, mas houve um erro \"\n\"ao conectar-se a ele.\"\n\n#: lib/solaar/ui/common.py:53\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"\"\n\"Tente desconectar o dispositivo e reconectá-lo, ou desligá-lo e ligá-lo \"\n\"novamente.\"\n\n#: lib/solaar/ui/common.py:56\nmsgid \"Unpairing failed\"\nmsgstr \"Desemparelhamento falhou\"\n\n#: lib/solaar/ui/common.py:58\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"Falha ao desemparelhar %{device} do %{receiver}.\"\n\n#: lib/solaar/ui/common.py:63\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"O receptor retornou um erro, sem maiores detalhes.\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Complete - ENTER to change\"\nmsgstr \"Completo - pressione ENTER para alterar\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Incomplete\"\nmsgstr \"Incompleto\"\n\n#: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d valor\"\nmsgstr[1] \"%d valores\"\n\n#: lib/solaar/ui/config_panel.py:642\nmsgid \"Changes allowed\"\nmsgstr \"Mudanças permitidas\"\n\n#: lib/solaar/ui/config_panel.py:643\nmsgid \"No changes allowed\"\nmsgstr \"Mudanças não permitidas\"\n\n#: lib/solaar/ui/config_panel.py:644\nmsgid \"Ignore this setting\"\nmsgstr \"Ignorar esta configuração\"\n\n#: lib/solaar/ui/config_panel.py:690\nmsgid \"Working\"\nmsgstr \"Funcionando\"\n\n#: lib/solaar/ui/config_panel.py:693\nmsgid \"Read/write operation failed.\"\nmsgstr \"Operação de leitura/escrita falhou.\"\n\n#: lib/solaar/ui/desktop_notifications.py:112\nmsgid \"unspecified reason\"\nmsgstr \"razão não especificada\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"Built-in rules\"\nmsgstr \"Regras predefinidas\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"User-defined rules\"\nmsgstr \"Regras do usuário\"\n\n#: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126\nmsgid \"Rule\"\nmsgstr \"Regra\"\n\n#: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382\n#: lib/solaar/ui/diversion_rules.py:509\nmsgid \"Sub-rule\"\nmsgstr \"Sub-regra\"\n\n#: lib/solaar/ui/diversion_rules.py:108\nmsgid \"[empty]\"\nmsgstr \"[vazio]\"\n\n#: lib/solaar/ui/diversion_rules.py:132\nmsgid \"Make changes permanent?\"\nmsgstr \"Tornar as alterações permanentes?\"\n\n#: lib/solaar/ui/diversion_rules.py:137\nmsgid \"Yes\"\nmsgstr \"Sim\"\n\n#: lib/solaar/ui/diversion_rules.py:139\nmsgid \"No\"\nmsgstr \"Não\"\n\n#: lib/solaar/ui/diversion_rules.py:144\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"\"\n\"Se você escolher Não, as alterações serão perdidas quando o Solaar for \"\n\"fechado.\"\n\n#: lib/solaar/ui/diversion_rules.py:273\nmsgid \"Paste here\"\nmsgstr \"Colar aqui\"\n\n#: lib/solaar/ui/diversion_rules.py:275\nmsgid \"Paste above\"\nmsgstr \"Colar acima\"\n\n#: lib/solaar/ui/diversion_rules.py:277\nmsgid \"Paste below\"\nmsgstr \"Colar abaixo\"\n\n#: lib/solaar/ui/diversion_rules.py:283\nmsgid \"Paste rule here\"\nmsgstr \"Colar regra aqui\"\n\n#: lib/solaar/ui/diversion_rules.py:285\nmsgid \"Paste rule above\"\nmsgstr \"Colar regra acima\"\n\n#: lib/solaar/ui/diversion_rules.py:287\nmsgid \"Paste rule below\"\nmsgstr \"Colar regra abaixo\"\n\n#: lib/solaar/ui/diversion_rules.py:291\nmsgid \"Paste rule\"\nmsgstr \"Colar regra\"\n\n#: lib/solaar/ui/diversion_rules.py:306\nmsgid \"Insert here\"\nmsgstr \"Inserir aqui\"\n\n#: lib/solaar/ui/diversion_rules.py:308\nmsgid \"Insert above\"\nmsgstr \"Inserir acima\"\n\n#: lib/solaar/ui/diversion_rules.py:310\nmsgid \"Insert below\"\nmsgstr \"Inserir abaixo\"\n\n#: lib/solaar/ui/diversion_rules.py:316\nmsgid \"Insert new rule here\"\nmsgstr \"Inserir nova regra aqui\"\n\n#: lib/solaar/ui/diversion_rules.py:318\nmsgid \"Insert new rule above\"\nmsgstr \"Inserir nova regra acima\"\n\n#: lib/solaar/ui/diversion_rules.py:320\nmsgid \"Insert new rule below\"\nmsgstr \"Inserir nova regra abaixo\"\n\n#: lib/solaar/ui/diversion_rules.py:347\nmsgid \"Flatten\"\nmsgstr \"Desaninhar\"\n\n#: lib/solaar/ui/diversion_rules.py:380\nmsgid \"Insert\"\nmsgstr \"Inserir\"\n\n#: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511\n#: lib/solaar/ui/diversion_rules.py:1158\nmsgid \"Or\"\nmsgstr \"Ou\"\n\n#: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510\n#: lib/solaar/ui/diversion_rules.py:1144\nmsgid \"And\"\nmsgstr \"E\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid \"Condition\"\nmsgstr \"Condição\"\n\n#: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154\nmsgid \"Feature\"\nmsgstr \"Feature\"\n\n#: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188\nmsgid \"Report\"\nmsgstr \"Report\"\n\n#: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69\nmsgid \"Process\"\nmsgstr \"Processo\"\n\n#: lib/solaar/ui/diversion_rules.py:391\nmsgid \"Mouse process\"\nmsgstr \"Processo do mouse\"\n\n#: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225\nmsgid \"Modifiers\"\nmsgstr \"Teclas modificadoras\"\n\n#: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277\nmsgid \"Key\"\nmsgstr \"Tecla\"\n\n#: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318\nmsgid \"KeyIsDown\"\nmsgstr \"Tecla Pressionada\"\n\n#: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432\nmsgid \"Active\"\nmsgstr \"Ativo\"\n\n#: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390\n#: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487\nmsgid \"Device\"\nmsgstr \"Dispositivo\"\n\n#: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467\nmsgid \"Host\"\nmsgstr \"Host\"\n\n#: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506\nmsgid \"Setting\"\nmsgstr \"Configuração\"\n\n#: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333\n#: lib/solaar/ui/rule_conditions.py:382\nmsgid \"Test\"\nmsgstr \"Teste\"\n\n#: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507\nmsgid \"Test bytes\"\nmsgstr \"Bytes de teste\"\n\n#: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608\nmsgid \"Mouse Gesture\"\nmsgstr \"Gesto do mouse\"\n\n#: lib/solaar/ui/diversion_rules.py:405\nmsgid \"Action\"\nmsgstr \"Ação\"\n\n#: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138\nmsgid \"Key press\"\nmsgstr \"Pressionamento de tecla\"\n\n#: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191\nmsgid \"Mouse scroll\"\nmsgstr \"Rolagem do mouse\"\n\n#: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256\nmsgid \"Mouse click\"\nmsgstr \"Clique do mouse\"\n\n#: lib/solaar/ui/diversion_rules.py:410\nmsgid \"Set\"\nmsgstr \"Definir\"\n\n#: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328\nmsgid \"Execute\"\nmsgstr \"Executar\"\n\n#: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189\nmsgid \"Later\"\nmsgstr \"Mais tarde\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid \"Insert new rule\"\nmsgstr \"Inserir nova regra\"\n\n#: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82\n#: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556\nmsgid \"Delete\"\nmsgstr \"Apagar\"\n\n#: lib/solaar/ui/diversion_rules.py:483\nmsgid \"Negate\"\nmsgstr \"Negar\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid \"Wrap with\"\nmsgstr \"Envolver com\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid \"Cut\"\nmsgstr \"Recortar\"\n\n#: lib/solaar/ui/diversion_rules.py:553\nmsgid \"Paste\"\nmsgstr \"Colar\"\n\n#: lib/solaar/ui/diversion_rules.py:559\nmsgid \"Copy\"\nmsgstr \"Copiar\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Editor de Regras do Solaar\"\n\n#: lib/solaar/ui/diversion_rules.py:668\nmsgid \"Save changes\"\nmsgstr \"Salvar alterações\"\n\n#: lib/solaar/ui/diversion_rules.py:673\nmsgid \"Discard changes\"\nmsgstr \"Descartar alterações\"\n\n#: lib/solaar/ui/diversion_rules.py:1104\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"Este editor ainda não suporta o componente de regra selecionado.\"\n\n#: lib/solaar/ui/diversion_rules.py:1169\nmsgid \"\"\n\"Number of seconds to delay.  Delay between 0 and 1 is done with higher \"\n\"precision.\"\nmsgstr \"\"\n\"Número de segundos de atraso. Atrasos entre 0 e 1 são calculados com maior \"\n\"precisão.\"\n\n#: lib/solaar/ui/diversion_rules.py:1207\nmsgid \"Not\"\nmsgstr \"Não\"\n\n#: lib/solaar/ui/diversion_rules.py:1238\nmsgid \"Toggle\"\nmsgstr \"Alternar\"\n\n#: lib/solaar/ui/diversion_rules.py:1239\nmsgid \"True\"\nmsgstr \"Verdadeiro\"\n\n#: lib/solaar/ui/diversion_rules.py:1240\nmsgid \"False\"\nmsgstr \"Falso\"\n\n#: lib/solaar/ui/diversion_rules.py:1253\nmsgid \"Unsupported setting\"\nmsgstr \"Configuração não suportada\"\n\n#: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415\n#: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748\n#: lib/solaar/ui/diversion_rules.py:1766\nmsgid \"Originating device\"\nmsgstr \"Dispositivo de origem\"\n\n#: lib/solaar/ui/diversion_rules.py:1428\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"O dispositivo está ativo e suas configurações podem ser alteradas.\"\n\n#: lib/solaar/ui/diversion_rules.py:1437\nmsgid \"Device that originated the current notification.\"\nmsgstr \"Dispositivo que originou a notificação atual.\"\n\n#: lib/solaar/ui/diversion_rules.py:1450\nmsgid \"Name of host computer.\"\nmsgstr \"Name of host computer.\"\n\n#: lib/solaar/ui/diversion_rules.py:1520\nmsgid \"Value\"\nmsgstr \"Valor\"\n\n#: lib/solaar/ui/diversion_rules.py:1529\nmsgid \"Item\"\nmsgstr \"Item\"\n\n#: lib/solaar/ui/diversion_rules.py:1808\nmsgid \"Change setting on device\"\nmsgstr \"Alterar configuração no dispositivo\"\n\n#: lib/solaar/ui/diversion_rules.py:1824\nmsgid \"Setting on device\"\nmsgstr \"Configuração no dispositivo\"\n\n#: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: new dispositivo emparelhado\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Os receptores Bolt são compatíveis apenas com dispositivos Bolt.\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"\"\n\"Pressione o botão ou tecla de emparelhamento até que a luz de emparelhamento \"\n\"pisque rapidamente.\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"\"\n\"Os receptores Unifying são compatíveis apenas com dispositivos Unifying.\"\n\n#: lib/solaar/ui/pair_window.py:53\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"Outros receptores são compatíveis apenas com alguns dispositivos.\"\n\n#: lib/solaar/ui/pair_window.py:55\nmsgid \"For most devices, turn on the device you want to pair.\"\nmsgstr \"\"\n\"Para a maioria dos dispositivos, ligue o dispositivo que deseja emparelhar.\"\n\n#: lib/solaar/ui/pair_window.py:56\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"Se o dispositivo já estiver ligado, desligue-o e ligue-o novamente.\"\n\n#: lib/solaar/ui/pair_window.py:58\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"\"\n\"O dispositivo não deve estar emparelhado com um receptor ligado nas \"\n\"proximidades.\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid \"\"\n\"For devices with multiple channels, press, hold, and release the button for \"\n\"the channel you wish to pair\\n\"\n\"or use the channel switch button to select a channel and then press, hold, \"\n\"and release the channel switch button.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/pair_window.py:68\nmsgid \"The channel indicator light should be blinking rapidly.\"\nmsgstr \"A luz indicadora do canal deve estar piscando rapidamente.\"\n\n#: lib/solaar/ui/pair_window.py:72\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"Este dispositivo tem %d pareamento disponível.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"Este dispositivo tem %d pareamentos disponíveis.\"\n\n#: lib/solaar/ui/pair_window.py:78\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"Cancelar neste ponto não usará um pareamento.\"\n\n#: lib/solaar/ui/pair_window.py:168\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"Digite a senha em %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:171\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"Digite %(passcode)s e então pressione a tecla Enter.\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"left\"\nmsgstr \"esquerda\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"right\"\nmsgstr \"direita\"\n\n#: lib/solaar/ui/pair_window.py:178\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"Pressione %(code)s\\n\"\n\"e em seguida, pressione os botões esquerdo e direito simultaneamente.\"\n\n#: lib/solaar/ui/pair_window.py:221\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"A conexão sem fio não é criptografada\"\n\n#: lib/solaar/ui/pair_window.py:226\nmsgid \"Found a new device:\"\nmsgstr \"Encontrado um novo dispositivo:\"\n\n#: lib/solaar/ui/pair_window.py:247\nmsgid \"Pairing failed\"\nmsgstr \"Emparelhamento falhou\"\n\n#: lib/solaar/ui/pair_window.py:249\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"\"\n\"Certifique-se de que o seu dispositivo esteja dentro do alcance e, que \"\n\"possui bateria com carga aceitável.\"\n\n#: lib/solaar/ui/pair_window.py:251\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"\"\n\"Um novo dispositivo foi detectado, mas não é compatível com este receptor.\"\n\n#: lib/solaar/ui/pair_window.py:253\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"Há mais dispositivos pareados do que o receptor suporta.\"\n\n#: lib/solaar/ui/pair_window.py:255\nmsgid \"No further details are available about the error.\"\nmsgstr \"Sem maiores detalhes sobre o erro.\"\n\n#: lib/solaar/ui/rule_actions.py:54\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simule um clique, pressionamento ou liberação de tecla em conjunto.\\n\"\n\"No Wayland, requer acesso de gravação a /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:60\nmsgid \"Add key\"\nmsgstr \"Adicionar tecla\"\n\n#: lib/solaar/ui/rule_actions.py:63\nmsgid \"Click\"\nmsgstr \"Clique\"\n\n#: lib/solaar/ui/rule_actions.py:66\nmsgid \"Depress\"\nmsgstr \"Pressionar\"\n\n#: lib/solaar/ui/rule_actions.py:69\nmsgid \"Release\"\nmsgstr \"Liberar\"\n\n#: lib/solaar/ui/rule_actions.py:153\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simule a rolagem do mouse.\\n\"\n\"Em Wayland, é necessário ter acesso de escrita a /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:211\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simule o clique do mouse.\\r\\n\"\n\"Em Wayland, é necessário ter acesso de escrita a /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:216\nmsgid \"Button\"\nmsgstr \"Botão\"\n\n#: lib/solaar/ui/rule_actions.py:218\nmsgid \"Action (and Count, if click)\"\nmsgstr \"Ação (e contagem, se houver clique)\"\n\n#: lib/solaar/ui/rule_actions.py:269\nmsgid \"Execute a command with arguments.\"\nmsgstr \"Executar um comando com argumentos.\"\n\n#: lib/solaar/ui/rule_actions.py:273\nmsgid \"Add argument\"\nmsgstr \"Adicionar argumento\"\n\n#: lib/solaar/ui/rule_conditions.py:52\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"Processo ativo do X11. Para uso exclusivo no X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:82\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"Processo de mouse X11. Para uso exclusivo no X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:99\nmsgid \"MouseProcess\"\nmsgstr \"Processo (mouse)\"\n\n#: lib/solaar/ui/rule_conditions.py:123\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/rule_conditions.py:169\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/rule_conditions.py:201\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/rule_conditions.py:241\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/rule_conditions.py:250\nmsgid \"Key down\"\nmsgstr \"Tecla pressionada\"\n\n#: lib/solaar/ui/rule_conditions.py:253\nmsgid \"Key up\"\nmsgstr \"Tecla liberada\"\n\n#: lib/solaar/ui/rule_conditions.py:293\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/rule_conditions.py:331\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/rule_conditions.py:335\nmsgid \"Parameter\"\nmsgstr \"Parâmetro\"\n\n#: lib/solaar/ui/rule_conditions.py:408\nmsgid \"begin (inclusive)\"\nmsgstr \"início (inclusivo)\"\n\n#: lib/solaar/ui/rule_conditions.py:409\nmsgid \"end (exclusive)\"\nmsgstr \"fim (exclusivo)\"\n\n#: lib/solaar/ui/rule_conditions.py:417\nmsgid \"range\"\nmsgstr \"faixa\"\n\n#: lib/solaar/ui/rule_conditions.py:420\nmsgid \"minimum\"\nmsgstr \"mínimo\"\n\n#: lib/solaar/ui/rule_conditions.py:421\nmsgid \"maximum\"\nmsgstr \"máximo\"\n\n#: lib/solaar/ui/rule_conditions.py:423\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"\"\n\n#: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427\nmsgid \"mask\"\nmsgstr \"máscara\"\n\n#: lib/solaar/ui/rule_conditions.py:428\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"\"\n\n#: lib/solaar/ui/rule_conditions.py:437\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/rule_conditions.py:447\nmsgid \"type\"\nmsgstr \"tipo\"\n\n#: lib/solaar/ui/rule_conditions.py:535\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"\"\n\"Gesto do mouse com botão iniciador opcional, seguido por zero ou mais \"\n\"movimentos do mouse.\"\n\n#: lib/solaar/ui/rule_conditions.py:541\nmsgid \"Add movement\"\nmsgstr \"Adicionar movimento\"\n\n#: lib/solaar/ui/tray.py:55\nmsgid \"No supported device found\"\nmsgstr \"Nenhum dispositivo suportado encontrado\"\n\n#: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328\n#, python-format\nmsgid \"About %s\"\nmsgstr \"Sobre o %s\"\n\n#: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"Sair do %s\"\n\n#: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281\nmsgid \"no receiver\"\nmsgstr \"nenhum receptor\"\n\n#: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299\n#: lib/solaar/ui/window.py:728\nmsgid \"offline\"\nmsgstr \"offline\"\n\n#: lib/solaar/ui/tray.py:297\nmsgid \"no status\"\nmsgstr \"sem status\"\n\n#: lib/solaar/ui/window.py:110\nmsgid \"Scanning\"\nmsgstr \"Procurando\"\n\n#: lib/solaar/ui/window.py:141\nmsgid \"Battery\"\nmsgstr \"Bateria\"\n\n#: lib/solaar/ui/window.py:144\nmsgid \"Wireless Link\"\nmsgstr \"Conexão sem fio\"\n\n#: lib/solaar/ui/window.py:148\nmsgid \"Lighting\"\nmsgstr \"Iluminação\"\n\n#: lib/solaar/ui/window.py:182\nmsgid \"Show Technical Details\"\nmsgstr \"Mostrar detalhes técnicos\"\n\n#: lib/solaar/ui/window.py:198\nmsgid \"Pair new device\"\nmsgstr \"Emparelhar novo dispositivo\"\n\n#: lib/solaar/ui/window.py:216\nmsgid \"Select a device\"\nmsgstr \"Selecione um dispositivo\"\n\n#: lib/solaar/ui/window.py:331\nmsgid \"Rule Editor\"\nmsgstr \"Editor de regras\"\n\n#: lib/solaar/ui/window.py:522\nmsgid \"Path\"\nmsgstr \"Caminho\"\n\n#: lib/solaar/ui/window.py:524\nmsgid \"USB ID\"\nmsgstr \"ID USB\"\n\n#: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529\n#: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546\nmsgid \"Serial\"\nmsgstr \"Número de série\"\n\n#: lib/solaar/ui/window.py:533\nmsgid \"Index\"\nmsgstr \"Índice\"\n\n#: lib/solaar/ui/window.py:535\nmsgid \"Wireless PID\"\nmsgstr \"PID sem fio\"\n\n#: lib/solaar/ui/window.py:537\nmsgid \"Product ID\"\nmsgstr \"ID do produto\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Protocol\"\nmsgstr \"Protocolo\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Unknown\"\nmsgstr \"Desconhecido\"\n\n#: lib/solaar/ui/window.py:541\nmsgid \"Polling rate\"\nmsgstr \"Taxa de sondagem\"\n\n#: lib/solaar/ui/window.py:548\nmsgid \"Unit ID\"\nmsgstr \"Unit ID\"\n\n#: lib/solaar/ui/window.py:559\nmsgid \"none\"\nmsgstr \"nenhum\"\n\n#: lib/solaar/ui/window.py:560\nmsgid \"Notifications\"\nmsgstr \"Notificações\"\n\n#: lib/solaar/ui/window.py:604\nmsgid \"No device paired.\"\nmsgstr \"Nenhum dispositivo emparelhado.\"\n\n#: lib/solaar/ui/window.py:613\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"Até %(max_count)s dispositivo pode ser emparelhado neste receptor.\"\nmsgstr[1] \"\"\n\"Até %(max_count)s dispositivos podem ser emparelhados neste receptor.\"\n\n#: lib/solaar/ui/window.py:620\nmsgid \"Only one device can be paired to this receiver.\"\nmsgstr \"Apenas um dispositivo pode ser emparelhado neste receptor.\"\n\n#: lib/solaar/ui/window.py:624\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"Este dispositivo tem %d pareamento disponível.\"\nmsgstr[1] \"Este dispositivo tem %d pareamentos disponíveis.\"\n\n#: lib/solaar/ui/window.py:681\nmsgid \"Battery Voltage\"\nmsgstr \"Tensão da Bateria\"\n\n#: lib/solaar/ui/window.py:683\nmsgid \"Voltage reported by battery\"\nmsgstr \"Tensão informada pela bateria\"\n\n#: lib/solaar/ui/window.py:685\nmsgid \"Battery Level\"\nmsgstr \"Nível de bateria\"\n\n#: lib/solaar/ui/window.py:687\nmsgid \"Approximate level reported by battery\"\nmsgstr \"Nível aproximado informado pela bateria\"\n\n#: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696\nmsgid \"next reported \"\nmsgstr \"próximo valor informado: \"\n\n#: lib/solaar/ui/window.py:697\nmsgid \" and next level to be reported.\"\nmsgstr \" e o próximo nível que será informado.\"\n\n#: lib/solaar/ui/window.py:702\nmsgid \"last known\"\nmsgstr \"último conhecido\"\n\n#: lib/solaar/ui/window.py:713\nmsgid \"encrypted\"\nmsgstr \"criptografada\"\n\n#: lib/solaar/ui/window.py:715\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"A conexão sem fio entre o dispositivo e seu receptor é criptografada.\"\n\n#: lib/solaar/ui/window.py:717\nmsgid \"not encrypted\"\nmsgstr \"não criptografada\"\n\n#: lib/solaar/ui/window.py:721\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"A conexão sem fio entre este dispositivo e o seu receptor não está \"\n\"criptografada.\\n\"\n\"Isso representa um problema de segurança para dispositivos apontadores e um \"\n\"problema de segurança grave para dispositivos de entrada de texto.\"\n\n#: lib/solaar/ui/window.py:737\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d lux\"\n\n#~ msgid \" paired devices.\"\n#~ msgstr \" dispositivos emparelhados.\"\n\n#~ msgid \"%(battery_level)s\"\n#~ msgstr \"%(battery_level)s\"\n\n#~ msgid \"%(battery_percent)d%%\"\n#~ msgstr \"%(battery_percent)d%%\"\n\n#, python-format\n#~ msgid \"%(rate)d ms (%(rate_hz)dHz)\"\n#~ msgstr \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#~ msgid \"1 paired device.\"\n#~ msgstr \"1 dispositivo emparelhado.\"\n\n#~ msgid \"Add action\"\n#~ msgstr \"Adicionar ação\"\n\n#~ msgid \"\"\n#~ \"Adjust the DPI by sliding the mouse horizontally while holding the DPI \"\n#~ \"button.\"\n#~ msgstr \"\"\n#~ \"Ajustar o DPI deslizando o mouse horizontalmente ao segurar o botão DPI.\"\n\n#~ msgid \"\"\n#~ \"Adjust the DPI by sliding the mouse horizontally while holding the button \"\n#~ \"down.\"\n#~ msgstr \"Ajustar DPI deslizando o mouse horizontalmente ao segurar o botão.\"\n\n#~ msgid \"\"\n#~ \"Automatically switch the mouse wheel between ratchet and freespin mode.\\n\"\n#~ \"The mouse wheel is always free at 0, and always locked at 50\"\n#~ msgstr \"\"\n#~ \"Automaticamente alterna a roda do mouse entre modo catraca e modo livre.\\n\"\n#~ \"A roda do mouse está sempre live em 0, e sempre em modo catraca em 50\"\n\n#~ msgid \"\"\n#~ \"Automatically switch the mouse wheel between ratchet and freespin mode.\\n\"\n#~ \"The mouse wheel is always free at 0, and always ratcheted at 50\"\n#~ msgstr \"\"\n#~ \"Alternar automaticamente a roda do mouse entre o modo de catraca e o modo \"\n#~ \"de rotação livre.\\n\"\n#~ \"A roda do mouse fica sempre livre no valor 0, e sempre no modo catraca no \"\n#~ \"valor 50\"\n\n#~ msgid \"Battery information unknown.\"\n#~ msgstr \"A informação sobre a bateria é desconhecida.\"\n\n#, python-format\n#~ msgid \"Battery: %(level)s\"\n#~ msgstr \"Bateria: %(level)s\"\n\n#, python-format\n#~ msgid \"Battery: %(percent)d%%\"\n#~ msgstr \"Bateria: %(percent)d%%\"\n\n#~ msgid \"Count\"\n#~ msgstr \"Número\"\n\n#~ msgid \"DPI Sliding Adjustment\"\n#~ msgstr \"Ajuste de DPI por deslizamento\"\n\n#~ msgid \"DPI Sliding Ajustment\"\n#~ msgstr \"Ajuste de DPI por deslizamento\"\n\n#~ msgid \"Divert G Keys\"\n#~ msgstr \"Desviar teclas G\"\n\n#~ msgid \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr \"Na prática, desativa a rolagem com o polegar no Linux.\"\n\n#~ msgid \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr \"Na prática, desativa a rolagem com a roda no Linux.\"\n\n#~ msgid \"\"\n#~ \"For more information see the Solaar installation directions\\n\"\n#~ \"at https://pwr-solaar.github.io/Solaar/installation\"\n#~ msgstr \"\"\n#~ \"Para mais informações, consulte as instruções de instalação do Solaar\\n\"\n#~ \"em https://pwr-solaar.github.io/Solaar/installation\"\n\n#, python-format\n#~ msgid \"\"\n#~ \"Found a Logitech Receiver (%s), but did not have permission to open it.\"\n#~ msgstr \"\"\n#~ \"Foi encontrado um Receptor da Logitech (%s), mas sem permissão para abri-\"\n#~ \"lo.\"\n\n#~ msgid \"Found a new device\"\n#~ msgstr \"Novo dispositivo encontrado\"\n\n#~ msgid \"Frequency of device polling, in milliseconds\"\n#~ msgstr \"Frequência de sondagem, em milissegundos\"\n\n#~ msgid \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr \"Modo HID++ para a rolagem horizontal com o polegar.\"\n\n#~ msgid \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr \"Modo HID++ para a rolagem vertical com a roda.\"\n\n#~ msgid \"High Resolution Wheel Invert\"\n#~ msgstr \"Roda Invertida de Alta Resolução\"\n\n#~ msgid \"High-sensitivity wheel invert mode for vertical scroll.\"\n#~ msgstr \"Roda invertida de alta sensibilidade para rolagem vertical.\"\n\n#~ msgid \"\"\n#~ \"If the device is already turned on,\\n\"\n#~ \"turn if off and on again.\"\n#~ msgstr \"\"\n#~ \"Se o dispositivo já encontra-se ligado,\\n\"\n#~ \"desligue-o e ligue-o novamente.\"\n\n#~ msgid \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr \"Se o dispositivo já estiver ligado, desligue-o e ligue-o novamente.\"\n\n#~ msgid \"\"\n#~ \"If you've just installed Solaar, try removing the receiver and plugging \"\n#~ \"it back in.\"\n#~ msgstr \"\"\n#~ \"Se você acabou de instalar o Solaar, tente retirar o receptor e conectá-\"\n#~ \"lo novamente.\"\n\n#, python-format\n#~ msgid \"Lighting: %(level)s lux\"\n#~ msgstr \"Iluminação: %(level)s lux\"\n\n#~ msgid \"\"\n#~ \"Make G keys send GKEY HID++ notifications (which trigger Solaar rules but \"\n#~ \"are otherwise ignored).\"\n#~ msgstr \"\"\n#~ \"Fazer as teclas G enviarem notificações HID++ GKEY (que desencadeiam \"\n#~ \"regras do Solaar, mas são ignoradas fora disso).\"\n\n#~ msgid \"\"\n#~ \"Make the key or button send HID++ notifications (which trigger Solaar \"\n#~ \"rules but are otherwise ignored).\"\n#~ msgstr \"\"\n#~ \"Fazer as teclas ou botões enviarem notificações HID++ (que desencadeiam \"\n#~ \"regras do Solaar, mas são ignoradas fora disso).\"\n\n#~ msgid \"No Logitech receiver found\"\n#~ msgstr \"Nenhum receptor da Logitech encontrado\"\n\n#~ msgid \"No device paired\"\n#~ msgstr \"Nenhum dispositivo emparelhado\"\n\n#~ msgid \"Only one device can be paired to this receiver\"\n#~ msgstr \"Apenas um dispositivo pode ser emparelhado com este receptor\"\n\n#~ msgid \"Polling Rate (ms)\"\n#~ msgstr \"Taxa de Sondagem (ms)\"\n\n#~ msgid \"Scroll Wheel HID++ Scrolling\"\n#~ msgstr \"Rolagem com a roda usando HID++\"\n\n#~ msgid \"Scroll Wheel Rachet\"\n#~ msgstr \"Rolagem no modo catraca\"\n\n#~ msgid \"Send a gesture by sliding the mouse while holding the button down.\"\n#~ msgstr \"Enviar um gesto deslizando o mouse ao segurar o botão.\"\n\n#~ msgid \"\"\n#~ \"Shows status of devices connected\\n\"\n#~ \"through wireless Logitech receivers.\"\n#~ msgstr \"\"\n#~ \"Mostra o status dos dispositivos conectados\\n\"\n#~ \"através de receptores sem fio da Logitech.\"\n\n#~ msgid \"Smooth Scrolling\"\n#~ msgstr \"Rolagem suave\"\n\n#~ msgid \"Solaar depends on a udev file that is not present\"\n#~ msgstr \"Solaar depende de um arquivo udev que não está presente.\"\n\n#~ msgid \"The receiver only supports %d paired device(s).\"\n#~ msgstr \"O receptor só suporta %d dispositivo(s) emparelhado(s)\"\n\n#~ msgid \"The receiver was unplugged.\"\n#~ msgstr \"O receptor foi desplugado.\"\n\n#~ msgid \"\"\n#~ \"The wireless link between this device and its receiver is not encrypted.\\n\"\n#~ \"\\n\"\n#~ \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~ \"security issue.\\n\"\n#~ \"\\n\"\n#~ \"It is, however, a major security issue for text-input devices (keyboards, \"\n#~ \"numpads),\\n\"\n#~ \"because typed text can be sniffed inconspicuously by 3rd parties within \"\n#~ \"range.\"\n#~ msgstr \"\"\n#~ \"A conexão sem fio entre o dispositivo e seu receptor não é \"\n#~ \"criptografada.\\n\"\n#~ \"\\n\"\n#~ \"Para dispositivos de apontamento (mouses, trackballs, trackpads), isto \"\n#~ \"não representa um grande problema de segurança.\\n\"\n#~ \"\\n\"\n#~ \"No entanto, é um grande problema de segurança para dispositivos de \"\n#~ \"entrada de texto (teclados, teclados numéricos), pois\\n\"\n#~ \"o texto digitado pode ser capturado, de forma indetectável, por terceiros \"\n#~ \"que estejam dentro do alcance.\"\n\n#~ msgid \"Thumb Wheel HID++ Scrolling\"\n#~ msgstr \"Rolagem com o polegar usando HID++\"\n\n#~ msgid \"Top-most coordinate.\"\n#~ msgstr \"Coordenada do ponto mais acima.\"\n\n#~ msgid \"Triple tap\"\n#~ msgstr \"Toque triplo\"\n\n#~ msgid \"\"\n#~ \"Try removing the device and plugging it back in or turning it off and \"\n#~ \"then on.\"\n#~ msgstr \"\"\n#~ \"Tente remover o dispositivo e conectá-lo novamente, ou desligá-lo e ligá-\"\n#~ \"lo.\"\n\n#~ msgid \"Turn illumination on or off on keyboard.\"\n#~ msgstr \"Ativar ou desativar a iluminação do teclado.\"\n\n#~ msgid \"Turn on the device you want to pair.\"\n#~ msgstr \"Ligue o dispositivo que você quer emparelhar.\"\n\n#~ msgid \"USB id\"\n#~ msgstr \"ID do USB\"\n\n#~ msgid \"Up to %d devices can be paired to this receiver\"\n#~ msgstr \"Até %d dispositivos podem ser emparelhados com este receptor\"\n\n#~ msgid \"Wheel Resolution\"\n#~ msgstr \"Resolução da Roda\"\n\n#~ msgid \"closed\"\n#~ msgstr \"fechado\"\n\n#~ msgid \"height\"\n#~ msgstr \"altura\"\n\n#~ msgid \"lux\"\n#~ msgstr \"lux\"\n\n#~ msgid \"open\"\n#~ msgstr \"aberto\"\n\n#~ msgid \"pair new device\"\n#~ msgstr \"emparelhar novo dispositivo\"\n\n#~ msgid \"paired devices\"\n#~ msgstr \"dispositivos emparelhados\"\n\n#~ msgid \"pairing lock is \"\n#~ msgstr \"trava de emparelhamento está \"\n\n#~ msgid \"top\"\n#~ msgstr \"topo\"\n\n#~ msgid \"unknown\"\n#~ msgstr \"desconhecida\"\n\n#~ msgid \"width\"\n#~ msgstr \"largura\"\n"
  },
  {
    "path": "po/ro.po",
    "content": "# Romanian translations for solaar package.\n# Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2013.\n#\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 0.9.1\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n        \"PO-Revision-Date: 2013-07-17 20:27+0100\\n\"\n        \"Last-Translator: Daniel Pavel <daniel.pavel@gmail.com>\\n\"\n        \"Language-Team: none\\n\"\n        \"Language: ro\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && \"\n        \"n%100 < 20)) ? 1 : 2;\\n\"\n        \"X-Generator: Poedit 1.5.4\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid   \"Bolt Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid   \"Unifying Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid   \"Nano Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"empty\"\nmsgstr  \"descărcată\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"critical\"\nmsgstr  \"aproape descărcată\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"low\"\nmsgstr  \"joasă\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"average\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid   \"good\"\nmsgstr  \"bună\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"full\"\nmsgstr  \"plină\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"discharging\"\nmsgstr  \"în descarcare\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"recharging\"\nmsgstr  \"re-încărcare\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid   \"charging\"\nmsgstr  \"se încarcă\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"not charging\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"almost full\"\nmsgstr  \"aproape plină\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"charged\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"slow recharge\"\nmsgstr  \"încarcare inceată\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"invalid battery\"\nmsgstr  \"baterie necorespunzătoare\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"thermal error\"\nmsgstr  \"eroare termică\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"error\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid   \"standard\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"fast\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid   \"device timeout\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid   \"device not supported\"\nmsgstr  \"periferic incompatibil\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"too many devices\"\nmsgstr  \"prea multe periferice\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"sequence timeout\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid   \"Firmware\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Bootloader\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Hardware\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Other\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Smart Shift\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"DPI Switch\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Left Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Right Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Left Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Right Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"Mouse Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid   \"pressed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid   \"released\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid   \"connected\"\nmsgstr  \"conectat(ă)\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid   \"disconnected\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid   \"unpaired\"\nmsgstr  \"deconectat(ă)\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid   \"powered on\"\nmsgstr  \"a pornit\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid   \"register\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid   \"feature\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid   \"Swap Fx function\"\nmsgstr  \"Inversează funcțiile Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"Când este activ, tastele F1..F12 vor opera funcțiile speciale,\\n\"\n        \"și trebuie să țineți apăsată tasta FN pentru a folosi funcțiile lor \"\n        \"standard.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"Când nu este activ, tastele F1..F12 vor opera functiile standard,\\n\"\n        \"și trebuie să țineți apăsată tasta FN pentru a folosi funcțiile lor \"\n        \"speciale.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid   \"Hand Detection\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"Senzitivitate crescută la derularea verticală cu rotița.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid   \"Side Scrolling\"\nmsgstr  \"Derulare orizontală\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid   \"Backlight\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid   \"Turn illumination on or off on keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid   \"Onboard Profiles\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid   \"Enable onboard profiles, which often control report rate and \"\n        \"keyboard lighting\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid   \"Polling Rate (ms)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid   \"Frequency of device polling, in milliseconds\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid   \"Divert crown events\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid   \"Divert G Keys\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid   \"Make G keys send GKEY HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid   \"May also make M keys and MR key send HID++ notifications\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Freespinning\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid   \"Key/Button Actions\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Diverted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid   \"Mouse Gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Regular\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid   \"Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"Sentivitivate (PPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid   \"Off\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid   \"Disable keys\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid   \"Set OS\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid   \"Change Host\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Performs a left click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Single tap\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Performs a right click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Double tap\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Performs a double click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Tap and drag\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid   \"Scroll with one finger\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scrolls.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Natural scrolling\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Thumbwheel\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid   \"Pixel zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid   \"Ratio zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Scale factor\"\nmsgstr  \"Factor de scalare\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width\"\nmsgstr  \"Lățime\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height\"\nmsgstr  \"Înălțime\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Cursor speed.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Scale\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid   \"Gestures\"\nmsgstr  \"Gesturi\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid   \"Gestures Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid   \"Gesture params\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid   \"M-Key LEDs\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid   \"MR-Key LED\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Sidetone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid   \"Set sidetone level.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid   \"Equalizer\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid   \"Hz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid   \"Power Management\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid   \"No paired devices.\"\nmsgstr  \"Nici un periferic contectat.\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\nmsgstr[2]       \"\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid   \"Battery: %(level)s\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid   \"Battery: %(percent)d%%\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid   \"Lighting: %(level)s lux\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid   \"Permissions error\"\nmsgstr  \"Eroare de permisiuni\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid   \"Unpairing failed\"\nmsgstr  \"Deconectare eșuată\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"Deconectarea %{device} de la %{receiver} a eșuat.\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"Receptorul a semnalat o eroare, fără alte detalii.\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:44\nmsgid   \"Additional Programming\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about.py:45\nmsgid   \"GUI design\"\nmsgstr  \"Interfață grafica\"\n\n#: lib/solaar/ui/about.py:47\nmsgid   \"Testing\"\nmsgstr  \"Testare\"\n\n#: lib/solaar/ui/about.py:54\nmsgid   \"Logitech documentation\"\nmsgstr  \"Documentație Logitech\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid   \"Unpair\"\nmsgstr  \"Deconectează\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid   \"Cancel\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Incomplete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\nmsgstr[2]       \"\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid   \"Changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid   \"No changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid   \"Ignore this setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid   \"Working\"\nmsgstr  \"Prelucrez\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"Operațiunea a eșuat.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"Built-in rules\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"User-defined rules\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid   \"Rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid   \"Sub-rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid   \"[empty]\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Make changes permanent?\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid   \"Yes\"\nmsgstr  \"Da\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid   \"No\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid   \"Save changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid   \"Discard changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid   \"Insert here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid   \"Insert above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid   \"Insert below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid   \"Insert new rule here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid   \"Insert new rule above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Insert new rule below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid   \"Paste here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid   \"Paste above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid   \"Paste below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid   \"Paste rule here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid   \"Paste rule above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Paste rule below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid   \"Paste rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid   \"Flatten\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Insert\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Or\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid   \"And\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid   \"Condition\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid   \"Feature\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid   \"Report\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid   \"Process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid   \"Mouse process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid   \"Modifiers\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid   \"Key\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid   \"KeyIsDown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid   \"Active\"\nmsgstr  \"Activ\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid   \"Device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid   \"Setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid   \"Test\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid   \"Test bytes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid   \"Mouse Gesture\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid   \"Action\"\nmsgstr  \"Acțiune\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid   \"Key press\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid   \"Mouse scroll\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid   \"Mouse click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Set\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid   \"Execute\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Later\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Insert new rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid   \"Delete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid   \"Negate\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid   \"Wrap with\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid   \"Cut\"\nmsgstr  \"Taie\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid   \"Paste\"\nmsgstr  \"Lipește\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid   \"Copy\"\nmsgstr  \"Copiază\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid   \"Number of seconds to delay.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid   \"Not\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid   \"MouseProcess\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid   \"Key down\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid   \"Key up\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid   \"Parameter\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid   \"begin (inclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid   \"end (exclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid   \"range\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid   \"minimum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid   \"maximum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid   \"mask\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid   \"type\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid   \"Add movement\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid   \"Add key\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid   \"Click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid   \"Depress\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid   \"Release\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid   \"Button\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid   \"Count and Action\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid   \"Add argument\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"Toggle\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"True\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid   \"False\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid   \"Unsupported setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid   \"Originating device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid   \"Name of host computer.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid   \"Value\"\nmsgstr  \"Valoare\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid   \"Item\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid   \"Change setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid   \"Setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid   \"offline\"\nmsgstr  \"inactivă\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"left\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"right\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid   \"Pairing failed\"\nmsgstr  \"Conectare eșuată\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"Asigurați-vă că dispozitivul este în apropiere, iar bateria este \"\n        \"încarcată.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"A fost detectat un nou periferic, dar nu este compatibil cu acest \"\n        \"receptor.\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"Alte detalii despre eroare nu sunt disponibile.\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid   \"Found a new device:\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"Legătura fără fir nu este criptată\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid   \"You may have to first turn the device off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid   \"Turn on the device you want to pair.\"\nmsgstr  \"Porniți dispozitivul pe care doriți să-l conectați.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\nmsgstr[2]       \"\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid   \"No supported device found\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"Despre %s\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"Ieșire %s\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid   \"no receiver\"\nmsgstr  \"nici un receptor\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid   \"no status\"\nmsgstr  \"stare necunoscută\"\n\n#: lib/solaar/ui/window.py:96\nmsgid   \"Scanning\"\nmsgstr  \"Caut\"\n\n#: lib/solaar/ui/window.py:129\nmsgid   \"Battery\"\nmsgstr  \"Baterie\"\n\n#: lib/solaar/ui/window.py:132\nmsgid   \"Wireless Link\"\nmsgstr  \"Legatură fără fir\"\n\n#: lib/solaar/ui/window.py:136\nmsgid   \"Lighting\"\nmsgstr  \"Lumină\"\n\n#: lib/solaar/ui/window.py:170\nmsgid   \"Show Technical Details\"\nmsgstr  \"Detalii tehnice\"\n\n#: lib/solaar/ui/window.py:186\nmsgid   \"Pair new device\"\nmsgstr  \"Conectează periferic\"\n\n#: lib/solaar/ui/window.py:205\nmsgid   \"Select a device\"\nmsgstr  \"Selectați un dispozitiv\"\n\n#: lib/solaar/ui/window.py:322\nmsgid   \"Rule Editor\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Path\"\nmsgstr  \"Cale\"\n\n#: lib/solaar/ui/window.py:536\nmsgid   \"USB ID\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid   \"Serial\"\nmsgstr  \"Serial\"\n\n#: lib/solaar/ui/window.py:545\nmsgid   \"Index\"\nmsgstr  \"Index\"\n\n#: lib/solaar/ui/window.py:547\nmsgid   \"Wireless PID\"\nmsgstr  \"Cod WPID\"\n\n#: lib/solaar/ui/window.py:549\nmsgid   \"Product ID\"\nmsgstr  \"ID produs\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Protocol\"\nmsgstr  \"Protocol\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Unknown\"\nmsgstr  \"Necunoscut\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid   \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:554\nmsgid   \"Polling rate\"\nmsgstr  \"Rată acces\"\n\n#: lib/solaar/ui/window.py:565\nmsgid   \"Unit ID\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:576\nmsgid   \"none\"\nmsgstr  \"nici una\"\n\n#: lib/solaar/ui/window.py:577\nmsgid   \"Notifications\"\nmsgstr  \"Notificări\"\n\n#: lib/solaar/ui/window.py:621\nmsgid   \"No device paired.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\nmsgstr[2]       \"\"\n\n#: lib/solaar/ui/window.py:634\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\nmsgstr[2]       \"\"\n\n#: lib/solaar/ui/window.py:692\nmsgid   \"Battery Voltage\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:694\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:696\nmsgid   \"Battery Level\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:698\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid   \"next reported \"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:708\nmsgid   \" and next level to be reported.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"last known\"\nmsgstr  \"ultima valoare\"\n\n#: lib/solaar/ui/window.py:724\nmsgid   \"encrypted\"\nmsgstr  \"criptată\"\n\n#: lib/solaar/ui/window.py:726\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"Legătura fără fir este criptată.\"\n\n#: lib/solaar/ui/window.py:728\nmsgid   \"not encrypted\"\nmsgstr  \"ne-criptată\"\n\n#: lib/solaar/ui/window.py:732\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"\"\n\n#~ msgid        \" paired devices.\"\n#~ msgstr       \" periferice contectate.\"\n\n#~ msgid        \"1 paired device.\"\n#~ msgstr       \"Un periferic contectat.\"\n\n#~ msgid        \"Count\"\n#~ msgstr       \"Contor\"\n\n#, python-format\n#~ msgid        \"Found a Logitech Receiver (%s), but did not have permission \"\n#~      \"to open it.\"\n#~ msgstr       \"Receptor Logitech detectat (%s), dar nu am permisiunea să-l \"\n#~      \"deschid.\"\n\n#~ msgid        \"Found a new device\"\n#~ msgstr       \"Periferic nou detectat\"\n\n#~ msgid        \"If the device is already turned on,\\n\"\n#~      \"turn if off and on again.\"\n#~ msgstr       \"Dacă dispozitivul este deja pornit,\\n\"\n#~      \"opriți-l și porniți-l din nou.\"\n\n#~ msgid        \"If you've just installed Solaar, try removing the receiver \"\n#~      \"and plugging it back in.\"\n#~ msgstr       \"Dacă tocmai ați instalat Solaar, scoateți receptorul și re-\"\n#~      \"introduceți-l.\"\n\n#~ msgid        \"No Logitech receiver found\"\n#~ msgstr       \"Nu am găsit nici un receptor Logitech\"\n\n#~ msgid        \"No device paired\"\n#~ msgstr       \"Nici un periferic conectat\"\n\n#~ msgid        \"Only one device can be paired to this receiver\"\n#~ msgstr       \"Acest receptor suportă un singur periferic conectat\"\n\n#~ msgid        \"Shows status of devices connected\\n\"\n#~      \"through wireless Logitech receivers.\"\n#~ msgstr       \"Afișează starea perifericelor conectate\\n\"\n#~      \"printr-un receptor Logitech fără fir.\"\n\n#~ msgid        \"Smooth Scrolling\"\n#~ msgstr       \"Derulare fină\"\n\n#, python-format\n#~ msgid        \"The receiver only supports %d paired device(s).\"\n#~ msgstr       \"Receptorul suportă maxim %d periferic(e) contectate.\"\n\n#~ msgid        \"The receiver was unplugged.\"\n#~ msgstr       \"Receptor deconectat.\"\n\n#~ msgid        \"The wireless link between this device and its receiver is \"\n#~      \"not encrypted.\\n\"\n#~      \"\\n\"\n#~      \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~      \"security issue.\\n\"\n#~      \"\\n\"\n#~      \"It is, however, a major security issue for text-input devices \"\n#~      \"(keyboards, numpads),\\n\"\n#~      \"because typed text can be sniffed inconspicuously by 3rd parties \"\n#~      \"within range.\"\n#~ msgstr       \"Legătura fără fir nu este criptată.\"\n\n#~ msgid        \"USB id\"\n#~ msgstr       \"USB\"\n\n#~ msgid        \"Up to %d devices can be paired to this receiver\"\n#~ msgstr       \"Acest receptor suportă maxim %d periferice conectate\"\n\n#~ msgid        \"closed\"\n#~ msgstr       \"închis\"\n\n#~ msgid        \"height\"\n#~ msgstr       \"înălțime\"\n\n#~ msgid        \"lux\"\n#~ msgstr       \"lucși\"\n\n#~ msgid        \"open\"\n#~ msgstr       \"deschis\"\n\n#~ msgid        \"pair new device\"\n#~ msgstr       \"conectează periferic nou\"\n\n#~ msgid        \"paired devices\"\n#~ msgstr       \"periferice conectate\"\n\n#~ msgid        \"pairing lock is \"\n#~ msgstr       \"lacătul de contectare este \"\n\n#~ msgid        \"unknown\"\n#~ msgstr       \"necunoscută\"\n\n#~ msgid        \"width\"\n#~ msgstr       \"lățime\"\n"
  },
  {
    "path": "po/ru.po",
    "content": "# Russian translations for solaar package.\n# Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n#\n# Automatically generated, 2013.\n# Dmitry Ryazantcev <DJm00n@mail.ru>, 2013-2016.\n# Vadim Illarionov <gbIMoBou@gmail.com>, 2021.\n# Olesya Gerasimenko <translation-team@basealt.ru>, 2021, 2022.\n# MistificaT0r <0mistificator0@gmail.com>, 2024.\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 1.1.13\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2025-12-01 21:43+0300\\n\"\n        \"PO-Revision-Date: 2024-04-21 01:38+0300\\n\"\n        \"Last-Translator: MistificaT0r <0mistificator0@gmail.com>\\n\"\n        \"Language-Team: ru\\n\"\n        \"Language: ru\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 \"\n        \"&& n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\\n\"\n        \"X-Generator: Lokalize 24.02.2\\n\"\n\n#: lib/logitech_receiver/base_usb.py:52\nmsgid   \"Bolt Receiver\"\nmsgstr  \"Приёмник «Bolt»\"\n\n#: lib/logitech_receiver/base_usb.py:64\nmsgid   \"Unifying Receiver\"\nmsgstr  \"Приёмник «Unifying»\"\n\n#: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87\n#: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113\nmsgid   \"Nano Receiver\"\nmsgstr  \"Приёмник «Nano»\"\n\n#: lib/logitech_receiver/base_usb.py:125\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"Приёмник «Lightspeed»\"\n\n#: lib/logitech_receiver/base_usb.py:135\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"Приёмник «EX100» 27 МГц\"\n\n#: lib/logitech_receiver/common.py:649\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"Батарея: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:652\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"Батарея: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:1048\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Disabled\"\nmsgstr  \"Отключено\"\n\n#: lib/logitech_receiver/hidpp20.py:1049\nmsgid   \"Static\"\nmsgstr  \"Статичный\"\n\n#: lib/logitech_receiver/hidpp20.py:1050\nmsgid   \"Pulse\"\nmsgstr  \"Пульс\"\n\n#: lib/logitech_receiver/hidpp20.py:1051\nmsgid   \"Cycle\"\nmsgstr  \"Цикл\"\n\n#: lib/logitech_receiver/hidpp20.py:1052\nmsgid   \"Boot\"\nmsgstr  \"Запуск\"\n\n#: lib/logitech_receiver/hidpp20.py:1053\nmsgid   \"Demo\"\nmsgstr  \"Демонстрация\"\n\n#: lib/logitech_receiver/hidpp20.py:1055\nmsgid   \"Breathe\"\nmsgstr  \"Дышать\"\n\n#: lib/logitech_receiver/hidpp20.py:1058\nmsgid   \"Ripple\"\nmsgstr  \"Пульсация\"\n\n#: lib/logitech_receiver/hidpp20.py:1059\nmsgid   \"Decomposition\"\nmsgstr  \"Разложение\"\n\n#: lib/logitech_receiver/hidpp20.py:1060\nmsgid   \"Signature1\"\nmsgstr  \"Подпись1\"\n\n#: lib/logitech_receiver/hidpp20.py:1061\nmsgid   \"Signature2\"\nmsgstr  \"Подпись2\"\n\n#: lib/logitech_receiver/hidpp20.py:1062\nmsgid   \"CycleS\"\nmsgstr  \"Циклы\"\n\n#: lib/logitech_receiver/hidpp20.py:1126\nmsgid   \"Unknown Location\"\nmsgstr  \"Неизвестное местоположение\"\n\n#: lib/logitech_receiver/hidpp20.py:1127\nmsgid   \"Primary\"\nmsgstr  \"Первичный\"\n\n#: lib/logitech_receiver/hidpp20.py:1128\nmsgid   \"Logo\"\nmsgstr  \"Логотип\"\n\n#: lib/logitech_receiver/hidpp20.py:1129\nmsgid   \"Left Side\"\nmsgstr  \"Левая сторона\"\n\n#: lib/logitech_receiver/hidpp20.py:1130\nmsgid   \"Right Side\"\nmsgstr  \"Правая сторона\"\n\n#: lib/logitech_receiver/hidpp20.py:1131\nmsgid   \"Combined\"\nmsgstr  \"Комбинированный\"\n\n#: lib/logitech_receiver/hidpp20.py:1132\nmsgid   \"Primary 1\"\nmsgstr  \"Первичный 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1133\nmsgid   \"Primary 2\"\nmsgstr  \"Первичный 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1134\nmsgid   \"Primary 3\"\nmsgstr  \"Первичный 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1135\nmsgid   \"Primary 4\"\nmsgstr  \"Первичный 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1136\nmsgid   \"Primary 5\"\nmsgstr  \"Первичный 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1137\nmsgid   \"Primary 6\"\nmsgstr  \"Первичный 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid   \"empty\"\nmsgstr  \"пусто\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid   \"critical\"\nmsgstr  \"критический\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"low\"\nmsgstr  \"низкий\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"average\"\nmsgstr  \"средний\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"good\"\nmsgstr  \"нормальный\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"full\"\nmsgstr  \"полный\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"discharging\"\nmsgstr  \"разряжается\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid   \"recharging\"\nmsgstr  \"перезаряжается\"\n\n#: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700\nmsgid   \"charging\"\nmsgstr  \"заряжается\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"not charging\"\nmsgstr  \"не заряжается\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"almost full\"\nmsgstr  \"почти полная\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid   \"charged\"\nmsgstr  \"заряжено\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"slow recharge\"\nmsgstr  \"медленная разрядка\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"invalid battery\"\nmsgstr  \"недопустимая батарея\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"thermal error\"\nmsgstr  \"тепловая ошибка\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"error\"\nmsgstr  \"ошибка\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"standard\"\nmsgstr  \"стандартно\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"fast\"\nmsgstr  \"быстро\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"slow\"\nmsgstr  \"медленно\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"device timeout\"\nmsgstr  \"тайм-аут устройства\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"device not supported\"\nmsgstr  \"устройство не поддерживается\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid   \"too many devices\"\nmsgstr  \"слишком много устройств\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid   \"sequence timeout\"\nmsgstr  \"тайм-аут последовательности\"\n\n#: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555\nmsgid   \"Firmware\"\nmsgstr  \"Прошивка\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"Bootloader\"\nmsgstr  \"Загрузчик\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"Hardware\"\nmsgstr  \"Оборудование\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid   \"Other\"\nmsgstr  \"Другое\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid   \"Left Button\"\nmsgstr  \"Левая кнопка\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Right Button\"\nmsgstr  \"Правая кнопка\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Middle Button\"\nmsgstr  \"Средняя кнопка\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Back Button\"\nmsgstr  \"Кнопка назад\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid   \"Forward Button\"\nmsgstr  \"Кнопка вперёд\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"Кнопка жестов\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Smart Shift\"\nmsgstr  \"Умный Переход\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"DPI Switch\"\nmsgstr  \"Переключатель чувствительности\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Left Tilt\"\nmsgstr  \"Наклон влево\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Right Tilt\"\nmsgstr  \"Наклон вправо\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Left Click\"\nmsgstr  \"Щелчок левой кнопкой\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Right Click\"\nmsgstr  \"Щелчок правой кнопкой\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"Средняя кнопка мыши\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"Mouse Back Button\"\nmsgstr  \"Кнопка мыши Назад\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"Кнопка мыши Вперед\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"Навигация кнопкой жестов\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"Кнопка прокрутки влево\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"Кнопка прокрутки вправо\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"pressed\"\nmsgstr  \"нажата\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"released\"\nmsgstr  \"отпущена\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid   \"connected\"\nmsgstr  \"соединено\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid   \"disconnected\"\nmsgstr  \"разъединено\"\n\n#: lib/logitech_receiver/notifications.py:182\nmsgid   \"unpaired\"\nmsgstr  \"не сопряжено\"\n\n#: lib/logitech_receiver/notifications.py:231\nmsgid   \"powered on\"\nmsgstr  \"включено\"\n\n#: lib/logitech_receiver/notifications.py:283\nmsgid   \"ADC measurement notification\"\nmsgstr  \"Уведомление об измерении ADC\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:483\nmsgid   \"pairing lock is closed\"\nmsgstr  \"сопряжение заблокировано\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:483\nmsgid   \"pairing lock is open\"\nmsgstr  \"сопряжение разблокировано\"\n\n#: lib/logitech_receiver/notifications.py:446\nmsgid   \"discovery lock is closed\"\nmsgstr  \"обнаружение заблокировано\"\n\n#: lib/logitech_receiver/notifications.py:446\nmsgid   \"discovery lock is open\"\nmsgstr  \"обнаружение разблокировано\"\n\n#: lib/logitech_receiver/receiver.py:437\nmsgid   \"No paired devices.\"\nmsgstr  \"Нет сопряжённых устройств.\"\n\n#: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"%(count)s сопряжённое устройство.\"\nmsgstr[1]       \"%(count)s сопряжённых устройства.\"\nmsgstr[2]       \"%(count)s сопряжённых устройств.\"\n\n#: lib/logitech_receiver/settings.py:602\nmsgid   \"register\"\nmsgstr  \"зарегистрировано\"\n\n#: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654\nmsgid   \"feature\"\nmsgstr  \"особенность\"\n\n#: lib/logitech_receiver/settings_templates.py:138\nmsgid   \"Swap Fx function\"\nmsgstr  \"Сменить поведение Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:141\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"Когда включено, кнопки F1..F12 работают по дополнительным функциям,\\n\"\n        \"а выбор основных производится с зажатой кнопкой «FN».\"\n\n#: lib/logitech_receiver/settings_templates.py:146\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"Когда выключено, кнопки F1..F12 работают по основным функциям,\\n\"\n        \"а выбор дополнительных производится с зажатой кнопкой «FN».\"\n\n#: lib/logitech_receiver/settings_templates.py:154\nmsgid   \"Hand Detection\"\nmsgstr  \"Обнаружение рук\"\n\n#: lib/logitech_receiver/settings_templates.py:155\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"Включать подсветку, когда руки над клавиатурой.\"\n\n#: lib/logitech_receiver/settings_templates.py:162\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"Плавная прокрутка колесом мыши\"\n\n#: lib/logitech_receiver/settings_templates.py:163\n#: lib/logitech_receiver/settings_templates.py:410\n#: lib/logitech_receiver/settings_templates.py:439\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"Режим высокой чувствительности для вертикальной прокрутки колесом.\"\n\n#: lib/logitech_receiver/settings_templates.py:170\nmsgid   \"Side Scrolling\"\nmsgstr  \"Горизонтальная прокрутка\"\n\n#: lib/logitech_receiver/settings_templates.py:172\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"Когда отключено, нажатие на колесо сбоку\\n\"\n        \"вместо стандартных событий горизонтальной прокрутки\\n\"\n        \"будет отправлять пользовательские события нажатия.\"\n\n#: lib/logitech_receiver/settings_templates.py:182\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"Чувствительность (тчк/дюйм — старые мыши)\"\n\n#: lib/logitech_receiver/settings_templates.py:183\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"Чувствительность перемещения мыши\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Backlight Timed\"\nmsgstr  \"Подсветка по времени\"\n\n#: lib/logitech_receiver/settings_templates.py:257\n#: lib/logitech_receiver/settings_templates.py:397\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"Настройка времени подсветки клавиатуры.\"\n\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Backlight\"\nmsgstr  \"Подсветка\"\n\n#: lib/logitech_receiver/settings_templates.py:269\nmsgid   \"Illumination level on keyboard.  Changes made are only applied in \"\n        \"Manual mode.\"\nmsgstr  \"Уровень подсветки клавиатуры. Внесенные изменения применяются только \"\n        \"в Ручном режиме.\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Automatic\"\nmsgstr  \"Автоматический\"\n\n#: lib/logitech_receiver/settings_templates.py:303\nmsgid   \"Manual\"\nmsgstr  \"Ручной\"\n\n#: lib/logitech_receiver/settings_templates.py:305\nmsgid   \"Enabled\"\nmsgstr  \"Включенный\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Backlight Level\"\nmsgstr  \"Уровень подсветки\"\n\n#: lib/logitech_receiver/settings_templates.py:312\nmsgid   \"Illumination level on keyboard when in Manual mode.\"\nmsgstr  \"Уровень освещенности клавиатуры в ручном режиме.\"\n\n#: lib/logitech_receiver/settings_templates.py:369\nmsgid   \"Backlight Delay Hands Out\"\nmsgstr  \"Задержка подсветки\"\n\n#: lib/logitech_receiver/settings_templates.py:370\nmsgid   \"Delay in seconds until backlight fades out with hands away from \"\n        \"keyboard.\"\nmsgstr  \"Задержка в секундах, пока подсветка не погаснет, если руки не будут \"\n        \"лежать на клавиатуре.\"\n\n#: lib/logitech_receiver/settings_templates.py:378\nmsgid   \"Backlight Delay Hands In\"\nmsgstr  \"Задержка подсветки стрелок в\"\n\n#: lib/logitech_receiver/settings_templates.py:379\nmsgid   \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr  \"Задержка в секундах, пока подсветка не погаснет, если руки находятся \"\n        \"рядом с клавиатурой.\"\n\n#: lib/logitech_receiver/settings_templates.py:387\nmsgid   \"Backlight Delay Powered\"\nmsgstr  \"Включение подсветки с задержкой\"\n\n#: lib/logitech_receiver/settings_templates.py:388\nmsgid   \"Delay in seconds until backlight fades out with external power.\"\nmsgstr  \"Задержка в секундах до тех пор, пока подсветка не погаснет при \"\n        \"включении внешнего питания.\"\n\n#: lib/logitech_receiver/settings_templates.py:396\nmsgid   \"Backlight (Seconds)\"\nmsgstr  \"Подсветка (секунды)\"\n\n#: lib/logitech_receiver/settings_templates.py:408\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"Высокое разрешение колеса прокрутки\"\n\n#: lib/logitech_receiver/settings_templates.py:412\n#: lib/logitech_receiver/settings_templates.py:441\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"Настройка игнорирования слишком быстрой или медленной прокрутки\"\n\n#: lib/logitech_receiver/settings_templates.py:419\n#: lib/logitech_receiver/settings_templates.py:450\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"Поведение колеса прокрутки\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"Заставить колесо прокрутки отправлять уведомления LOWRES_WHEEL HID++ \"\n        \"(которые запускают правила Solaar, но в остальном игнорируются).\"\n\n#: lib/logitech_receiver/settings_templates.py:428\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"Направление прокрутки\"\n\n#: lib/logitech_receiver/settings_templates.py:429\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"Обратная прокрутка колесом.\"\n\n#: lib/logitech_receiver/settings_templates.py:437\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"Разрешение прокрутки колесом\"\n\n#: lib/logitech_receiver/settings_templates.py:452\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"Заставить колесо прокрутки отправлять уведомления HIRES_WHEEL HID++ \"\n        \"(которые запускают правила Solaar, но в остальном игнорируются).\"\n\n#: lib/logitech_receiver/settings_templates.py:461\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"Чувствительность (скорость указателя)\"\n\n#: lib/logitech_receiver/settings_templates.py:462\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"Множитель скорости мыши (обычно - 256).\"\n\n#: lib/logitech_receiver/settings_templates.py:472\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"Поведение бокового колеса\"\n\n#: lib/logitech_receiver/settings_templates.py:474\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"Заставить колесо большого пальца отправлять уведомления THUMB_WHEEL \"\n        \"HID++ (которые запускают Правила Solaar, но в остальном \"\n        \"игнорируются).\"\n\n#: lib/logitech_receiver/settings_templates.py:483\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"Направление вращения бокового колеса\"\n\n#: lib/logitech_receiver/settings_templates.py:484\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"Изменяет направление вращения бокового колеса.\"\n\n#: lib/logitech_receiver/settings_templates.py:504\nmsgid   \"Onboard Profiles\"\nmsgstr  \"Встроенные профили\"\n\n#: lib/logitech_receiver/settings_templates.py:505\nmsgid   \"Enable an onboard profile, which controls report rate, sensitivity, \"\n        \"and button actions\"\nmsgstr  \"Включите встроенный профиль, который контролирует частоту отчетов, \"\n        \"чувствительность, и действия кнопок\"\n\n#: lib/logitech_receiver/settings_templates.py:549\n#: lib/logitech_receiver/settings_templates.py:582\nmsgid   \"Report Rate\"\nmsgstr  \"Частота отчетов\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\nmsgid   \"Frequency of device movement reports\"\nmsgstr  \"Частота сообщений о перемещении устройства\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1421\n#: lib/logitech_receiver/settings_templates.py:1452\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"Для работы может потребоваться отключить параметр «Встроенные \"\n        \"профили».\"\n\n#: lib/logitech_receiver/settings_templates.py:612\nmsgid   \"Divert crown events\"\nmsgstr  \"Поведение верньера\"\n\n#: lib/logitech_receiver/settings_templates.py:613\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Включает отправку верньером оповещения CROWN HID++ (применимо только \"\n        \"к правилам Solaar, остальными игнорируется).\"\n\n#: lib/logitech_receiver/settings_templates.py:621\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"Плавная прокрутка верньера\"\n\n#: lib/logitech_receiver/settings_templates.py:622\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"Настройка плавной прокрутки верньера\"\n\n#: lib/logitech_receiver/settings_templates.py:630\nmsgid   \"Divert G and M Keys\"\nmsgstr  \"Перенаправление клавиш G и M\"\n\n#: lib/logitech_receiver/settings_templates.py:631\nmsgid   \"Make G and M keys send HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Заставить клавиши G и M отправлять уведомления HID++ (которые \"\n        \"запускают Solaar правила, но в остальном игнорируются).\"\n\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"Колесо прокрутки с храповым механизмом\"\n\n#: lib/logitech_receiver/settings_templates.py:646\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"Переключение колеса мыши между вращением с храповым механизмом и \"\n        \"свободным вращением.\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid   \"Freespinning\"\nmsgstr  \"Свободное вращение\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid   \"Ratcheted\"\nmsgstr  \"Вращение с храповым механизмом\"\n\n#: lib/logitech_receiver/settings_templates.py:655\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"Скорость вращения колеса прокрутки\"\n\n#: lib/logitech_receiver/settings_templates.py:657\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"Используйте скорость вращения колесика мыши для переключения между \"\n        \"вращением с храповым механизмом и свободным вращением.\\n\"\n        \"Колесо мыши всегда вращается с храповым механизмом на 50 градусов.\"\n\n#: lib/logitech_receiver/settings_templates.py:707\nmsgid   \"Scroll Wheel Ratchet Torque\"\nmsgstr  \"Крутящий момент храпового механизма прокручивающего колеса\"\n\n#: lib/logitech_receiver/settings_templates.py:708\nmsgid   \"Change the torque needed to overcome the ratchet.\"\nmsgstr  \"Измените крутящий момент, необходимый для преодоления храпового механизма.\"\n\n#: lib/logitech_receiver/settings_templates.py:743\nmsgid   \"Key/Button Actions\"\nmsgstr  \"Действия с клавишами/кнопками\"\n\n#: lib/logitech_receiver/settings_templates.py:745\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"Изменить действие кнопки или клавиши.\"\n\n#: lib/logitech_receiver/settings_templates.py:747\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"Отменено перенаправлением.\"\n\n#: lib/logitech_receiver/settings_templates.py:749\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"(изменение важных действий — например, левой кнопки мыши - может \"\n        \"вывести систему из строя).\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"Поведение клавиш/кнопок\"\n\n#: lib/logitech_receiver/settings_templates.py:925\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"Заставьте клавишу или кнопку отправлять уведомления HID++ \"\n        \"(перенаправленные) или инициировать жесты мыши или скользящее \"\n        \"значение DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid   \"Diverted\"\nmsgstr  \"Перенаправлено\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\nmsgid   \"Mouse Gestures\"\nmsgstr  \"Жесты мышью\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid   \"Regular\"\nmsgstr  \"Обычное\"\n\n#: lib/logitech_receiver/settings_templates.py:928\nmsgid   \"Sliding DPI\"\nmsgstr  \"Скользящий тчк/дюйм\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"Чувствительность (тчк/дюйм)\"\n\n#: lib/logitech_receiver/settings_templates.py:1123\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"Переключение чувствительности\"\n\n#: lib/logitech_receiver/settings_templates.py:1125\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"Переключение текущей чувствительности и сохранённой чувствительности \"\n        \"при нажатии клавиши или кнопки.\\n\"\n        \"Если сохранённой чувствительности нет, сохраняется текущая \"\n        \"чувствительность\"\n\n#: lib/logitech_receiver/settings_templates.py:1129\nmsgid   \"Off\"\nmsgstr  \"Откл\"\n\n#: lib/logitech_receiver/settings_templates.py:1160\nmsgid   \"Disable keys\"\nmsgstr  \"Отключить клавиши\"\n\n#: lib/logitech_receiver/settings_templates.py:1161\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"Отключение определённых клавиш клавиатуры.\"\n\n#: lib/logitech_receiver/settings_templates.py:1164\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"Отключение клавиши %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1177\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid   \"Set OS\"\nmsgstr  \"Операционная система\"\n\n#: lib/logitech_receiver/settings_templates.py:1178\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"Изменяет назначение клавиш соответственно ОС.\"\n\n#: lib/logitech_receiver/settings_templates.py:1247\nmsgid   \"Change Host\"\nmsgstr  \"Подключено к\"\n\n#: lib/logitech_receiver/settings_templates.py:1248\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"Переключает соединение на выбранный хост.\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid   \"Performs a left click.\"\nmsgstr  \"Осуществляет щелчок левой кнопкой.\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid   \"Single tap\"\nmsgstr  \"Одиночное касание\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid   \"Performs a right click.\"\nmsgstr  \"Осуществляет щелчок правой кнопкой.\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"Одиночное касание двумя пальцами\"\n\n#: lib/logitech_receiver/settings_templates.py:1274\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"Одиночное касание тремя пальцами\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid   \"Double tap\"\nmsgstr  \"Двойное касание\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid   \"Performs a double click.\"\nmsgstr  \"Осуществление двойного щелчка.\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"Двойное касание двумя пальцами\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"Двойное касание тремя пальцами\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"Перетаскивать объекты перемещением пальца после двойного касания.\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid   \"Tap and drag\"\nmsgstr  \"Касание и перетаскивание\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"Касание и перетаскивание двумя пальцами\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"Перетаскивать объекты перемещением пальцев после двойного касания.\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"Касание и перетаскивание тремя пальцами\"\n\n#: lib/logitech_receiver/settings_templates.py:1291\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"Подавление касаний и жестов по краям\"\n\n#: lib/logitech_receiver/settings_templates.py:1292\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"Отключает касания и жесты по краям (то же что FN+ЩелчокЛевойКнопкой).\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\nmsgid   \"Scroll with one finger\"\nmsgstr  \"Вертикальная прокрутка одним пальцем\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid   \"Scrolls.\"\nmsgstr  \"Прокручивать вертикально.\"\n\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"Вертикальная прокрутка двумя пальцами\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"Горизонтальная прокрутка двумя пальцами\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"Прокручивать горизонтально.\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"Вертикальная прокрутка двумя пальцами\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"Прокручивать вертикально.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"Инвертирует направления прокрутки.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid   \"Natural scrolling\"\nmsgstr  \"Естественная прокрутка\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"Включение бокового колеса прокрутки.\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid   \"Thumbwheel\"\nmsgstr  \"Боковое колесо прокрутки\"\n\n#: lib/logitech_receiver/settings_templates.py:1311\n#: lib/logitech_receiver/settings_templates.py:1315\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"Листание от верхнего края\"\n\n#: lib/logitech_receiver/settings_templates.py:1312\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"Листание от левого края\"\n\n#: lib/logitech_receiver/settings_templates.py:1313\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"Листание от правого края\"\n\n#: lib/logitech_receiver/settings_templates.py:1314\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"Листание от нижнего края\"\n\n#: lib/logitech_receiver/settings_templates.py:1316\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"Листание двумя пальцами от левого края\"\n\n#: lib/logitech_receiver/settings_templates.py:1317\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"Листание двумя пальцами от правого края\"\n\n#: lib/logitech_receiver/settings_templates.py:1318\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"Листание двумя пальцами от нижнего края\"\n\n#: lib/logitech_receiver/settings_templates.py:1319\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"Листание двумя пальцами от верхнего края\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"Щипок - уменьшить, раздвинуть - увеличить.\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"Масштабирование двумя пальцами.\"\n\n#: lib/logitech_receiver/settings_templates.py:1321\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"Щипок - уменьшить.\"\n\n#: lib/logitech_receiver/settings_templates.py:1322\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"Раздвинуть - увеличить.\"\n\n#: lib/logitech_receiver/settings_templates.py:1323\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"Масштабирование тремя пальцами.\"\n\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"Масштабирование двумя пальцами\"\n\n#: lib/logitech_receiver/settings_templates.py:1342\nmsgid   \"Pixel zone\"\nmsgstr  \"Зона пикселей\"\n\n#: lib/logitech_receiver/settings_templates.py:1343\nmsgid   \"Ratio zone\"\nmsgstr  \"Зона масштаба\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid   \"Scale factor\"\nmsgstr  \"Коэффициент масштабирования\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"Установка скорости курсора.\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid   \"Left\"\nmsgstr  \"Лево\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"Самая левая позиция.\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid   \"Bottom\"\nmsgstr  \"Низ\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"Нижняя позиция.\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid   \"Width\"\nmsgstr  \"Ширина\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid   \"Width.\"\nmsgstr  \"Ширина.\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid   \"Height\"\nmsgstr  \"Высота\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid   \"Height.\"\nmsgstr  \"Высота.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid   \"Cursor speed.\"\nmsgstr  \"Скорость курсора.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid   \"Scale\"\nmsgstr  \"Масштаб\"\n\n#: lib/logitech_receiver/settings_templates.py:1358\nmsgid   \"Gestures\"\nmsgstr  \"Жесты\"\n\n#: lib/logitech_receiver/settings_templates.py:1359\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"Регулировка поведения мыши/сенсорной панели.\"\n\n#: lib/logitech_receiver/settings_templates.py:1375\nmsgid   \"Gestures Diversion\"\nmsgstr  \"Поведение жестов\"\n\n#: lib/logitech_receiver/settings_templates.py:1376\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"Регулировка поведения жестов мыши/сенсорной панели.\"\n\n#: lib/logitech_receiver/settings_templates.py:1392\nmsgid   \"Gesture params\"\nmsgstr  \"Параметры жестов\"\n\n#: lib/logitech_receiver/settings_templates.py:1393\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"Изменение числовых параметров мыши/сенсорной панели.\"\n\n#: lib/logitech_receiver/settings_templates.py:1417\nmsgid   \"M-Key LEDs\"\nmsgstr  \"Светодиоды клавиш M\"\n\n#: lib/logitech_receiver/settings_templates.py:1419\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"Управление светодиодами клавиш M.\"\n\n#: lib/logitech_receiver/settings_templates.py:1423\n#: lib/logitech_receiver/settings_templates.py:1454\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"Возможно, для эффективности потребуется перенаправить G-клавиши.\"\n\n#: lib/logitech_receiver/settings_templates.py:1429\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"Подсветка клавиши %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1448\nmsgid   \"MR-Key LED\"\nmsgstr  \"Светодиод клавиши MR\"\n\n#: lib/logitech_receiver/settings_templates.py:1450\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"Управление светодиодом клавиши MR.\"\n\n#: lib/logitech_receiver/settings_templates.py:1471\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"Постоянное сопоставление клавиши или кнопки\"\n\n#: lib/logitech_receiver/settings_templates.py:1473\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"Навсегда изменить сопоставление для клавиши или кнопки.\"\n\n#: lib/logitech_receiver/settings_templates.py:1475\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"Изменение важных клавиш или кнопок (например, левой мыши кнопку) \"\n        \"может привести к выводу системы из строя.\"\n\n#: lib/logitech_receiver/settings_templates.py:1532\nmsgid   \"Sidetone\"\nmsgstr  \"Самопрослушивание\"\n\n#: lib/logitech_receiver/settings_templates.py:1533\nmsgid   \"Set sidetone level.\"\nmsgstr  \"Установите уровень самопрослушивания.\"\n\n#: lib/logitech_receiver/settings_templates.py:1542\nmsgid   \"Equalizer\"\nmsgstr  \"Эквалайзер\"\n\n#: lib/logitech_receiver/settings_templates.py:1543\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"Установите уровни эквалайзера.\"\n\n#: lib/logitech_receiver/settings_templates.py:1565\nmsgid   \"Hz\"\nmsgstr  \"Гц\"\n\n#: lib/logitech_receiver/settings_templates.py:1571\nmsgid   \"Power Management\"\nmsgstr  \"Управление питанием\"\n\n#: lib/logitech_receiver/settings_templates.py:1572\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"Выключите питание через несколько минут (0 означает \\\"никогда\\\").\"\n\n#: lib/logitech_receiver/settings_templates.py:1584\nmsgid   \"Brightness Control\"\nmsgstr  \"Регулировка яркости\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\nmsgid   \"Control overall brightness\"\nmsgstr  \"Контролируйте общую яркость\"\n\n#: lib/logitech_receiver/settings_templates.py:1628\n#: lib/logitech_receiver/settings_templates.py:1681\nmsgid   \"LED Control\"\nmsgstr  \"Светодиодное управление\"\n\n#: lib/logitech_receiver/settings_templates.py:1629\n#: lib/logitech_receiver/settings_templates.py:1682\nmsgid   \"Switch control of LED zones between device and Solaar\"\nmsgstr  \"Переключайте управление светодиодными зонами между устройством и \"\n        \"Solaar\"\n\n#: lib/logitech_receiver/settings_templates.py:1644\n#: lib/logitech_receiver/settings_templates.py:1692\nmsgid   \"LED Zone Effects\"\nmsgstr  \"Эффекты светодиодной зоны\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid   \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr  \"Для эффективного управления светодиодом необходимо установить режим \"\n        \"Solaar.\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid   \"Set effect for LED Zone\"\nmsgstr  \"Установите эффект для светодиодной зоны\"\n\n#: lib/logitech_receiver/settings_templates.py:1647\nmsgid   \"Color\"\nmsgstr  \"Цвет\"\n\n#: lib/logitech_receiver/settings_templates.py:1648\nmsgid   \"Speed\"\nmsgstr  \"Скорость\"\n\n#: lib/logitech_receiver/settings_templates.py:1649\nmsgid   \"Period\"\nmsgstr  \"Период\"\n\n#: lib/logitech_receiver/settings_templates.py:1650\nmsgid   \"Intensity\"\nmsgstr  \"Интенсивность\"\n\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid   \"Ramp\"\nmsgstr  \"Рампа\"\n\n#: lib/logitech_receiver/settings_templates.py:1666\nmsgid   \"LEDs\"\nmsgstr  \"Светодиоды\"\n\n#: lib/logitech_receiver/settings_templates.py:1703\nmsgid   \"Per-key Lighting\"\nmsgstr  \"Индивидуальное освещение\"\n\n#: lib/logitech_receiver/settings_templates.py:1704\nmsgid   \"Control per-key lighting.\"\nmsgstr  \"Управление подсветкой каждой клавиши.\"\n\n#: lib/logitech_receiver/settings_templates.py:1786\nmsgid   \"Force Sensing Buttons\"\nmsgstr  \"Кнопки с датчиками силы нажатия\"\n\n#: lib/logitech_receiver/settings_templates.py:1787\nmsgid   \"Change the force required to activate button.\"\nmsgstr  \"Измените усилие, необходимое для активации кнопки.\"\n\n#: lib/logitech_receiver/settings_templates.py:1804\nmsgid   \"Force Sensing Button\"\nmsgstr  \"Кнопка измерения усилия\"\n\n#: lib/logitech_receiver/settings_templates.py:1814\nmsgid   \"Haptic Feeback Level\"\nmsgstr  \"Уровень тактильной обратной связи\"\n\n#: lib/logitech_receiver/settings_templates.py:1815\nmsgid   \"Change power of haptic feedback.  (Zero to turn off.)\"\nmsgstr  \"Измените мощность тактильной обратной связи. (Ноль - отключение.)\"\n\n#: lib/logitech_receiver/settings_templates.py:1857\nmsgid   \"Play Haptic Waveform\"\nmsgstr  \"Воспроизведение тактильной формы сигнала\"\n\n#: lib/logitech_receiver/settings_templates.py:1858\nmsgid   \"Tell device to play a haptic waveform.\"\nmsgstr  \"Дайте команду устройству воспроизвести тактильный сигнал.\"\n\n#: lib/solaar/ui/__init__.py:120\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"Другой Solaar процесс уже запущен, так что просто откройте его окно\"\n\n#: lib/solaar/ui/about/model.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"Управление приёмниками, клавиатурами,\\n\"\n        \"мышами и другими устройствами Logitech.\"\n\n#: lib/solaar/ui/about/model.py:63\nmsgid   \"Additional Programming\"\nmsgstr  \"Дополнительные параметры\"\n\n#: lib/solaar/ui/about/model.py:64\nmsgid   \"GUI design\"\nmsgstr  \"Дизайн интерфейса\"\n\n#: lib/solaar/ui/about/model.py:66\nmsgid   \"Testing\"\nmsgstr  \"Тестирование\"\n\n#: lib/solaar/ui/about/model.py:74\nmsgid   \"Logitech documentation\"\nmsgstr  \"Документация Logitech\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92\n#: lib/solaar/ui/window.py:208\nmsgid   \"Unpair\"\nmsgstr  \"Отмена сопряжения\"\n\n#: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Cancel\"\nmsgstr  \"Отмена\"\n\n#: lib/solaar/ui/common.py:42\nmsgid   \"Permissions error\"\nmsgstr  \"Ошибка доступа\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"Найден приёмник Logitech (%s), но нет прав доступ открыть его.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"Если вы только что установили Solaar, попробуйте отключить и снова \"\n        \"подключить приёмник или устройство.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"Невозможно подключиться к устройству\"\n\n#: lib/solaar/ui/common.py:51\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"Найден приёмник или устройство Logitech на %s, но не удалось к нему \"\n        \"подключиться.\"\n\n#: lib/solaar/ui/common.py:53\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"Попробуйте отключить и снова подключить устройство или выключить и \"\n        \"затем снова включить его.\"\n\n#: lib/solaar/ui/common.py:56\nmsgid   \"Unpairing failed\"\nmsgstr  \"Отмена сопряжения не удалась\"\n\n#: lib/solaar/ui/common.py:58\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"Отмена сопряжения %{device} с %{receiver} не удалась.\"\n\n#: lib/solaar/ui/common.py:63\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"Приёмник вернул ошибку без дополнительных сведений.\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"Завершено - «ВВОД» для изменения\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid   \"Incomplete\"\nmsgstr  \"Незавершено\"\n\n#: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"%d значение\"\nmsgstr[1]       \"%d значения\"\nmsgstr[2]       \"%d значений\"\n\n#: lib/solaar/ui/config_panel.py:642\nmsgid   \"Changes allowed\"\nmsgstr  \"Изменения разрешены\"\n\n#: lib/solaar/ui/config_panel.py:643\nmsgid   \"No changes allowed\"\nmsgstr  \"Изменения запрещены\"\n\n#: lib/solaar/ui/config_panel.py:644\nmsgid   \"Ignore this setting\"\nmsgstr  \"Игнорировать данный параметр\"\n\n#: lib/solaar/ui/config_panel.py:690\nmsgid   \"Working\"\nmsgstr  \"Работает\"\n\n#: lib/solaar/ui/config_panel.py:693\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"Операция чтения/записи не удалась.\"\n\n#: lib/solaar/ui/desktop_notifications.py:112\nmsgid   \"unspecified reason\"\nmsgstr  \"неустановленная причина\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid   \"Built-in rules\"\nmsgstr  \"Встроенные правила\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid   \"User-defined rules\"\nmsgstr  \"Пользовательские правила\"\n\n#: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Rule\"\nmsgstr  \"Правило\"\n\n#: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382\n#: lib/solaar/ui/diversion_rules.py:509\nmsgid   \"Sub-rule\"\nmsgstr  \"Подправило\"\n\n#: lib/solaar/ui/diversion_rules.py:108\nmsgid   \"[empty]\"\nmsgstr  \"[пусто]\"\n\n#: lib/solaar/ui/diversion_rules.py:132\nmsgid   \"Make changes permanent?\"\nmsgstr  \"Сохранить изменения навсегда?\"\n\n#: lib/solaar/ui/diversion_rules.py:137\nmsgid   \"Yes\"\nmsgstr  \"Да\"\n\n#: lib/solaar/ui/diversion_rules.py:139\nmsgid   \"No\"\nmsgstr  \"Нет\"\n\n#: lib/solaar/ui/diversion_rules.py:144\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"Если выбрать «Нет», при закрытии программы изменения пропадут.\"\n\n#: lib/solaar/ui/diversion_rules.py:273\nmsgid   \"Paste here\"\nmsgstr  \"Скопировать сюда\"\n\n#: lib/solaar/ui/diversion_rules.py:275\nmsgid   \"Paste above\"\nmsgstr  \"Скопировать выше\"\n\n#: lib/solaar/ui/diversion_rules.py:277\nmsgid   \"Paste below\"\nmsgstr  \"Скопировать ниже\"\n\n#: lib/solaar/ui/diversion_rules.py:283\nmsgid   \"Paste rule here\"\nmsgstr  \"Скопировать правило сюда\"\n\n#: lib/solaar/ui/diversion_rules.py:285\nmsgid   \"Paste rule above\"\nmsgstr  \"Скопировать правило выше\"\n\n#: lib/solaar/ui/diversion_rules.py:287\nmsgid   \"Paste rule below\"\nmsgstr  \"Скопировать правило ниже\"\n\n#: lib/solaar/ui/diversion_rules.py:291\nmsgid   \"Paste rule\"\nmsgstr  \"Скопировать правило\"\n\n#: lib/solaar/ui/diversion_rules.py:306\nmsgid   \"Insert here\"\nmsgstr  \"Вставить сюда\"\n\n#: lib/solaar/ui/diversion_rules.py:308\nmsgid   \"Insert above\"\nmsgstr  \"Вставить выше\"\n\n#: lib/solaar/ui/diversion_rules.py:310\nmsgid   \"Insert below\"\nmsgstr  \"Вставить ниже\"\n\n#: lib/solaar/ui/diversion_rules.py:316\nmsgid   \"Insert new rule here\"\nmsgstr  \"Вставить новое правило сюда\"\n\n#: lib/solaar/ui/diversion_rules.py:318\nmsgid   \"Insert new rule above\"\nmsgstr  \"Вставить новое правило выше\"\n\n#: lib/solaar/ui/diversion_rules.py:320\nmsgid   \"Insert new rule below\"\nmsgstr  \"Вставить новое правило ниже\"\n\n#: lib/solaar/ui/diversion_rules.py:347\nmsgid   \"Flatten\"\nmsgstr  \"Снять обёртку\"\n\n#: lib/solaar/ui/diversion_rules.py:380\nmsgid   \"Insert\"\nmsgstr  \"Вставка\"\n\n#: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511\n#: lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Or\"\nmsgstr  \"Или\"\n\n#: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510\n#: lib/solaar/ui/diversion_rules.py:1144\nmsgid   \"And\"\nmsgstr  \"И\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Condition\"\nmsgstr  \"Компонент\"\n\n#: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154\nmsgid   \"Feature\"\nmsgstr  \"Feature\"\n\n#: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188\nmsgid   \"Report\"\nmsgstr  \"Отчёт\"\n\n#: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69\nmsgid   \"Process\"\nmsgstr  \"Процесс\"\n\n#: lib/solaar/ui/diversion_rules.py:391\nmsgid   \"Mouse process\"\nmsgstr  \"Действие мыши\"\n\n#: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225\nmsgid   \"Modifiers\"\nmsgstr  \"Модификаторы\"\n\n#: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277\nmsgid   \"Key\"\nmsgstr  \"Клавиша\"\n\n#: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318\nmsgid   \"KeyIsDown\"\nmsgstr  \"Клавиша нажата\"\n\n#: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432\nmsgid   \"Active\"\nmsgstr  \"Активный\"\n\n#: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390\n#: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487\nmsgid   \"Device\"\nmsgstr  \"Устройство\"\n\n#: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467\nmsgid   \"Host\"\nmsgstr  \"Хост\"\n\n#: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506\nmsgid   \"Setting\"\nmsgstr  \"Установка\"\n\n#: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333\n#: lib/solaar/ui/rule_conditions.py:382\nmsgid   \"Test\"\nmsgstr  \"Условие\"\n\n#: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507\nmsgid   \"Test bytes\"\nmsgstr  \"Тестовые байты\"\n\n#: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608\nmsgid   \"Mouse Gesture\"\nmsgstr  \"Жест мышью\"\n\n#: lib/solaar/ui/diversion_rules.py:405\nmsgid   \"Action\"\nmsgstr  \"Действие\"\n\n#: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138\nmsgid   \"Key press\"\nmsgstr  \"Нажатие клавиши\"\n\n#: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191\nmsgid   \"Mouse scroll\"\nmsgstr  \"Прокрутка мышью\"\n\n#: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256\nmsgid   \"Mouse click\"\nmsgstr  \"Щелчок мышью\"\n\n#: lib/solaar/ui/diversion_rules.py:410\nmsgid   \"Set\"\nmsgstr  \"Установить\"\n\n#: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328\nmsgid   \"Execute\"\nmsgstr  \"Исполнить\"\n\n#: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189\nmsgid   \"Later\"\nmsgstr  \"Задержка\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Insert new rule\"\nmsgstr  \"Добавить правило\"\n\n#: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82\n#: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556\nmsgid   \"Delete\"\nmsgstr  \"Удалить\"\n\n#: lib/solaar/ui/diversion_rules.py:483\nmsgid   \"Negate\"\nmsgstr  \"Инвертировать\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Wrap with\"\nmsgstr  \"Завернуть в\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Cut\"\nmsgstr  \"Вырезать\"\n\n#: lib/solaar/ui/diversion_rules.py:553\nmsgid   \"Paste\"\nmsgstr  \"Вставить\"\n\n#: lib/solaar/ui/diversion_rules.py:559\nmsgid   \"Copy\"\nmsgstr  \"Копировать\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"Редактор правил\"\n\n#: lib/solaar/ui/diversion_rules.py:668\nmsgid   \"Save changes\"\nmsgstr  \"Сохранить изменения\"\n\n#: lib/solaar/ui/diversion_rules.py:673\nmsgid   \"Discard changes\"\nmsgstr  \"Отменить изменения\"\n\n#: lib/solaar/ui/diversion_rules.py:1104\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"Редактор пока не поддерживает выбранную компоненту правила.\"\n\n#: lib/solaar/ui/diversion_rules.py:1169\nmsgid   \"Number of seconds to delay.  Delay between 0 and 1 is done with \"\n        \"higher precision.\"\nmsgstr  \"Количество секунд задержки. Задержка между 0 и 1 выполняется с \"\n        \"помощью более высокая точность.\"\n\n#: lib/solaar/ui/diversion_rules.py:1207\nmsgid   \"Not\"\nmsgstr  \"Не\"\n\n#: lib/solaar/ui/diversion_rules.py:1238\nmsgid   \"Toggle\"\nmsgstr  \"Переключение\"\n\n#: lib/solaar/ui/diversion_rules.py:1239\nmsgid   \"True\"\nmsgstr  \"Истина\"\n\n#: lib/solaar/ui/diversion_rules.py:1240\nmsgid   \"False\"\nmsgstr  \"Ложь\"\n\n#: lib/solaar/ui/diversion_rules.py:1253\nmsgid   \"Unsupported setting\"\nmsgstr  \"Неподдерживаемый параметр\"\n\n#: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415\n#: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748\n#: lib/solaar/ui/diversion_rules.py:1766\nmsgid   \"Originating device\"\nmsgstr  \"Исходное устройство\"\n\n#: lib/solaar/ui/diversion_rules.py:1428\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"Устройство активно, и его настройки могут быть изменены.\"\n\n#: lib/solaar/ui/diversion_rules.py:1437\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"Устройство, отправившее текущее уведомление.\"\n\n#: lib/solaar/ui/diversion_rules.py:1450\nmsgid   \"Name of host computer.\"\nmsgstr  \"Имя главного компьютера.\"\n\n#: lib/solaar/ui/diversion_rules.py:1520\nmsgid   \"Value\"\nmsgstr  \"Значение\"\n\n#: lib/solaar/ui/diversion_rules.py:1529\nmsgid   \"Item\"\nmsgstr  \"Элемент\"\n\n#: lib/solaar/ui/diversion_rules.py:1808\nmsgid   \"Change setting on device\"\nmsgstr  \"Изменить настройку на устройстве\"\n\n#: lib/solaar/ui/diversion_rules.py:1824\nmsgid   \"Setting on device\"\nmsgstr  \"Настройка на устройстве\"\n\n#: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"%(receiver_name)s: новое сопряжённое устройство\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"Приемники Bolt совместимы только с устройствами Bolt.\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"Нажимайте кнопку или клавишу сопряжения, пока индикатор сопряжения \"\n        \"не начнёт быстро мигать.\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"Приемники Unifying совместимы только с устройствами Unifying.\"\n\n#: lib/solaar/ui/pair_window.py:53\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"Другие ресиверы совместимы только с некоторыми устройствами.\"\n\n#: lib/solaar/ui/pair_window.py:55\nmsgid   \"For most devices, turn on the device you want to pair.\"\nmsgstr  \"Обычно достаточно включить устройство, с которым вы хотите \"\n        \"установить соединение.\"\n\n#: lib/solaar/ui/pair_window.py:56\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"Если устройство включено, выключите его и включите снова.\"\n\n#: lib/solaar/ui/pair_window.py:58\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"Устройство не должно быть сопряжено с находящимся поблизости \"\n        \"включенным приемником.\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid   \"For devices with multiple channels, press, hold, and release the \"\n        \"button for the channel you wish to pair\\n\"\n        \"or use the channel switch button to select a channel and then press, \"\n        \"hold, and release the channel switch button.\"\nmsgstr  \"Для устройств с несколькими каналами нажмите, удерживайте и \"\n        \"отпустите кнопку соответствующего канала, который требуется \"\n        \"подключить, или используйте кнопку переключения каналов, чтобы \"\n        \"выбрать нужный канал, затем нажмите, удерживайте и отпустите кнопку \"\n        \"переключения каналов.\"\n\n#: lib/solaar/ui/pair_window.py:68\nmsgid   \"The channel indicator light should be blinking rapidly.\"\nmsgstr  \"Индикатор канала должен быстро мигать.\"\n\n#: lib/solaar/ui/pair_window.py:72\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\\n\"\n        \"Данному приёмнику доступно %d сопряжение.\"\nmsgstr[1]       \"\\n\"\n        \"Данному приёмнику доступно %d сопряжения.\"\nmsgstr[2]       \"\\n\"\n        \"Данному приёмнику доступно %d сопряжений.\"\n\n#: lib/solaar/ui/pair_window.py:78\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\\n\"\n        \"Прерывание в данный момент отменит сопряжение.\"\n\n#: lib/solaar/ui/pair_window.py:168\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"Введите код доступа на %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:171\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"Введите %(passcode)s и затем нажмите клавишу «Ввод».\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid   \"left\"\nmsgstr  \"слева\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid   \"right\"\nmsgstr  \"справа\"\n\n#: lib/solaar/ui/pair_window.py:178\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"Нажмите %(code)s\\n\"\n        \"и затем нажмите одновременно левую и правую кнопки.\"\n\n#: lib/solaar/ui/pair_window.py:221\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"Беспроводное соединение не зашифровано\"\n\n#: lib/solaar/ui/pair_window.py:226\nmsgid   \"Found a new device:\"\nmsgstr  \"Найдено новое устройство:\"\n\n#: lib/solaar/ui/pair_window.py:247\nmsgid   \"Pairing failed\"\nmsgstr  \"Сопряжение не удалось\"\n\n#: lib/solaar/ui/pair_window.py:249\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"Удостоверьтесь, что ваше устройство в радиусе приёма и батарея \"\n        \"заряжена.\"\n\n#: lib/solaar/ui/pair_window.py:251\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"Обнаружено новое устройство, несовместимое с данным приёмником.\"\n\n#: lib/solaar/ui/pair_window.py:253\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"Превышено число сопрягаемых устройств, поддерживаемое приёмником.\"\n\n#: lib/solaar/ui/pair_window.py:255\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"Дополнительные сведения об этой ошибке отсутствуют.\"\n\n#: lib/solaar/ui/rule_actions.py:54\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"Имитируйте щелчок аккордовой клавиши, нажмите или отпустите.\\n\"\n        \"В Wayland требуется доступ на запись в /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:60\nmsgid   \"Add key\"\nmsgstr  \"Добавить клавишу\"\n\n#: lib/solaar/ui/rule_actions.py:63\nmsgid   \"Click\"\nmsgstr  \"Щелчок\"\n\n#: lib/solaar/ui/rule_actions.py:66\nmsgid   \"Depress\"\nmsgstr  \"Подавить\"\n\n#: lib/solaar/ui/rule_actions.py:69\nmsgid   \"Release\"\nmsgstr  \"Выпускать\"\n\n#: lib/solaar/ui/rule_actions.py:153\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"Имитация прокрутки мыши.\\n\"\n        \"В Wayland требуется доступ на запись в /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:211\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"Имитация щелчка мыши.В Wayland требуется доступ на запись в /dev/\"\n        \"uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:216\nmsgid   \"Button\"\nmsgstr  \"Кнопка\"\n\n#: lib/solaar/ui/rule_actions.py:218\nmsgid   \"Action (and Count, if click)\"\nmsgstr  \"Действие (и количество, если кликнуть)\"\n\n#: lib/solaar/ui/rule_actions.py:269\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"Выполните команду с аргументами.\"\n\n#: lib/solaar/ui/rule_actions.py:273\nmsgid   \"Add argument\"\nmsgstr  \"Добавить аргумент\"\n\n#: lib/solaar/ui/rule_conditions.py:52\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"Активный процесс X11. Только для использования в X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:82\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"Процесс работы с мышью X11. Только для использования в X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:99\nmsgid   \"MouseProcess\"\nmsgstr  \"Действие мыши\"\n\n#: lib/solaar/ui/rule_conditions.py:123\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"Название функции обработки правила запуска уведомления.\"\n\n#: lib/solaar/ui/rule_conditions.py:169\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"Сообщите номер уведомления, запускающего обработку правила.\"\n\n#: lib/solaar/ui/rule_conditions.py:201\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"Активные модификаторы клавиатуры. Не всегда доступны в Wayland.\"\n\n#: lib/solaar/ui/rule_conditions.py:241\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"Перенаправленная клавиша или кнопка нажата или отпущена.\\n\"\n        \"Для переадресации используйте настройки «Переадресация клавиш/\"\n        \"кнопок» и «Переадресация G-клавиш» ключи и кнопки.\"\n\n#: lib/solaar/ui/rule_conditions.py:250\nmsgid   \"Key down\"\nmsgstr  \"Нажать клавишу\"\n\n#: lib/solaar/ui/rule_conditions.py:253\nmsgid   \"Key up\"\nmsgstr  \"Отпустить клавишу\"\n\n#: lib/solaar/ui/rule_conditions.py:293\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"Переадресованная клавиша или кнопка в данный момент нажата.\\n\"\n        \"Используйте настройки Переадресации клавиш/кнопок и Переадресации \"\n        \"клавиш G для переадресации клавиш и кнопок.\"\n\n#: lib/solaar/ui/rule_conditions.py:331\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"Тестовое условие для обработки правила запуска уведомления.\"\n\n#: lib/solaar/ui/rule_conditions.py:335\nmsgid   \"Parameter\"\nmsgstr  \"Параметр\"\n\n#: lib/solaar/ui/rule_conditions.py:408\nmsgid   \"begin (inclusive)\"\nmsgstr  \"начало (включительно)\"\n\n#: lib/solaar/ui/rule_conditions.py:409\nmsgid   \"end (exclusive)\"\nmsgstr  \"конец (исключительно)\"\n\n#: lib/solaar/ui/rule_conditions.py:417\nmsgid   \"range\"\nmsgstr  \"диапазон\"\n\n#: lib/solaar/ui/rule_conditions.py:420\nmsgid   \"minimum\"\nmsgstr  \"минимум\"\n\n#: lib/solaar/ui/rule_conditions.py:421\nmsgid   \"maximum\"\nmsgstr  \"максимум\"\n\n#: lib/solaar/ui/rule_conditions.py:423\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"байты с %(0)d по %(1)d, в диапазоне от %(2)d до %(3)d\"\n\n#: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427\nmsgid   \"mask\"\nmsgstr  \"маска\"\n\n#: lib/solaar/ui/rule_conditions.py:428\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"байты с %(0)d по %(1)d, маска %(2)d\"\n\n#: lib/solaar/ui/rule_conditions.py:437\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"Проверка битов или диапазона на байтах в уведомительном сообщении, \"\n        \"запускающем обработку правила.\"\n\n#: lib/solaar/ui/rule_conditions.py:447\nmsgid   \"type\"\nmsgstr  \"тип\"\n\n#: lib/solaar/ui/rule_conditions.py:535\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"Жест мыши с дополнительной кнопкой запуска, за которым следует ноль \"\n        \"или более движений мыши.\"\n\n#: lib/solaar/ui/rule_conditions.py:541\nmsgid   \"Add movement\"\nmsgstr  \"Добавить движение\"\n\n#: lib/solaar/ui/tray.py:55\nmsgid   \"No supported device found\"\nmsgstr  \"Поддерживаемое устройство не найдено\"\n\n#: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"О программе %s\"\n\n#: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"Выйти из %s\"\n\n#: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281\nmsgid   \"no receiver\"\nmsgstr  \"отсутствует приёмник\"\n\n#: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299\n#: lib/solaar/ui/window.py:728\nmsgid   \"offline\"\nmsgstr  \"нет соединения\"\n\n#: lib/solaar/ui/tray.py:297\nmsgid   \"no status\"\nmsgstr  \"отсутствует статус\"\n\n#: lib/solaar/ui/window.py:110\nmsgid   \"Scanning\"\nmsgstr  \"Сканирование\"\n\n#: lib/solaar/ui/window.py:141\nmsgid   \"Battery\"\nmsgstr  \"Батарея\"\n\n#: lib/solaar/ui/window.py:144\nmsgid   \"Wireless Link\"\nmsgstr  \"Беспроводное соединение\"\n\n#: lib/solaar/ui/window.py:148\nmsgid   \"Lighting\"\nmsgstr  \"Освещённость\"\n\n#: lib/solaar/ui/window.py:182\nmsgid   \"Show Technical Details\"\nmsgstr  \"Технические сведения об устройстве\"\n\n#: lib/solaar/ui/window.py:198\nmsgid   \"Pair new device\"\nmsgstr  \"Новое сопряженное устройство\"\n\n#: lib/solaar/ui/window.py:216\nmsgid   \"Select a device\"\nmsgstr  \"Выбор устройства\"\n\n#: lib/solaar/ui/window.py:331\nmsgid   \"Rule Editor\"\nmsgstr  \"Редактор правил\"\n\n#: lib/solaar/ui/window.py:522\nmsgid   \"Path\"\nmsgstr  \"Расположение\"\n\n#: lib/solaar/ui/window.py:524\nmsgid   \"USB ID\"\nmsgstr  \"Идент. USB\"\n\n#: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529\n#: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546\nmsgid   \"Serial\"\nmsgstr  \"Серийный №\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Index\"\nmsgstr  \"Индекс\"\n\n#: lib/solaar/ui/window.py:535\nmsgid   \"Wireless PID\"\nmsgstr  \"Б/проводн.PID\"\n\n#: lib/solaar/ui/window.py:537\nmsgid   \"Product ID\"\nmsgstr  \"ID изделия\"\n\n#: lib/solaar/ui/window.py:539\nmsgid   \"Protocol\"\nmsgstr  \"Протокол\"\n\n#: lib/solaar/ui/window.py:539\nmsgid   \"Unknown\"\nmsgstr  \"Неизвестен\"\n\n#: lib/solaar/ui/window.py:541\nmsgid   \"Polling rate\"\nmsgstr  \"Част. опроса\"\n\n#: lib/solaar/ui/window.py:548\nmsgid   \"Unit ID\"\nmsgstr  \"ID устройства\"\n\n#: lib/solaar/ui/window.py:559\nmsgid   \"none\"\nmsgstr  \"никто\"\n\n#: lib/solaar/ui/window.py:560\nmsgid   \"Notifications\"\nmsgstr  \"Уведомления\"\n\n#: lib/solaar/ui/window.py:604\nmsgid   \"No device paired.\"\nmsgstr  \"Нет сопряжённых устройств.\"\n\n#: lib/solaar/ui/window.py:613\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"С этим приёмником может быть сопряжено до %(max_count)s \"\n        \"устройства.\"\nmsgstr[1]       \"С этим приёмником может быть сопряжено до %(max_count)s \"\n        \"устройств.\"\nmsgstr[2]       \"С этим приёмником может быть сопряжено до %(max_count)s \"\n        \"устройств.\"\n\n#: lib/solaar/ui/window.py:620\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"К этому приемнику может быть подключено только одно устройство.\"\n\n#: lib/solaar/ui/window.py:624\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"Данному приёмнику доступно ещё %d сопряжение.\"\nmsgstr[1]       \"Данному приёмнику доступно ещё %d сопряжения.\"\nmsgstr[2]       \"Данному приёмнику доступно ещё %d сопряжений.\"\n\n#: lib/solaar/ui/window.py:681\nmsgid   \"Battery Voltage\"\nmsgstr  \"Напряжение батареи\"\n\n#: lib/solaar/ui/window.py:683\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"Напряжение батареи\"\n\n#: lib/solaar/ui/window.py:685\nmsgid   \"Battery Level\"\nmsgstr  \"Уровень заряда\"\n\n#: lib/solaar/ui/window.py:687\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"Приблизительный уровень заряда, cообщаемый батареей\"\n\n#: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696\nmsgid   \"next reported \"\nmsgstr  \"следующий доклад на \"\n\n#: lib/solaar/ui/window.py:697\nmsgid   \" and next level to be reported.\"\nmsgstr  \" \\n\"\n        \"(следующий уровень для отчёта).\"\n\n#: lib/solaar/ui/window.py:702\nmsgid   \"last known\"\nmsgstr  \"последний известный\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"encrypted\"\nmsgstr  \"зашифровано\"\n\n#: lib/solaar/ui/window.py:715\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"Беспроводное соединение между этим устройством и его приёмником \"\n        \"зашифровано.\"\n\n#: lib/solaar/ui/window.py:717\nmsgid   \"not encrypted\"\nmsgstr  \"не зашифровано\"\n\n#: lib/solaar/ui/window.py:721\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"Беспроводное соединение между этим устройством и его приёмником не \"\n        \"зашифровано.\\n\"\n        \"Это проблема безопасности для указывающих устройств и серьезная \"\n        \"проблема безопасности для устройств ввода текста.\"\n\n#: lib/solaar/ui/window.py:737\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"%(light_level)d люкс\"\n"
  },
  {
    "path": "po/sk.po",
    "content": "# Slovak translations for solaar package.\n# Copyright (C) 2021 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2021.\n#\n# SPDX-FileCopyrightText: 2026 Miroslav Ďurian <aasami@gmail.com>\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 1.0.6\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n\"PO-Revision-Date: 2026-01-15 13:17+0100\\n\"\n\"Last-Translator: Miroslav Ďurian <aasami@gmail.com>\\n\"\n\"Language-Team: Slovak <kde-i18n-doc@kde.org>\\n\"\n\"Language: sk\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\\n\"\n\"X-Generator: Lokalize 25.12.0\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid \"Bolt Receiver\"\nmsgstr \"Prijímač Bolt\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid \"Unifying Receiver\"\nmsgstr \"Prijímač Unifying\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid \"Nano Receiver\"\nmsgstr \"Prijímač Nano\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Prijímač Lightspeed\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"Prijímač EX100 27 Mhz\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"empty\"\nmsgstr \"prázdna\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"critical\"\nmsgstr \"kritická\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"low\"\nmsgstr \"nízka\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"average\"\nmsgstr \"priemerná\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid \"good\"\nmsgstr \"dobrá\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"full\"\nmsgstr \"plná\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"discharging\"\nmsgstr \"vybíja sa\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"recharging\"\nmsgstr \"nabíja sa\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid \"charging\"\nmsgstr \"nabíja sa\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"not charging\"\nmsgstr \"nenabíja sa\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"almost full\"\nmsgstr \"takmer nabitá\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"charged\"\nmsgstr \"nabitá\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"slow recharge\"\nmsgstr \"pomalé nabíjanie\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"invalid battery\"\nmsgstr \"chybná batéria\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"thermal error\"\nmsgstr \"teplotná chyba\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"error\"\nmsgstr \"chyba\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid \"standard\"\nmsgstr \"štandardné\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"fast\"\nmsgstr \"rýchle\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"slow\"\nmsgstr \"pomalé\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid \"device timeout\"\nmsgstr \"vypršal časový limit zariadenia\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid \"device not supported\"\nmsgstr \"nepodporované zariadenie\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"too many devices\"\nmsgstr \"príliš veľa zariadení\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"sequence timeout\"\nmsgstr \"vypršal časový limit sekvencie\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid \"Firmware\"\nmsgstr \"Firmvér\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Bootloader\"\nmsgstr \"Bootloader\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Hardware\"\nmsgstr \"Hardvér\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Other\"\nmsgstr \"Ďalší\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Left Button\"\nmsgstr \"Ľavé tlačidlo\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"Right Button\"\nmsgstr \"Pravé tlačidlo\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Middle Button\"\nmsgstr \"Stredné tlačidlo\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Back Button\"\nmsgstr \"Tlačidlo Späť\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Forward Button\"\nmsgstr \"Tlačidlo Dopredu\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Mouse Gesture Button\"\nmsgstr \"Tlačidlo gesta myši\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Smart Shift\"\nmsgstr \"Inteligentné Prepínanie\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"DPI Switch\"\nmsgstr \"Prepínač DPI\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Left Tilt\"\nmsgstr \"Náklon Vľavo\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Right Tilt\"\nmsgstr \"Náklon Vpravo\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Left Click\"\nmsgstr \"Ľavý klik\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Right Click\"\nmsgstr \"Pravý klik\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid \"Mouse Middle Button\"\nmsgstr \"Stredné tlačidlo myši\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"Mouse Back Button\"\nmsgstr \"Tlačidlo Späť na myši\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"Mouse Forward Button\"\nmsgstr \"Tlačidlo Dopredu na myši\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid \"Gesture Button Navigation\"\nmsgstr \"Tlačidlo navigácie gestami\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"Ľavé tlačidlo rolovania na myši\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"Pravé tlačidlo rolovania na myši\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid \"pressed\"\nmsgstr \"stlačnené\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid \"released\"\nmsgstr \"uvoľnené\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid \"pairing lock is closed\"\nmsgstr \"zámok párovania bol uzatvorený\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid \"pairing lock is open\"\nmsgstr \"zámok párovania bol otvorený\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid \"discovery lock is closed\"\nmsgstr \"zámok objavovania je uzatvorený\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid \"discovery lock is open\"\nmsgstr \"zámok objavovania je otvorený\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid \"connected\"\nmsgstr \"pripojené\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid \"disconnected\"\nmsgstr \"odpojené\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid \"unpaired\"\nmsgstr \"nespárované\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid \"powered on\"\nmsgstr \"zapnuté\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid \"register\"\nmsgstr \"prihlásiť\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid \"feature\"\nmsgstr \"vlastnosť\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid \"Swap Fx function\"\nmsgstr \"Prepnúť funkciu Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"Ak je nastavené, budú klávesy F1..F12 zapínať ich špeciálne \"\n\"funkcie.\\n\"\n\"Pre aktiváciu ich štandardnej funkcie budete musieť súčasne stlačiť \"\n\"Fn.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"Ak nie je nastavené, budú klávesy F1..F12 zapínať ich štandardné \"\n\"funkcie.\\n\"\n\"Pre aktiváciu špeciálnych funkcií budete musieť súčasne stlačiť Fn.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid \"Hand Detection\"\nmsgstr \"Detekcia rúk\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"Zapne podsvietenie, keď sa nad klávesnicou objavia ruky.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"Plynulé skrolovanie\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"Vysokocitlivý režim zvislého posunu kolieska myši.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid \"Side Scrolling\"\nmsgstr \"Bočné skrolovanie\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button \"\n\"events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"Ak je vypnuté, bočné stlačenie kolieska vygeneruje vlastné udalosti \"\n\"tlačidiel\\n\"\n\"namiesto štandardných udalostí skrolovania do strán.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"Citlivosť (DPI - staršie myši)\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"Citlivosť kurzora myši\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid \"Backlight\"\nmsgstr \"Podsvietenie\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"Nastaviť čas podsvietenia klávesnice\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid \"Turn illumination on or off on keyboard.\"\nmsgstr \"Vypne/zapne podsvietenie klávesnice.\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"Vysoké rozlíšenie skrolovania myši\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"\"\n\"Nastavte na ignorovanie ak je rolovanie neprimerane rýchle alebo pomalé\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"Odklonenie rolovacieho kolieska\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n\"trigger Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Nech rolovacie koliesko posiela LOWRES_WHEEL HID++ notifikácie (ktoré spúšťajú\"\n\" pravidlá v Solaare ale inak sú ignorované).\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"Smer skrolovania\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"Zmeniť zmer zvislého skrolovania myši.\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"Rozlíšenie skrolovania myši\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n\"trigger Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Nech rolovacie koliesko posiela HIRES_WHEEL HID++ notifikácie (ktoré spúšťajú \"\n\"pravidlá v Solaare ale inak sú ignorované).\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"Citlivosť (rýchlosť kurzora)\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"Násobič rýchlosti myši (256 je bežný násobič).\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"Odchylka palcového kolieska\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Nech rolovacie koliesko posiela THUMB_WHEEL HID++ notifikácie (ktoré spúšťajú \"\n\"pravidlá v Solaare ale inak sú ignorované).\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"Smer posuvného kolieska\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"Zmeniť smer otáčania kolieska.\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid \"Onboard Profiles\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid \"\"\n\"Enable onboard profiles, which often control report rate and \"\n\"keyboard lighting\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid \"Polling Rate (ms)\"\nmsgstr \"Intenzita dopytovania (ms)\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid \"Frequency of device polling, in milliseconds\"\nmsgstr \"Frekvencia dopytov na zariadenie, v ms\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid \"Divert crown events\"\nmsgstr \"Odklonenie udalostí korunky\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Korunka bude zasielať CROWN HID++ notifikácie (tie aktivujú Solaar \"\n\"pravidlá, ale inak budú ignorované).\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid \"Crown smooth scroll\"\nmsgstr \"Hladké rolovanie korunky\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid \"Set crown smooth scroll\"\nmsgstr \"Nastavuje hladké rolovanie korunky\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid \"Divert G Keys\"\nmsgstr \"Odkloniť G klávesy\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid \"\"\n\"Make G keys send GKEY HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"G klávesy budú zasielať GKEY HID++ notifikácie (tie aktivujú Solaar \"\n\"pravidlá, ale inak budú ignorované).\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid \"May also make M keys and MR key send HID++ notifications\"\nmsgstr \"Umožniť aj klávesom M a MR posielať HID++ upozornenia\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"Rapkavé rolovacie koliesko\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and \"\n\"always freespin.\"\nmsgstr \"\"\n\"Prepína koliesko myši medzi rapkaním v závislosti od rýchlosti a voľnobehom.\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid \"Freespinning\"\nmsgstr \"Voľnobeh\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid \"Ratcheted\"\nmsgstr \"Rapkanie\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"Rýchlosť rapkania rolovacieho kolieska\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and \"\n\"freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"Použiť rýchlosť kolieska myši na prepínanie medzi rapkaním a voľnobehom.\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid \"Key/Button Actions\"\nmsgstr \"Akcie klávesu/tlačidla\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid \"Change the action for the key or button.\"\nmsgstr \"Zmeniť akciu klávesy alebo tlačidla.\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid \"Overridden by diversion.\"\nmsgstr \"Obídené nastavením odklonenia\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"\"\n\"Zmenou dôležitej akcie (napríklad pre ľavé tlačidlo myši) môžete \"\n\"systém uviesť do stavu, kedy sa nebude dať používať.\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid \"Key/Button Diversion\"\nmsgstr \"Odklonenie klávesu/tlačidla\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or \"\n\"initiate Mouse Gestures or Sliding DPI\"\nmsgstr \"\"\n\"Nech kláves alebo tlačidlo posiela HID++ upozornenia (Odklonené) alebo spustí \"\n\"gestá myši alebo posunie DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid \"Diverted\"\nmsgstr \"Odklonené\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid \"Mouse Gestures\"\nmsgstr \"Gestá myši\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid \"Regular\"\nmsgstr \"Normálne\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid \"Sliding DPI\"\nmsgstr \"Posun DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"Citlivosť (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid \"Sensitivity Switching\"\nmsgstr \"Prepínanie citlivosti\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when \"\n\"the key or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current \"\n\"sensitivity\"\nmsgstr \"\"\n\"Stlačením klávesu alebo tlačidla, prepínať súčasnú citlivosť a zapamätanú citl\"\n\"ivosť.\\n\"\n\"Ak nie je zapamätaná citlivosť, tak si len zapamätá súčasnú citlivosť.\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid \"Off\"\nmsgstr \"Vyp\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid \"Disable keys\"\nmsgstr \"Zakázať klávesy\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"Zakázať špecifické klávesy.\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"Zakáže %s kláves.\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid \"Set OS\"\nmsgstr \"Nastaviť OS\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid \"Change keys to match OS.\"\nmsgstr \"Zmeniť klávesy podľa operačného systému.\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid \"Change Host\"\nmsgstr \"Zmeniť hostiteľa\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid \"Switch connection to a different host\"\nmsgstr \"Prepnúť spojenie na iného hostiteľa\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid \"Performs a left click.\"\nmsgstr \"Vykoná kliknutie ľavým tlačidlom.\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid \"Single tap\"\nmsgstr \"Dotyk\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid \"Performs a right click.\"\nmsgstr \"Vykoná kliknutie pravým tlačidlom.\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid \"Single tap with two fingers\"\nmsgstr \"Dotyk dvoma prstami\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid \"Single tap with three fingers\"\nmsgstr \"Dotyk tromi prstami\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid \"Double tap\"\nmsgstr \"Dvojdotyk\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid \"Performs a double click.\"\nmsgstr \"Vykoná dvojité kliknutie.\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid \"Double tap with two fingers\"\nmsgstr \"Dvojdotyk dvoma prstami\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid \"Double tap with three fingers\"\nmsgstr \"Dvojdotyk troma prstami\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"Presúvanie položiek ťahaním prstu po dvojdotyku.\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid \"Tap and drag\"\nmsgstr \"Ťahaj a pusti\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"Presúvanie položiek ťahaním prstov po dvojdotyku.\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"Dotyk a ťahanie dvomi prstami\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"Dotyk a ťahanie tromi prstami\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"Vypnúť gestá dotyku a hrany (ekvivalent stlačenia Fn + ľavý klik).\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"Potlačiť gestá dotyku a hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid \"Scroll with one finger\"\nmsgstr \"Skrolovanie jedným prstom\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid \"Scrolls.\"\nmsgstr \"Skrolovania.\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid \"Scroll with two fingers\"\nmsgstr \"Skrolovanie dvoma prstami\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"Vodorovné skrolovanie dvoma prstami\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid \"Scrolls horizontally.\"\nmsgstr \"Vodorovné skrolovanie.\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"Zvislé skrolovanie dvoma prstami\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid \"Scrolls vertically.\"\nmsgstr \"Zvislé skrolovanie.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"Zmeniť smer otáčania.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid \"Natural scrolling\"\nmsgstr \"Prirodzené skrolovanie\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"Povoliť koliesko.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid \"Thumbwheel\"\nmsgstr \"Koliesko\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid \"Swipe from the top edge\"\nmsgstr \"Ťahanie z hornej hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid \"Swipe from the left edge\"\nmsgstr \"Ťahanie z ľavej hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid \"Swipe from the right edge\"\nmsgstr \"Ťahanie z pravej hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"Ťahanie zo spodnej hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"Ťahanie dvoma prstami z ľavej hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"Ťahanie dvoma prstami z pravej hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"Ťahanie dvoma prstami zo spodnej hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"Ťahanie dvoma prstami z hornej hrany\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"Zovrieť pre priblíženie; rozovrieť pre oddialenie.\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid \"Zoom with two fingers.\"\nmsgstr \"Priblíženie dvoma prstami.\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid \"Pinch to zoom out.\"\nmsgstr \"Zovrieť pre priblíženie.\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid \"Spread to zoom in.\"\nmsgstr \"Rozovrieť pre oddialenie.\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid \"Zoom with three fingers.\"\nmsgstr \"Priblíženie troma prstami.\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid \"Zoom with two fingers\"\nmsgstr \"Priblíženie dvoma pstami\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid \"Pixel zone\"\nmsgstr \"Pixlová oblasť\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid \"Ratio zone\"\nmsgstr \"Pomerná oblasť\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid \"Scale factor\"\nmsgstr \"Faktor mierky\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid \"Sets the cursor speed.\"\nmsgstr \"Nastavuje rýchlosť kurzora.\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid \"Left\"\nmsgstr \"Vľavo\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid \"Left-most coordinate.\"\nmsgstr \"Súradnica najviac vľavo.\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid \"Bottom\"\nmsgstr \"Spodok\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid \"Bottom coordinate.\"\nmsgstr \"Úplne spodná súradnica.\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid \"Width\"\nmsgstr \"Šírka\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid \"Width.\"\nmsgstr \"Šírka.\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid \"Height\"\nmsgstr \"Výška\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid \"Height.\"\nmsgstr \"Výška.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid \"Cursor speed.\"\nmsgstr \"Rýchlosť kurzora.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid \"Scale\"\nmsgstr \"Mierka\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid \"Gestures\"\nmsgstr \"Gestá\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"Upraviť správanie myši/touchpadu.\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid \"Gestures Diversion\"\nmsgstr \"Odklon gest\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"Odkloniť gestá myši/touchpadu.\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid \"Gesture params\"\nmsgstr \"Parametre gesta\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"Zmeňte číselné parametre myši/touchpadu.\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid \"M-Key LEDs\"\nmsgstr \"LEDky M-Key\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"Ovládanie LED svetla klávesu M-Key\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"Môže vyžadovať odklon G Klávesov aby to fungovalo.\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"Rozsvieti kláves %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid \"MR-Key LED\"\nmsgstr \"MR-Key LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"Ovláda LEDky klávesu MR-Key.\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"Trvalé mapovanie Klávesov/Tlačidiel\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"Natrvalo zmeniť mapovanie pre kláves alebo tlačidlo.\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse \"\n\"button) can result in an unusable system.\"\nmsgstr \"\"\n\"Zmena dôležitých klávesov alebo tlačidiel (ako je Ľavé tlačidlo myši) môže sko\"\n\"nčiť nepoužiteľným systémom.\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid \"Sidetone\"\nmsgstr \"Bočný odtieň\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid \"Set sidetone level.\"\nmsgstr \"Nastavenie bočného odtieňa.\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid \"Equalizer\"\nmsgstr \"Ekvalizér\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid \"Set equalizer levels.\"\nmsgstr \"Nastavenie úrovne ekvalizéru.\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid \"Hz\"\nmsgstr \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid \"Power Management\"\nmsgstr \"Správa napájania\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"Minúty do vypnutia (0 znamená nikdy)\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid \"No paired devices.\"\nmsgstr \"Žiadne spárované zariadenia.\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s spárované zariadenie.\"\nmsgstr[1] \"%(count)s spárované zariadenia.\"\nmsgstr[2] \"%(count)s spárovaných zariadení.\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid \"Battery: %(level)s\"\nmsgstr \"Batéria: %(level)s\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid \"Battery: %(percent)d%%\"\nmsgstr \"Batéria: %(percent)d%%\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid \"Lighting: %(level)s lux\"\nmsgstr \"Osvetlenie: %(level)s lux\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"Batéria: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"Batéria: %(percent)d%% (%(status)s)\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid \"Permissions error\"\nmsgstr \"Chyba oprávnenia\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have \"\n\"permission to open it.\"\nmsgstr \"\"\n\"Našiel sa prijímač alebo zariadenie Logitech (%s), ale nemal oprávnenie na jeh\"\n\"o otvorenie.\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or \"\n\"device and then reconnecting it.\"\nmsgstr \"\"\n\"Ak ste práve nainštalovali Solaar, skúste odpojiť prijímač alebo zariadenie a \"\n\"znova ho pripojiť.\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid \"Cannot connect to device error\"\nmsgstr \"Chyba počas pripájania k zariadeniu\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"Našiel sa Logitech prijímač alebo zariadenie na %s, ale pri pokuse o \"\n\"pripojenie nastala chyba.\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it \"\n\"off and then on.\"\nmsgstr \"\"\n\"Skúste odpojiť zariadenie a potom ho opätovne pripojiť alebo ho skúste vypnúť \"\n\"a zase zapnúť.\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid \"Unpairing failed\"\nmsgstr \"Rušenie spárovania skončilo s chybou\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"Zlyhalo zrušenie spárovania zariadenia %{device} k %{receiver}.\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"Prijímač vrátil chybu, ale nie sú dostupné žiadne podrobnosti o nej.\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"Iný proces Solaaru uz beží, takže len odkryte jeho okno\"\n\n#: lib/solaar/ui/about.py:36\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"Správa prijímačov Logitech,\\n\"\n\"klávesníc, myší a tabletov.\"\n\n#: lib/solaar/ui/about.py:44\nmsgid \"Additional Programming\"\nmsgstr \"Dodatočné programovanie\"\n\n#: lib/solaar/ui/about.py:45\nmsgid \"GUI design\"\nmsgstr \"Návrh GUI\"\n\n#: lib/solaar/ui/about.py:47\nmsgid \"Testing\"\nmsgstr \"Testovanie\"\n\n#: lib/solaar/ui/about.py:54\nmsgid \"Logitech documentation\"\nmsgstr \"Dokumentácia Logitechu\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid \"Unpair\"\nmsgstr \"Zrušiť párovanie\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid \"Cancel\"\nmsgstr \"Zrušiť\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid \"Complete - ENTER to change\"\nmsgstr \"\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid \"Incomplete\"\nmsgstr \"\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d hodnota\"\nmsgstr[1] \"%d hodnoty\"\nmsgstr[2] \"%d hodnôt\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid \"Changes allowed\"\nmsgstr \"Zmeny sú povolené\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid \"No changes allowed\"\nmsgstr \"Zmeny nie sú povolené\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid \"Ignore this setting\"\nmsgstr \"Ignorovať toto nastavenie\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid \"Working\"\nmsgstr \"Pracujem\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid \"Read/write operation failed.\"\nmsgstr \"Operácia čítania/zápisu zlyhala.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid \"Built-in rules\"\nmsgstr \"Zabudované pravidlá\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid \"User-defined rules\"\nmsgstr \"Používateľom definované pravidlá\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid \"Rule\"\nmsgstr \"Pravidlo\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid \"Sub-rule\"\nmsgstr \"Podpravidlo\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid \"[empty]\"\nmsgstr \"[prázdne]\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Editor pravidiel Solaar\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid \"Make changes permanent?\"\nmsgstr \"Označiť zmeny ako trvalé?\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid \"Yes\"\nmsgstr \"Áno\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid \"No\"\nmsgstr \"Nie\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"\"\n\"Ak vyberiete Nie, zmeny, ktoré ste vykonali sa po ukončení \"\n\"aplikácie, stratia.\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid \"Save changes\"\nmsgstr \"Uložiť zmeny\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid \"Discard changes\"\nmsgstr \"Zahodiť zmeny\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid \"Insert here\"\nmsgstr \"Vložiť sem\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid \"Insert above\"\nmsgstr \"Vložiť nad\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid \"Insert below\"\nmsgstr \"Vložiť pod\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid \"Insert new rule here\"\nmsgstr \"Vložiť nové pravidlo sem\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid \"Insert new rule above\"\nmsgstr \"Vložiť nové pravidlo nad\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid \"Insert new rule below\"\nmsgstr \"Vložiť nové pravidlo pod\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid \"Paste here\"\nmsgstr \"Vložiť sem\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid \"Paste above\"\nmsgstr \"Vložiť nad\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid \"Paste below\"\nmsgstr \"Vložiť pod\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid \"Paste rule here\"\nmsgstr \"Vložiť pravidlo sem\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid \"Paste rule above\"\nmsgstr \"Vložiť pravidlo nad\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid \"Paste rule below\"\nmsgstr \"Vložiť pravidlo pod\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid \"Paste rule\"\nmsgstr \"Vložiť pravidlo\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid \"Flatten\"\nmsgstr \"Sploštiť\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid \"Insert\"\nmsgstr \"Vložiť\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid \"Or\"\nmsgstr \"Alebo\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid \"And\"\nmsgstr \"A\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid \"Condition\"\nmsgstr \"Podmienka\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid \"Feature\"\nmsgstr \"Vlastnosť\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid \"Report\"\nmsgstr \"Hlásenie\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid \"Process\"\nmsgstr \"Proces\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid \"Mouse process\"\nmsgstr \"Proces myši\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid \"Modifiers\"\nmsgstr \"Modifikátory\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid \"Key\"\nmsgstr \"Kláves\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid \"KeyIsDown\"\nmsgstr \"KlávesJeStlačený\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid \"Active\"\nmsgstr \"Aktívne\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid \"Device\"\nmsgstr \"Zariadenie\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid \"Host\"\nmsgstr \"Hostiteľ\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid \"Setting\"\nmsgstr \"Nastavenie\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid \"Test\"\nmsgstr \"Test\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid \"Test bytes\"\nmsgstr \"Test bajtov\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid \"Mouse Gesture\"\nmsgstr \"Gesto myši\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid \"Action\"\nmsgstr \"Akcia\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid \"Key press\"\nmsgstr \"Stlačenie klávesu\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid \"Mouse scroll\"\nmsgstr \"Skrolovanie kolieskom\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid \"Mouse click\"\nmsgstr \"Kliknutie myšou\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid \"Set\"\nmsgstr \"Nastaviť\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid \"Execute\"\nmsgstr \"Spustiť program\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid \"Later\"\nmsgstr \"Neskôr\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid \"Insert new rule\"\nmsgstr \"Vložiť nové pravidlo\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid \"Delete\"\nmsgstr \"Odstrániť\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid \"Negate\"\nmsgstr \"Negovať\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid \"Wrap with\"\nmsgstr \"Obaliť čím\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid \"Cut\"\nmsgstr \"Vystrihnúť\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid \"Paste\"\nmsgstr \"Vložiť\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid \"Copy\"\nmsgstr \"Kopírovať\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"Vybraný komponent nie je editorom ešte podporovaný.\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid \"Number of seconds to delay.\"\nmsgstr \"Počet sekúnd oneskorenia.\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid \"Not\"\nmsgstr \"Opak\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"Aktývny proces X11. Len pre použitie v X11.\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"Proces myši X11. Len pre použitie v X11.\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid \"MouseProcess\"\nmsgstr \"ProcesMyši\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"Názov funkcie upozornenia, ktorá spúšťa spracovanie pravidla.\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"Počet upozornení, ktoré spúšťajú spracovanie pravidla.\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"Aktívne modifikátory klávesnice. Vo Waylande nie sú vždy dostupné.\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n\"keys and buttons.\"\nmsgstr \"\"\n\"Odklonený kláves alebo tlačidlo stlačené alebo uvoľnené.\\n\"\n\"Použiť Odklonenie Klávesu/Tlačidla a Odkloniť nastavenie G Klávesov pre odklon\"\n\"enie klávesov a tlačidiel.\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid \"Key down\"\nmsgstr \"Kláves stlačený\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid \"Key up\"\nmsgstr \"Kláves uvoľnený\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n\"keys and buttons.\"\nmsgstr \"\"\n\"Odklonený kláves alebo tlačidlo je práve stlačené.\\n\"\n\"Použiť Odklon Klávesov/Tlačidiel a Odkloniť nastavenie G Klávesov na odkloneni\"\n\"e klávesov a tlačidiel.\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid \"Parameter\"\nmsgstr \"Parameter\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid \"begin (inclusive)\"\nmsgstr \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid \"end (exclusive)\"\nmsgstr \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid \"range\"\nmsgstr \"rozsah\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid \"minimum\"\nmsgstr \"minimum\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid \"maximum\"\nmsgstr \"maximum\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid \"mask\"\nmsgstr \"maska\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid \"type\"\nmsgstr \"typ\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or \"\n\"more mouse movements.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid \"Add movement\"\nmsgstr \"Pridať pohyb\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid \"Add key\"\nmsgstr \"Pridať kláves\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid \"Click\"\nmsgstr \"Kliknutie\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid \"Depress\"\nmsgstr \"Stlačiť\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid \"Release\"\nmsgstr \"Uvoľniť\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simulovať rolovanie myši.\\n\"\n\"Vo Waylande vyžaduje právo na zápis do /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simulovať kliknutie myši.\\n\"\n\"Vo Waylande vyžaduje právo na zápis do /dev/uinput.\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid \"Button\"\nmsgstr \"Tlačidlo\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid \"Count and Action\"\nmsgstr \"Počet a Akcia\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid \"Execute a command with arguments.\"\nmsgstr \"Vykonať príkaz s argumentami.\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid \"Add argument\"\nmsgstr \"Pridať argument\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid \"Toggle\"\nmsgstr \"Prepínač\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid \"True\"\nmsgstr \"Pravda\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid \"False\"\nmsgstr \"Nepravda\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid \"Unsupported setting\"\nmsgstr \"Nepodporované nastavenie\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid \"Originating device\"\nmsgstr \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"Zariadenie je aktívne a jeho nastavenia možno meniť.\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid \"Device that originated the current notification.\"\nmsgstr \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid \"Name of host computer.\"\nmsgstr \"Názov hostiteľského počítača.\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid \"Value\"\nmsgstr \"Hodnota\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid \"Item\"\nmsgstr \"Položka\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid \"Change setting on device\"\nmsgstr \"Zmeniť nastavenie na zariadení\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid \"Setting on device\"\nmsgstr \"Nastavenie na zariadení\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid \"offline\"\nmsgstr \"offline\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: spárovať nové zariadenie\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"Vložte tajný kód na %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"Napíšte %(passcode)s a potom stlačte kláves Enter.\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid \"left\"\nmsgstr \"vľavo\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid \"right\"\nmsgstr \"vpravo\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"Stlačte %(code)s\\n\"\n\"a potom stlačte ľavé a pravé tlačidlo súčasne.\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid \"Pairing failed\"\nmsgstr \"Párovanie skončilo s chybou\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid \"\"\n\"Make sure your device is within range, and has a decent battery \"\n\"charge.\"\nmsgstr \"Uistite sa, že je zariadenie v dosahu a je dostatočne nabité.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid \"\"\n\"A new device was detected, but it is not compatible with this \"\n\"receiver.\"\nmsgstr \"\"\n\"Bolo zistené nové zariadenie, ale nie je kompatibilné s týmto \"\n\"prijímačom.\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"Viac pripojených zariadení ako dokáže prijímač zvládnuť.\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid \"No further details are available about the error.\"\nmsgstr \"Ďalšie podrobnosti o chybe nie sú dostupné.\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid \"Found a new device:\"\nmsgstr \"Nájdené nové zariadenie:\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"Bezdrôtové pripojenie nepoužíva šifrovanie\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"Unifying prijímače sú kompatibilné len s Unifying zariadeniami.\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Bolt prijímače sú kompatibilné len s Bolt zariadeniami.\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"Ostatné prijímače sú kompatibilné len s máloktorými zariadeniami.\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"Zariadenie nesmie byť spárované s nedaľekým zapnutým prijímačom.\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid \"\"\n\"Press a pairing button or key until the pairing light flashes \"\n\"quickly.\"\nmsgstr \"\"\n\"Stlačte párovacie tlačidlo alebo kláves kým rýchlo nezabliká párovacie svetlo.\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid \"You may have to first turn the device off and on again.\"\nmsgstr \"Možno bude treba najprv zariadenie vypnuť a znova zapnúť.\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid \"Turn on the device you want to pair.\"\nmsgstr \"Zapnite zariadenie, ktoré chcete spárovať.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"Ak je zariadenie už zapnuté, vypnite ho a opäť zapnite.\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"Tomuto prijímaču ostáva ešte %d párovanie.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"Tomuto prijímaču ostáva ešte %d párovania.\"\nmsgstr[2] \"\"\n\"\\n\"\n\"\\n\"\n\"Tomuto prijímaču ostáva ešte %d párovaní.\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"Ak proces teraz zrušíte, spárovanie sa nespotrebuje.\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid \"No supported device found\"\nmsgstr \"Nenašlo sa podporované zariadenie\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid \"About %s\"\nmsgstr \"O programe %s\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"Ukončiť %s\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid \"no receiver\"\nmsgstr \"bez prijímača\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid \"no status\"\nmsgstr \"žiaden stav\"\n\n#: lib/solaar/ui/window.py:96\nmsgid \"Scanning\"\nmsgstr \"Hľadá sa\"\n\n#: lib/solaar/ui/window.py:129\nmsgid \"Battery\"\nmsgstr \"Batéria\"\n\n#: lib/solaar/ui/window.py:132\nmsgid \"Wireless Link\"\nmsgstr \"Bezdrôtové prepojenie\"\n\n#: lib/solaar/ui/window.py:136\nmsgid \"Lighting\"\nmsgstr \"Osvetlenie\"\n\n#: lib/solaar/ui/window.py:170\nmsgid \"Show Technical Details\"\nmsgstr \"Zobraziť technické podrobnosti\"\n\n#: lib/solaar/ui/window.py:186\nmsgid \"Pair new device\"\nmsgstr \"Spárovať nové zariadenie\"\n\n#: lib/solaar/ui/window.py:205\nmsgid \"Select a device\"\nmsgstr \"Vyberte zariadenie\"\n\n#: lib/solaar/ui/window.py:322\nmsgid \"Rule Editor\"\nmsgstr \"Editor pravidiel\"\n\n#: lib/solaar/ui/window.py:533\nmsgid \"Path\"\nmsgstr \"Cesta\"\n\n#: lib/solaar/ui/window.py:536\nmsgid \"USB ID\"\nmsgstr \"USB ID\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid \"Serial\"\nmsgstr \"Sériové číslo\"\n\n#: lib/solaar/ui/window.py:545\nmsgid \"Index\"\nmsgstr \"Index\"\n\n#: lib/solaar/ui/window.py:547\nmsgid \"Wireless PID\"\nmsgstr \"Bezdrôt. PID\"\n\n#: lib/solaar/ui/window.py:549\nmsgid \"Product ID\"\nmsgstr \"Identifikátor produktu\"\n\n#: lib/solaar/ui/window.py:551\nmsgid \"Protocol\"\nmsgstr \"Protokol\"\n\n#: lib/solaar/ui/window.py:551\nmsgid \"Unknown\"\nmsgstr \"Neznámy\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#: lib/solaar/ui/window.py:554\nmsgid \"Polling rate\"\nmsgstr \"Intenzita dopytovania\"\n\n#: lib/solaar/ui/window.py:565\nmsgid \"Unit ID\"\nmsgstr \"Číslo (ID) jednotky\"\n\n#: lib/solaar/ui/window.py:576\nmsgid \"none\"\nmsgstr \"žiadne\"\n\n#: lib/solaar/ui/window.py:577\nmsgid \"Notifications\"\nmsgstr \"Notifikácie\"\n\n#: lib/solaar/ui/window.py:621\nmsgid \"No device paired.\"\nmsgstr \"Žiadne spárované zariadenie.\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"K tomuto prijímaču môžete pripojiť %(max_count)s zariadenie.\"\nmsgstr[1] \"\"\n\"K tomuto prijímaču môžete pripojiť až %(max_count)s \"\n\"zariadenia.\"\nmsgstr[2] \"\"\n\"K tomuto prijímaču môžete pripojiť až %(max_count)s \"\n\"zariadení.\"\n\n#: lib/solaar/ui/window.py:634\nmsgid \"Only one device can be paired to this receiver.\"\nmsgstr \"K tomuto prijímaču sa dá pripojiť len jedno zariadenie.\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"Tomuto prijímaču ostáva %d párovanie.\"\nmsgstr[1] \"Tomuto prijímaču ostávajú %d párovania.\"\nmsgstr[2] \"Tomuto prijímaču ostáva %d párovaní.\"\n\n#: lib/solaar/ui/window.py:692\nmsgid \"Battery Voltage\"\nmsgstr \"Napätie batérie\"\n\n#: lib/solaar/ui/window.py:694\nmsgid \"Voltage reported by battery\"\nmsgstr \"Napätie hlásené batériou\"\n\n#: lib/solaar/ui/window.py:696\nmsgid \"Battery Level\"\nmsgstr \"Úroveň batérie\"\n\n#: lib/solaar/ui/window.py:698\nmsgid \"Approximate level reported by battery\"\nmsgstr \"Približná úroveň hlásená batériou\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid \"next reported \"\nmsgstr \"ďalšie hlásené \"\n\n#: lib/solaar/ui/window.py:708\nmsgid \" and next level to be reported.\"\nmsgstr \" a ďalšia úroveň, ktorá bude hlásená.\"\n\n#: lib/solaar/ui/window.py:713\nmsgid \"last known\"\nmsgstr \"naposledy známa\"\n\n#: lib/solaar/ui/window.py:724\nmsgid \"encrypted\"\nmsgstr \"šifrované\"\n\n#: lib/solaar/ui/window.py:726\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"Bezdrôtové spojenie medzi zariadením a prijímačom je šifrované.\"\n\n#: lib/solaar/ui/window.py:728\nmsgid \"not encrypted\"\nmsgstr \"bez šifrovania\"\n\n#: lib/solaar/ui/window.py:732\nmsgid \"\"\n\"The wireless link between this device and its receiver is not \"\n\"encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security \"\n\"issue for text-input devices.\"\nmsgstr \"\"\n\"Bezdrôtové prepojenie tohto zariadenia s jeho prijímačom nie je šifrované.\\n\"\n\"To je bezpečnostný problém pre ukazovacie zariadenia a závažný bezpečnostný pr\"\n\"oblém pre textové vstupné zariadenia.\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d lux\"\n\n#~ msgid        \"About\"\n#~ msgstr       \"O programe\"\n\n#~ msgid        \"Add action\"\n#~ msgstr       \"Pridať akciu\"\n\n#~ msgid        \"Adjust the DPI by sliding the mouse horizontally while \"\n#~      \"holding the DPI button.\"\n#~ msgstr       \"Upraviť DPI pohybom myši vo vodorovnom smere pri súčasnom \"\n#~      \"držaní tlačidla DPI.\"\n\n#~ msgid        \"Adjust the DPI by sliding the mouse horizontally while \"\n#~      \"holding the button down.\"\n#~ msgstr       \"Úprava DPI pohybom myši vo vodorovnom smere pri súčasnom \"\n#~      \"držaní tlačidla.\"\n\n#~ msgid        \"Automatically switch the mouse wheel between ratchet and \"\n#~      \"freespin mode.\\n\"\n#~      \"The mouse wheel is always free at 0, and always ratcheted at 50\"\n#~ msgstr       \"Automaticky prepnúť režim kolieska myši medzi krokovaním a \"\n#~      \"voľným otáčaním.\\n\"\n#~      \"Koliesko je pri hodnote 0 vždy voľné a pri hodnote 50 vždy krokuje\"\n\n#~ msgid        \"Battery information unknown.\"\n#~ msgstr       \"Informácie o batérii nie sú známe.\"\n\n#~ msgid        \"Click to allow changes.\"\n#~ msgstr       \"Kliknite pre povolenie zmien.\"\n\n#~ msgid        \"Click to prevent changes.\"\n#~ msgstr       \"Kliknite pre zakázanie zmien.\"\n\n#~ msgid        \"Count\"\n#~ msgstr       \"Počet\"\n\n#~ msgid        \"DPI Sliding Adjustment\"\n#~ msgstr       \"Úprava DPI pomocou myši\"\n\n#~ msgid        \"ERROR: \"\n#~ msgstr       \"CHYBA: \"\n\n#~ msgid        \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr       \"Vypne skrolovanie palcom v Linuxe.\"\n\n#~ msgid        \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr       \"Vypne skrolovanie kolieskom myši v Linuxe.\"\n\n#~ msgid        \"For more information see the Solaar installation directions\\n\"\n#~      \"at https://pwr-solaar.github.io/Solaar/installation\"\n#~ msgstr       \"Ďalšie informácie o inštalácii Solaaru nájdete na\\n\"\n#~      \"https://pwr-solaar.github.io/Solaar/installation\"\n\n#, python-format\n#~ msgid        \"Found a Logitech Receiver (%s), but did not have permission \"\n#~      \"to open it.\"\n#~ msgstr       \"Nájdený prijímač Logitech (%s), ale chýbajú práva na jeho \"\n#~      \"otvorenie.\"\n\n#~ msgid        \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr       \"HID++ režim pre vodorovný posun pomocou kolieska.\"\n\n#~ msgid        \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr       \"HID++ režim pre vertikálne skrolovanie myši.\"\n\n#~ msgid        \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr       \"Ak je zariadenie už zapnuté, vypnite ho a znovu zapnite.\"\n\n#~ msgid        \"If you've just installed Solaar, try removing the receiver \"\n#~      \"and plugging it back in.\"\n#~ msgstr       \"Ak ste Solaar práve nainštalovali, skúste prijímač odpojiť a \"\n#~      \"znova pripojiť.\"\n\n#~ msgid        \"Make the key or button send HID++ notifications (which \"\n#~      \"trigger Solaar rules but are otherwise ignored).\"\n#~ msgstr       \"Kláves alebo tlačidlo budú zasielať HID++ notifikácie (tie \"\n#~      \"aktivujú Solaar pravidlá, ale inak budú ignorované).\"\n\n#~ msgid        \"No Logitech receiver found\"\n#~ msgstr       \"Nebol nájdený žiaden prijímač Logitech\"\n\n#~ msgid        \"Scroll Wheel HID++ Scrolling\"\n#~ msgstr       \"HID++ skrolovanie\"\n\n#~ msgid        \"Scroll Wheel Rachet\"\n#~ msgstr       \"Krokovanie kolieska\"\n\n#~ msgid        \"Send a gesture by sliding the mouse while holding the button \"\n#~      \"down.\"\n#~ msgstr       \"Pošlite gesto pohybom myši pri súčasnom držaní tlačidla.\"\n\n#~ msgid        \"Shows status of devices connected\\n\"\n#~      \"through wireless Logitech receivers.\"\n#~ msgstr       \"Zobrazí stav zariadení pripojených\\n\"\n#~      \"pomocou bezdrôtového prijímača Logitech.\"\n\n#~ msgid        \"Solaar depends on a udev file that is not present\"\n#~ msgstr       \"Solaar závisí na udev súbore, ktorý chýba\"\n\n#~ msgid        \"The wireless link between this device and its receiver is \"\n#~      \"not encrypted.\\n\"\n#~      \"\\n\"\n#~      \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~      \"security issue.\\n\"\n#~      \"\\n\"\n#~      \"It is, however, a major security issue for text-input devices \"\n#~      \"(keyboards, numpads),\\n\"\n#~      \"because typed text can be sniffed inconspicuously by 3rd parties \"\n#~      \"within range.\"\n#~ msgstr       \"Bezdrôtové spojenie medzi zariadením a prijímačom nie je \"\n#~      \"šifrované.\\n\"\n#~      \"\\n\"\n#~      \"Pri ukazovacích zariadeniach (myši, trackbally, trackpady) to \"\n#~      \"nepredstavuje veľký bezpečnostný problém.\\n\"\n#~      \"\\n\"\n#~      \"Avšak pri vstupných zariadeniach zadávajúcich text (klávesnica, \"\n#~      \"numerická \\n\"\n#~      \"klávesnica) to predstavuje veľké riziko z hľadiska bezpečnosti, \"\n#~      \"pretože \\n\"\n#~      \"písaný text môže byť nepozorovane zachytený treťou stranou, ak je \"\n#~      \"signál v jej dosahu.\"\n\n#~ msgid        \"Thumb Wheel HID++ Scrolling\"\n#~ msgstr       \"HID++ posun kolieskom\"\n\n#~ msgid        \"Top-most coordinate.\"\n#~ msgstr       \"Najvyššia súradnica.\"\n\n#~ msgid        \"Try removing the device and plugging it back in or turning \"\n#~      \"it off and then on.\"\n#~ msgstr       \"Skúste zariadenie odpojiť a znovu ho pripojiť alebo ho \"\n#~      \"skúste vypnúť a opätovne zapnúť.\"\n\n#~ msgid        \"height\"\n#~ msgstr       \"výška\"\n\n#~ msgid        \"top\"\n#~ msgstr       \"hore\"\n\n#~ msgid        \"unknown\"\n#~ msgstr       \"neznáme\"\n\n#~ msgid        \"width\"\n#~ msgstr       \"šírka\"\n"
  },
  {
    "path": "po/solaar.pot",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 1.1.19\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2026-03-05 14:00+0200\\n\"\n        \"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n        \"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n        \"Language-Team: LANGUAGE <LL@li.org>\\n\"\n        \"Language: \\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n\"\n\n#: lib/logitech_receiver/base_usb.py:52\nmsgid   \"Bolt Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:64\nmsgid   \"Unifying Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87\n#: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113\nmsgid   \"Nano Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:125\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/base_usb.py:136\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/common.py:649\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/common.py:652\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1048\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Disabled\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1049\nmsgid   \"Static\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1050\nmsgid   \"Pulse\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1051\nmsgid   \"Cycle\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1052\nmsgid   \"Boot\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1053\nmsgid   \"Demo\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1055\nmsgid   \"Breathe\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1058\nmsgid   \"Ripple\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1059\nmsgid   \"Decomposition\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1060\nmsgid   \"Signature1\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1061\nmsgid   \"Signature2\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1062\nmsgid   \"CycleS\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1126\nmsgid   \"Unknown Location\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1127\nmsgid   \"Primary\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1128\nmsgid   \"Logo\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1129\nmsgid   \"Left Side\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1130\nmsgid   \"Right Side\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1131\nmsgid   \"Combined\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1132\nmsgid   \"Primary 1\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1133\nmsgid   \"Primary 2\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1134\nmsgid   \"Primary 3\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1135\nmsgid   \"Primary 4\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1136\nmsgid   \"Primary 5\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/hidpp20.py:1137\nmsgid   \"Primary 6\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid   \"empty\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid   \"critical\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"low\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"average\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"good\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"full\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"discharging\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid   \"recharging\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700\nmsgid   \"charging\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"not charging\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"almost full\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid   \"charged\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"slow recharge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"invalid battery\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"thermal error\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"error\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"standard\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"fast\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"device timeout\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"device not supported\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid   \"too many devices\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid   \"sequence timeout\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555\nmsgid   \"Firmware\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"Bootloader\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"Hardware\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid   \"Other\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid   \"Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid   \"Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Smart Shift\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"DPI Switch\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Left Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Right Tilt\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Left Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Right Click\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"Mouse Back Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"pressed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"released\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid   \"connected\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid   \"disconnected\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:182\nmsgid   \"unpaired\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:231\nmsgid   \"powered on\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:283\nmsgid   \"ADC measurement notification\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:484\nmsgid   \"pairing lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:484\nmsgid   \"pairing lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:447\nmsgid   \"discovery lock is closed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/notifications.py:447\nmsgid   \"discovery lock is open\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/receiver.py:437\nmsgid   \"No paired devices.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\n\n#: lib/logitech_receiver/settings.py:602\nmsgid   \"register\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654\nmsgid   \"feature\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:138\nmsgid   \"Swap Fx function\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:141\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:146\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:154\nmsgid   \"Hand Detection\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:155\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:162\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:163\n#: lib/logitech_receiver/settings_templates.py:410\n#: lib/logitech_receiver/settings_templates.py:439\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:170\nmsgid   \"Side Scrolling\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:172\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:182\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:183\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Backlight Timed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:257\n#: lib/logitech_receiver/settings_templates.py:397\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Backlight\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:269\nmsgid   \"Illumination level on keyboard.  Changes made are only applied in \"\n        \"Manual mode.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Automatic\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:303\nmsgid   \"Manual\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:305\nmsgid   \"Enabled\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Backlight Level\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:312\nmsgid   \"Illumination level on keyboard when in Manual mode.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:369\nmsgid   \"Backlight Delay Hands Out\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:370\nmsgid   \"Delay in seconds until backlight fades out with hands away from \"\n        \"keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:378\nmsgid   \"Backlight Delay Hands In\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:379\nmsgid   \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:387\nmsgid   \"Backlight Delay Powered\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:388\nmsgid   \"Delay in seconds until backlight fades out with external power.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:396\nmsgid   \"Backlight (Seconds)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:408\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:412\n#: lib/logitech_receiver/settings_templates.py:441\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:419\n#: lib/logitech_receiver/settings_templates.py:450\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:428\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:429\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:437\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:452\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:461\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:462\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:472\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:474\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:483\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:484\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:504\nmsgid   \"Onboard Profiles\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:505\nmsgid   \"Enable an onboard profile, which controls report rate, sensitivity, \"\n        \"and button actions\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:549\n#: lib/logitech_receiver/settings_templates.py:582\nmsgid   \"Report Rate\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\nmsgid   \"Frequency of device movement reports\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1421\n#: lib/logitech_receiver/settings_templates.py:1452\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:612\nmsgid   \"Divert crown events\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:613\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:621\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:622\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:630\nmsgid   \"Divert G and M Keys\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:631\nmsgid   \"Make G and M keys send HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:646\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid   \"Freespinning\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid   \"Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:655\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:657\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:707\nmsgid   \"Scroll Wheel Ratchet Torque\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:708\nmsgid   \"Change the torque needed to overcome the ratchet.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:743\nmsgid   \"Key/Button Actions\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:745\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:747\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:749\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:925\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid   \"Diverted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\nmsgid   \"Mouse Gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid   \"Regular\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:928\nmsgid   \"Sliding DPI\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1123\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1125\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1129\nmsgid   \"Off\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1160\nmsgid   \"Disable keys\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1161\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1164\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1177\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid   \"Set OS\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1178\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1247\nmsgid   \"Change Host\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1248\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid   \"Performs a left click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid   \"Single tap\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid   \"Performs a right click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1274\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid   \"Double tap\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid   \"Performs a double click.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid   \"Tap and drag\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1291\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1292\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\nmsgid   \"Scroll with one finger\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid   \"Scrolls.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid   \"Natural scrolling\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid   \"Thumbwheel\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1311\n#: lib/logitech_receiver/settings_templates.py:1315\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1312\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1313\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1314\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1316\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1317\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1318\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1319\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1321\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1322\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1323\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1342\nmsgid   \"Pixel zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1343\nmsgid   \"Ratio zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid   \"Scale factor\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid   \"Left\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid   \"Bottom\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid   \"Width\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid   \"Width.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid   \"Height\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid   \"Height.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid   \"Cursor speed.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid   \"Scale\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1358\nmsgid   \"Gestures\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1359\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1375\nmsgid   \"Gestures Diversion\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1376\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1392\nmsgid   \"Gesture params\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1393\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1417\nmsgid   \"M-Key LEDs\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1419\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1423\n#: lib/logitech_receiver/settings_templates.py:1454\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1429\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1448\nmsgid   \"MR-Key LED\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1450\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1471\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1473\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1475\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1532\nmsgid   \"Sidetone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1533\nmsgid   \"Set sidetone level.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1542\nmsgid   \"Equalizer\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1543\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1565\nmsgid   \"Hz\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1571\nmsgid   \"Power Management\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1572\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1584\nmsgid   \"Brightness Control\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\nmsgid   \"Control overall brightness\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1628\n#: lib/logitech_receiver/settings_templates.py:1681\nmsgid   \"LED Control\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1629\n#: lib/logitech_receiver/settings_templates.py:1682\nmsgid   \"Switch control of LED zones between device and Solaar\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1644\n#: lib/logitech_receiver/settings_templates.py:1692\nmsgid   \"LED Zone Effects\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid   \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid   \"Set effect for LED Zone\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1647\nmsgid   \"Color\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1648\nmsgid   \"Speed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1649\nmsgid   \"Period\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1650\nmsgid   \"Intensity\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid   \"Ramp\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1666\nmsgid   \"LEDs\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1703\nmsgid   \"Per-key Lighting\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1704\nmsgid   \"Control per-key lighting.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1786\nmsgid   \"Force Sensing Buttons\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1787\nmsgid   \"Change the force required to activate button.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1804\nmsgid   \"Force Sensing Button\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1814\nmsgid   \"Haptic Feedback Level\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1815\nmsgid   \"Change power of haptic feedback.  (Zero to turn off.)\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1857\nmsgid   \"Play Haptic Waveform\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1858\nmsgid   \"Tell device to play a haptic waveform.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:120\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about/model.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about/model.py:64\nmsgid   \"Additional Programming\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about/model.py:65\nmsgid   \"GUI design\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about/model.py:67\nmsgid   \"Testing\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/about/model.py:75\nmsgid   \"Logitech documentation\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92\n#: lib/solaar/ui/window.py:208\nmsgid   \"Unpair\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Cancel\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/common.py:42\nmsgid   \"Permissions error\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/common.py:46\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/common.py:49\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/common.py:51\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/common.py:53\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/common.py:56\nmsgid   \"Unpairing failed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/common.py:58\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/common.py:63\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid   \"Incomplete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\n\n#: lib/solaar/ui/config_panel.py:642\nmsgid   \"Changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:643\nmsgid   \"No changes allowed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:644\nmsgid   \"Ignore this setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:690\nmsgid   \"Working\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/config_panel.py:693\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/desktop_notifications.py:112\nmsgid   \"unspecified reason\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid   \"Built-in rules\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid   \"User-defined rules\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382\n#: lib/solaar/ui/diversion_rules.py:509\nmsgid   \"Sub-rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:108\nmsgid   \"[empty]\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:132\nmsgid   \"Make changes permanent?\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:137\nmsgid   \"Yes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:139\nmsgid   \"No\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:144\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:273\nmsgid   \"Paste here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:275\nmsgid   \"Paste above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:277\nmsgid   \"Paste below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:283\nmsgid   \"Paste rule here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:285\nmsgid   \"Paste rule above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:287\nmsgid   \"Paste rule below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:291\nmsgid   \"Paste rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:306\nmsgid   \"Insert here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:308\nmsgid   \"Insert above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:310\nmsgid   \"Insert below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:316\nmsgid   \"Insert new rule here\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:318\nmsgid   \"Insert new rule above\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:320\nmsgid   \"Insert new rule below\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:347\nmsgid   \"Flatten\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:380\nmsgid   \"Insert\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511\n#: lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Or\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510\n#: lib/solaar/ui/diversion_rules.py:1144\nmsgid   \"And\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Condition\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154\nmsgid   \"Feature\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188\nmsgid   \"Report\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69\nmsgid   \"Process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:391\nmsgid   \"Mouse process\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225\nmsgid   \"Modifiers\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277\nmsgid   \"Key\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318\nmsgid   \"KeyIsDown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432\nmsgid   \"Active\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390\n#: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487\nmsgid   \"Device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506\nmsgid   \"Setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333\n#: lib/solaar/ui/rule_conditions.py:382\nmsgid   \"Test\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507\nmsgid   \"Test bytes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608\nmsgid   \"Mouse Gesture\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:405\nmsgid   \"Action\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138\nmsgid   \"Key press\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191\nmsgid   \"Mouse scroll\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256\nmsgid   \"Mouse click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:410\nmsgid   \"Set\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328\nmsgid   \"Execute\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189\nmsgid   \"Later\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Insert new rule\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82\n#: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556\nmsgid   \"Delete\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:483\nmsgid   \"Negate\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Wrap with\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Cut\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:553\nmsgid   \"Paste\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:559\nmsgid   \"Copy\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:668\nmsgid   \"Save changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:673\nmsgid   \"Discard changes\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1104\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1169\nmsgid   \"Number of seconds to delay.  Delay between 0 and 1 is done with \"\n        \"higher precision.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1207\nmsgid   \"Not\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1238\nmsgid   \"Toggle\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1239\nmsgid   \"True\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1240\nmsgid   \"False\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1253\nmsgid   \"Unsupported setting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415\n#: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748\n#: lib/solaar/ui/diversion_rules.py:1766\nmsgid   \"Originating device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1428\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1437\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1450\nmsgid   \"Name of host computer.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1520\nmsgid   \"Value\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1529\nmsgid   \"Item\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1808\nmsgid   \"Change setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1824\nmsgid   \"Setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:53\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:55\nmsgid   \"For most devices, turn on the device you want to pair.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:56\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:58\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid   \"For devices with multiple channels, press, hold, and release the \"\n        \"button for the channel you wish to pair\\n\"\n        \"or use the channel switch button to select a channel and then press, \"\n        \"hold, and release the channel switch button.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:68\nmsgid   \"The channel indicator light should be blinking rapidly.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:72\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\n\n#: lib/solaar/ui/pair_window.py:78\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:168\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:171\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid   \"left\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid   \"right\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:178\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:221\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:226\nmsgid   \"Found a new device:\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:247\nmsgid   \"Pairing failed\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:249\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:251\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:253\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:255\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_actions.py:54\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_actions.py:60\nmsgid   \"Add key\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_actions.py:63\nmsgid   \"Click\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_actions.py:66\nmsgid   \"Depress\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_actions.py:69\nmsgid   \"Release\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_actions.py:153\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_actions.py:211\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_actions.py:216\nmsgid   \"Button\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_actions.py:218\nmsgid   \"Action (and Count, if click)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_actions.py:269\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_actions.py:273\nmsgid   \"Add argument\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:52\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:82\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:99\nmsgid   \"MouseProcess\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:123\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:169\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:201\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:241\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:250\nmsgid   \"Key down\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:253\nmsgid   \"Key up\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:293\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:331\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:335\nmsgid   \"Parameter\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:408\nmsgid   \"begin (inclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:409\nmsgid   \"end (exclusive)\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:417\nmsgid   \"range\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:420\nmsgid   \"minimum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:421\nmsgid   \"maximum\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:423\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427\nmsgid   \"mask\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:428\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:437\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:447\nmsgid   \"type\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:535\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/rule_conditions.py:541\nmsgid   \"Add movement\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:55\nmsgid   \"No supported device found\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281\nmsgid   \"no receiver\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299\n#: lib/solaar/ui/window.py:728\nmsgid   \"offline\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:297\nmsgid   \"no status\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:110\nmsgid   \"Scanning\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:141\nmsgid   \"Battery\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:144\nmsgid   \"Wireless Link\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:148\nmsgid   \"Lighting\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:182\nmsgid   \"Show Technical Details\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:198\nmsgid   \"Pair new device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:216\nmsgid   \"Select a device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:331\nmsgid   \"Rule Editor\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:522\nmsgid   \"Path\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:524\nmsgid   \"USB ID\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529\n#: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546\nmsgid   \"Serial\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Index\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:535\nmsgid   \"Wireless PID\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:537\nmsgid   \"Product ID\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:539\nmsgid   \"Protocol\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:539\nmsgid   \"Unknown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:541\nmsgid   \"Polling rate\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:548\nmsgid   \"Unit ID\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:559\nmsgid   \"none\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:560\nmsgid   \"Notifications\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:604\nmsgid   \"No device paired.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:613\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\n\n#: lib/solaar/ui/window.py:620\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:624\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\"\nmsgstr[1]       \"\"\n\n#: lib/solaar/ui/window.py:681\nmsgid   \"Battery Voltage\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:683\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:685\nmsgid   \"Battery Level\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:687\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696\nmsgid   \"next reported \"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:697\nmsgid   \" and next level to be reported.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:702\nmsgid   \"last known\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"encrypted\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:715\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:717\nmsgid   \"not encrypted\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:721\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:737\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"\"\n"
  },
  {
    "path": "po/sr.po",
    "content": "# Language rs translations for solaar package.\n# Copyright (C) 2022 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2022.\n#\nmsgid   \"\"\nmsgstr  \"Project-Id-Version: solaar 1.1.4\\n\"\n        \"Report-Msgid-Bugs-To: \\n\"\n        \"POT-Creation-Date: 2023-12-28 17:40+0100\\n\"\n        \"PO-Revision-Date: 2022-08-09 17:35+0200\\n\"\n        \"Last-Translator: Automatically generated\\n\"\n        \"Language-Team: github.com/renatoka\\n\"\n        \"Language: sr\\n\"\n        \"MIME-Version: 1.0\\n\"\n        \"Content-Type: text/plain; charset=UTF-8\\n\"\n        \"Content-Transfer-Encoding: 8bit\\n\"\n        \"Plural-Forms: nplurals=2; plural=n != 1;\\n\"\n\n#: lib/logitech_receiver/base_usb.py:46\nmsgid   \"Bolt Receiver\"\nmsgstr  \"Bolt prijemnik\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid   \"Unifying Receiver\"\nmsgstr  \"Unifying prijemnik\"\n\n#: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78\n#: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102\n#: lib/logitech_receiver/base_usb.py:114\nmsgid   \"Nano Receiver\"\nmsgstr  \"Nano prijemnik\"\n\n#: lib/logitech_receiver/base_usb.py:124\nmsgid   \"Lightspeed Receiver\"\nmsgstr  \"Lightspeed prijemnik\"\n\n#: lib/logitech_receiver/base_usb.py:133\nmsgid   \"EX100 Receiver 27 Mhz\"\nmsgstr  \"EX100 prijemnik 27 MHZ\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid   \"empty\"\nmsgstr  \"prazna\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid   \"critical\"\nmsgstr  \"kritično\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid   \"low\"\nmsgstr  \"slabo\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid   \"average\"\nmsgstr  \"prosečna\"\n\n#: lib/logitech_receiver/i18n.py:34\nmsgid   \"good\"\nmsgstr  \"dobra\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid   \"full\"\nmsgstr  \"puna\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid   \"discharging\"\nmsgstr  \"pražnjenje\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid   \"recharging\"\nmsgstr  \"punjenje\"\n\n#: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711\nmsgid   \"charging\"\nmsgstr  \"punjenje\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid   \"not charging\"\nmsgstr  \"ne puni se\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid   \"almost full\"\nmsgstr  \"skoro puna\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid   \"charged\"\nmsgstr  \"napunjeno\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid   \"slow recharge\"\nmsgstr  \"sporo punjenje\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid   \"invalid battery\"\nmsgstr  \"neispravna baterija\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid   \"thermal error\"\nmsgstr  \"toplotna greška\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid   \"error\"\nmsgstr  \"greška\"\n\n#: lib/logitech_receiver/i18n.py:48\nmsgid   \"standard\"\nmsgstr  \"standardno\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid   \"fast\"\nmsgstr  \"brzo\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid   \"slow\"\nmsgstr  \"sporo\"\n\n#: lib/logitech_receiver/i18n.py:53\nmsgid   \"device timeout\"\nmsgstr  \"istek čekanja uređaja\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid   \"device not supported\"\nmsgstr  \"uređaj nije podržan\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid   \"too many devices\"\nmsgstr  \"previše uređaja\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid   \"sequence timeout\"\nmsgstr  \"istek vremenske sekvence\"\n\n#: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572\nmsgid   \"Firmware\"\nmsgstr  \"Firmver\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid   \"Bootloader\"\nmsgstr  \"Bootloader\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid   \"Hardware\"\nmsgstr  \"Hardver\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid   \"Other\"\nmsgstr  \"Ostalo\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid   \"Left Button\"\nmsgstr  \"Levo dugme\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid   \"Right Button\"\nmsgstr  \"Desno dugme\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid   \"Middle Button\"\nmsgstr  \"Srednje dugme\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid   \"Back Button\"\nmsgstr  \"Dugme za unazad\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid   \"Forward Button\"\nmsgstr  \"Dugme za unapred\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid   \"Mouse Gesture Button\"\nmsgstr  \"Dugme za pokrete miša\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid   \"Smart Shift\"\nmsgstr  \"Pametan pomak\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid   \"DPI Switch\"\nmsgstr  \"DPI svitch\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid   \"Left Tilt\"\nmsgstr  \"Levi nagib\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid   \"Right Tilt\"\nmsgstr  \"Desni nagib\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid   \"Left Click\"\nmsgstr  \"Levi lik\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid   \"Right Click\"\nmsgstr  \"Desni klik\"\n\n#: lib/logitech_receiver/i18n.py:77\nmsgid   \"Mouse Middle Button\"\nmsgstr  \"Srednje dugme miša\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid   \"Mouse Back Button\"\nmsgstr  \"Dugme za povratak na mišu\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid   \"Mouse Forward Button\"\nmsgstr  \"Dugme za unapred na mišu\"\n\n#: lib/logitech_receiver/i18n.py:80\nmsgid   \"Gesture Button Navigation\"\nmsgstr  \"Navigacija pomoću dugmadi\"\n\n#: lib/logitech_receiver/i18n.py:81\nmsgid   \"Mouse Scroll Left Button\"\nmsgstr  \"Levo dugme za pomeranje miša\"\n\n#: lib/logitech_receiver/i18n.py:82\nmsgid   \"Mouse Scroll Right Button\"\nmsgstr  \"Desno dugme za pomeranje miša\"\n\n#: lib/logitech_receiver/i18n.py:85\nmsgid   \"pressed\"\nmsgstr  \"pritisnuto\"\n\n#: lib/logitech_receiver/i18n.py:86\nmsgid   \"released\"\nmsgstr  \"otpušteno\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is closed\"\nmsgstr  \"uparivanje je zatvoreno\"\n\n#: lib/logitech_receiver/notifications.py:75\n#: lib/logitech_receiver/notifications.py:126\nmsgid   \"pairing lock is open\"\nmsgstr  \"uparivanje je otvoreno\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is closed\"\nmsgstr  \"otkrivanje je otvoreno\"\n\n#: lib/logitech_receiver/notifications.py:92\nmsgid   \"discovery lock is open\"\nmsgstr  \"otkrivanje je zatvoreno\"\n\n#: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122\nmsgid   \"connected\"\nmsgstr  \"povezano\"\n\n#: lib/logitech_receiver/notifications.py:224\nmsgid   \"disconnected\"\nmsgstr  \"odspojeno\"\n\n#: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120\nmsgid   \"unpaired\"\nmsgstr  \"nije upareno\"\n\n#: lib/logitech_receiver/notifications.py:304\nmsgid   \"powered on\"\nmsgstr  \"uključen\"\n\n#: lib/logitech_receiver/settings.py:750\nmsgid   \"register\"\nmsgstr  \"registriraj se\"\n\n#: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791\nmsgid   \"feature\"\nmsgstr  \"značajka\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid   \"Swap Fx function\"\nmsgstr  \"Zameni Fx funkciju\"\n\n#: lib/logitech_receiver/settings_templates.py:140\nmsgid   \"When set, the F1..F12 keys will activate their special function,\\n\"\n        \"and you must hold the FN key to activate their standard function.\"\nmsgstr  \"Kada su podešeni, tasteri F1..F12 će aktivirati svoju posebnu \"\n        \"funkciju,\\n\"\n        \"i morate držati FN taster da biste aktivirali njihovu standardnu \"\n        \"funkciju.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid   \"When unset, the F1..F12 keys will activate their standard function,\\n\"\n        \"and you must hold the FN key to activate their special function.\"\nmsgstr  \"Kada nisu omogućeni, tasteri F1..F12 će aktivirati svoju standardnu \"\n        \"funkciju, \\n\"\n        \"i morate držati FN taster da biste aktivirali njihovu posebnu \"\n        \"funkciju.\"\n\n#: lib/logitech_receiver/settings_templates.py:149\nmsgid   \"Hand Detection\"\nmsgstr  \"Detekcija ruku\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid   \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr  \"Uključite osvetljenje kada ruke lebde preko tastature.\"\n\n#: lib/logitech_receiver/settings_templates.py:157\nmsgid   \"Scroll Wheel Smooth Scrolling\"\nmsgstr  \"Točak za pomeranje, glatko pomeranje\"\n\n#: lib/logitech_receiver/settings_templates.py:158\n#: lib/logitech_receiver/settings_templates.py:239\n#: lib/logitech_receiver/settings_templates.py:267\nmsgid   \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr  \"Režim visoke osetljivosti za vertikalno pomeranje pomoću točkića.\"\n\n#: lib/logitech_receiver/settings_templates.py:165\nmsgid   \"Side Scrolling\"\nmsgstr  \"Bočno pomeranje\"\n\n#: lib/logitech_receiver/settings_templates.py:167\nmsgid   \"When disabled, pushing the wheel sideways sends custom button \"\n        \"events\\n\"\n        \"instead of the standard side-scrolling events.\"\nmsgstr  \"Kada je onemogućeno, pomeranje točkića u stranu šalje događaje \"\n        \"prilagođenog dugmeta \\n\"\n        \"umesto standardnih događaja bočnog pomeranja.\"\n\n#: lib/logitech_receiver/settings_templates.py:177\nmsgid   \"Sensitivity (DPI - older mice)\"\nmsgstr  \"Osetljivost (DPI - stariji miševi)\"\n\n#: lib/logitech_receiver/settings_templates.py:178\n#: lib/logitech_receiver/settings_templates.py:712\nmsgid   \"Mouse movement sensitivity\"\nmsgstr  \"Osetljivost pokreta miša\"\n\n#: lib/logitech_receiver/settings_templates.py:208\n#: lib/logitech_receiver/settings_templates.py:218\n#: lib/logitech_receiver/settings_templates.py:225\nmsgid   \"Backlight\"\nmsgstr  \"Pozadinsko osvetljenje\"\n\n#: lib/logitech_receiver/settings_templates.py:209\n#: lib/logitech_receiver/settings_templates.py:226\nmsgid   \"Set illumination time for keyboard.\"\nmsgstr  \"Podesite vreme osvetljenja za tastaturu.\"\n\n#: lib/logitech_receiver/settings_templates.py:219\nmsgid   \"Turn illumination on or off on keyboard.\"\nmsgstr  \"Uključite ili isključite osvetljenje na tastaturi.\"\n\n#: lib/logitech_receiver/settings_templates.py:237\nmsgid   \"Scroll Wheel High Resolution\"\nmsgstr  \"Visoka rezolucija točkića za pomeranje.\"\n\n#: lib/logitech_receiver/settings_templates.py:240\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid   \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr  \"Podesite da ignorišete ako je pomeranje nenormalno brzo ili sporo\"\n\n#: lib/logitech_receiver/settings_templates.py:247\n#: lib/logitech_receiver/settings_templates.py:277\nmsgid   \"Scroll Wheel Diversion\"\nmsgstr  \"Preusmeravanje točkića za pomeranje\"\n\n#: lib/logitech_receiver/settings_templates.py:249\nmsgid   \"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"Neka točkić za pomeranje šalje LOWRES_WHEEL HID++ obaveštenja (koja \"\n        \"pokrećuSolaar pravila, ali se inače ignorišu.\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid   \"Scroll Wheel Direction\"\nmsgstr  \"Smer točkića za pomeranje\"\n\n#: lib/logitech_receiver/settings_templates.py:257\nmsgid   \"Invert direction for vertical scroll with wheel.\"\nmsgstr  \"Obrni smer za vertikalno pomeranje sa točkom.\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid   \"Scroll Wheel Resolution\"\nmsgstr  \"Rezolucija točkića za pomeranje\"\n\n#: lib/logitech_receiver/settings_templates.py:279\nmsgid   \"Make scroll wheel send HIRES_WHEEL HID++ notifications (which \"\n        \"trigger Solaar rules but are otherwise ignored).\"\nmsgstr  \"Neka točkić za pomeranje šalje HIRES_WHEEL HID++ obaveštenja (koja \"\n        \"pokrećuSolaar pravila, ali se inače ignorišu.\"\n\n#: lib/logitech_receiver/settings_templates.py:288\nmsgid   \"Sensitivity (Pointer Speed)\"\nmsgstr  \"Osetljivost (brzina pokazivača)\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid   \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr  \"Množilac brzine za miš (256 je normalan množilac).\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid   \"Thumb Wheel Diversion\"\nmsgstr  \"Diverzija sa palcem\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid   \"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger \"\n        \"Solaar rules but are otherwise ignored).\"\nmsgstr  \"Neka kotačić palca šalje THUMB_WHEEL HID++ obavijesti (što pokreće \"\n        \"Solaar pravila, u suprotnome ih zanemaruje).\"\n\n#: lib/logitech_receiver/settings_templates.py:310\nmsgid   \"Thumb Wheel Direction\"\nmsgstr  \"Preusmeravanje pomicanja kotačića palca\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid   \"Invert thumb wheel scroll direction.\"\nmsgstr  \"Obrnite smer pomeranja točkića\"\n\n#: lib/logitech_receiver/settings_templates.py:319\nmsgid   \"Onboard Profiles\"\nmsgstr  \"Onboard profili\"\n\n#: lib/logitech_receiver/settings_templates.py:320\nmsgid   \"Enable onboard profiles, which often control report rate and \"\n        \"keyboard lighting\"\nmsgstr  \"Omogućite onboard profile, koji najčešće kontrolišu brzinom \"\n        \"pozivanja i osvetljenje tipkovnice\"\n\n#: lib/logitech_receiver/settings_templates.py:330\nmsgid   \"Polling Rate (ms)\"\nmsgstr  \"Brzina pozivanja (ms)\"\n\n#: lib/logitech_receiver/settings_templates.py:332\nmsgid   \"Frequency of device polling, in milliseconds\"\nmsgstr  \"Frekvencija brzine pozivanja uređaja, u milisekundama.\"\n\n#: lib/logitech_receiver/settings_templates.py:333\n#: lib/logitech_receiver/settings_templates.py:1046\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr  \"Možda će biti potrebni ugrađeni profili podešeni na 'Onemogućeno' da \"\n        \"bi bili efikasni.\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid   \"Divert crown events\"\nmsgstr  \"Preusmerite crown događaje\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid   \"Make crown send CROWN HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Neka crown šalje CROWN HID++ obaveštenja (koja pokreću Solaar \"\n        \"pravila, alineka se inače ignorišu.\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid   \"Crown smooth scroll\"\nmsgstr  \"Crown glatko pomicanje\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid   \"Set crown smooth scroll\"\nmsgstr  \"Podesi Crown glatko pomicanje\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid   \"Divert G Keys\"\nmsgstr  \"Preusmeri G tastere\"\n\n#: lib/logitech_receiver/settings_templates.py:385\nmsgid   \"Make G keys send GKEY HID++ notifications (which trigger Solaar \"\n        \"rules but are otherwise ignored).\"\nmsgstr  \"Neka G tasteri šalju GKEY HID++ obaveštenja (koja pokreću Solaar \"\n        \"pravila, alineka se inače ignorišu.\"\n\n#: lib/logitech_receiver/settings_templates.py:386\nmsgid   \"May also make M keys and MR key send HID++ notifications\"\nmsgstr  \"Takođe može da učini da M i MR tasteri šalju HID++ obaveštenja\"\n\n#: lib/logitech_receiver/settings_templates.py:402\nmsgid   \"Scroll Wheel Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:403\nmsgid   \"Switch the mouse wheel between speed-controlled ratcheting and \"\n        \"always freespin.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Freespinning\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid   \"Ratcheted\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid   \"Scroll Wheel Ratchet Speed\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:414\nmsgid   \"Use the mouse wheel speed to switch between ratcheted and \"\n        \"freespinning.\\n\"\n        \"The mouse wheel is always ratcheted at 50.\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:463\nmsgid   \"Key/Button Actions\"\nmsgstr  \"Radnje tastera\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Change the action for the key or button.\"\nmsgstr  \"Promenite radnju za taster ili dugme.\"\n\n#: lib/logitech_receiver/settings_templates.py:465\nmsgid   \"Overridden by diversion.\"\nmsgstr  \"Preusmjeravanje tipki.\"\n\n#: lib/logitech_receiver/settings_templates.py:466\nmsgid   \"Changing important actions (such as for the left mouse button) can \"\n        \"result in an unusable system.\"\nmsgstr  \"Promena važnih radnji (kao što je levi taster miša) može dovesti do \"\n        \"neupotrebljivosti sistem.\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid   \"Key/Button Diversion\"\nmsgstr  \"Preusmeravanje tipki\"\n\n#: lib/logitech_receiver/settings_templates.py:640\nmsgid   \"Make the key or button send HID++ notifications (Diverted) or \"\n        \"initiate Mouse Gestures or Sliding DPI\"\nmsgstr  \"Neka taster ili dugme šalje HID++ obaveštenja (preusmereno) ili \"\n        \"pokrenite miš pokretom\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Diverted\"\nmsgstr  \"Preusmereno\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid   \"Mouse Gestures\"\nmsgstr  \"Pokreti miša\"\n\n#: lib/logitech_receiver/settings_templates.py:643\n#: lib/logitech_receiver/settings_templates.py:644\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid   \"Regular\"\nmsgstr  \"Redovno\"\n\n#: lib/logitech_receiver/settings_templates.py:643\nmsgid   \"Sliding DPI\"\nmsgstr  \"Klizni DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid   \"Sensitivity (DPI)\"\nmsgstr  \"Osetljivost (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:752\nmsgid   \"Sensitivity Switching\"\nmsgstr  \"Promena osetljivosti\"\n\n#: lib/logitech_receiver/settings_templates.py:754\nmsgid   \"Switch the current sensitivity and the remembered sensitivity when \"\n        \"the key or button is pressed.\\n\"\n        \"If there is no remembered sensitivity, just remember the current \"\n        \"sensitivity\"\nmsgstr  \"Promenite trenutnu osetljivost i zapamćenu osetljivost kada \"\n        \"pritisnete taster ili kada je dugme pritisnuto. \\n\"\n        \"Ako nema zapamćene osetljivosti, samo zapamtite trenutnu osetljivost\"\n\n#: lib/logitech_receiver/settings_templates.py:758\nmsgid   \"Off\"\nmsgstr  \"Ugašen\"\n\n#: lib/logitech_receiver/settings_templates.py:791\nmsgid   \"Disable keys\"\nmsgstr  \"Onemogući tipke\"\n\n#: lib/logitech_receiver/settings_templates.py:792\nmsgid   \"Disable specific keyboard keys.\"\nmsgstr  \"Onemogući određene tipke na tipkovnici.\"\n\n#: lib/logitech_receiver/settings_templates.py:795\n#, python-format\nmsgid   \"Disables the %s key.\"\nmsgstr  \"Onemogućuje %s tipku.\"\n\n#: lib/logitech_receiver/settings_templates.py:809\n#: lib/logitech_receiver/settings_templates.py:860\nmsgid   \"Set OS\"\nmsgstr  \"Postavi OS\"\n\n#: lib/logitech_receiver/settings_templates.py:810\n#: lib/logitech_receiver/settings_templates.py:861\nmsgid   \"Change keys to match OS.\"\nmsgstr  \"Promeni tastere da se poklapaju sa OS.\"\n\n#: lib/logitech_receiver/settings_templates.py:873\nmsgid   \"Change Host\"\nmsgstr  \"Promeni računalo\"\n\n#: lib/logitech_receiver/settings_templates.py:874\nmsgid   \"Switch connection to a different host\"\nmsgstr  \"Prebaci vezu na drugo računalo\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Performs a left click.\"\nmsgstr  \"Izvodi levi klik.\"\n\n#: lib/logitech_receiver/settings_templates.py:900\nmsgid   \"Single tap\"\nmsgstr  \"Jedan dodir\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Performs a right click.\"\nmsgstr  \"Izvodi desni klik.\"\n\n#: lib/logitech_receiver/settings_templates.py:901\nmsgid   \"Single tap with two fingers\"\nmsgstr  \"Jedan dodir sa dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:902\nmsgid   \"Single tap with three fingers\"\nmsgstr  \"Jedan dodir sa tri prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Double tap\"\nmsgstr  \"Dvostruki dodir\"\n\n#: lib/logitech_receiver/settings_templates.py:906\nmsgid   \"Performs a double click.\"\nmsgstr  \"Izvodi dvostruki klik.\"\n\n#: lib/logitech_receiver/settings_templates.py:907\nmsgid   \"Double tap with two fingers\"\nmsgstr  \"Dvoklik sa dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:908\nmsgid   \"Double tap with three fingers\"\nmsgstr  \"Dvoklik sa tri prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Drags items by dragging the finger after double tapping.\"\nmsgstr  \"Prevlači stavke prevlačenjem prsta nakon dvostrukog dodira.\"\n\n#: lib/logitech_receiver/settings_templates.py:911\nmsgid   \"Tap and drag\"\nmsgstr  \"Dodirnite i prevucite\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Drags items by dragging the fingers after double tapping.\"\nmsgstr  \"Prevlači stavke prevlačenjem prstiju nakon dvostrukog dodira.\"\n\n#: lib/logitech_receiver/settings_templates.py:913\nmsgid   \"Tap and drag with two fingers\"\nmsgstr  \"Dodirnite i prevucite sa dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:914\nmsgid   \"Tap and drag with three fingers\"\nmsgstr  \"Dodirnite i prevucite sa tri prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr  \"Onemogućava pokrete dodira i rubnih gesta (ekvivalentno pritiskanju \"\n        \"Fn+LeftClick).\"\n\n#: lib/logitech_receiver/settings_templates.py:917\nmsgid   \"Suppress tap and edge gestures\"\nmsgstr  \"Zaustavite pokrete dodira i ivica\"\n\n#: lib/logitech_receiver/settings_templates.py:918\nmsgid   \"Scroll with one finger\"\nmsgstr  \"Pomerite se jednim prstom\"\n\n#: lib/logitech_receiver/settings_templates.py:918\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scrolls.\"\nmsgstr  \"Pomeranje.\"\n\n#: lib/logitech_receiver/settings_templates.py:919\n#: lib/logitech_receiver/settings_templates.py:922\nmsgid   \"Scroll with two fingers\"\nmsgstr  \"Pomeranje sa dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scroll horizontally with two fingers\"\nmsgstr  \"Pomeranje horizontalno sa dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:920\nmsgid   \"Scrolls horizontally.\"\nmsgstr  \"Pomeranje horizontalno.\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scroll vertically with two fingers\"\nmsgstr  \"Pomeranje vertikalno sa dva prsta\"\n\n#: lib/logitech_receiver/settings_templates.py:921\nmsgid   \"Scrolls vertically.\"\nmsgstr  \"Pomeranje vertikalno.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Inverts the scrolling direction.\"\nmsgstr  \"Obrče smer pomeranja.\"\n\n#: lib/logitech_receiver/settings_templates.py:923\nmsgid   \"Natural scrolling\"\nmsgstr  \"Prirodno pomeranje\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Enables the thumbwheel.\"\nmsgstr  \"Omogućava točkić.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid   \"Thumbwheel\"\nmsgstr  \"Kotačić palca.\"\n\n#: lib/logitech_receiver/settings_templates.py:935\n#: lib/logitech_receiver/settings_templates.py:939\nmsgid   \"Swipe from the top edge\"\nmsgstr  \"Povucite od gornjeg ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:936\nmsgid   \"Swipe from the left edge\"\nmsgstr  \"Povucite od levog ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:937\nmsgid   \"Swipe from the right edge\"\nmsgstr  \"Povucite od desnog ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:938\nmsgid   \"Swipe from the bottom edge\"\nmsgstr  \"Povucite od donjeg ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:940\nmsgid   \"Swipe two fingers from the left edge\"\nmsgstr  \"Povucite sa dva prsta od levog ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:941\nmsgid   \"Swipe two fingers from the right edge\"\nmsgstr  \"Povucite sa dva prsta od desnog ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:942\nmsgid   \"Swipe two fingers from the bottom edge\"\nmsgstr  \"Povucite sa dva prsta od donjeg ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:943\nmsgid   \"Swipe two fingers from the top edge\"\nmsgstr  \"Povucite sa dva prsta od gornjeg ruba\"\n\n#: lib/logitech_receiver/settings_templates.py:944\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Pinch to zoom out; spread to zoom in.\"\nmsgstr  \"Stisnite da biste umanjili; proširite da biste uvećali.\"\n\n#: lib/logitech_receiver/settings_templates.py:944\nmsgid   \"Zoom with two fingers.\"\nmsgstr  \"Zumirajte sa dva prsta.\"\n\n#: lib/logitech_receiver/settings_templates.py:945\nmsgid   \"Pinch to zoom out.\"\nmsgstr  \"Stisnite prste da biste umanjili prikaz.\"\n\n#: lib/logitech_receiver/settings_templates.py:946\nmsgid   \"Spread to zoom in.\"\nmsgstr  \"Raširite prste da biste uvećali.\"\n\n#: lib/logitech_receiver/settings_templates.py:947\nmsgid   \"Zoom with three fingers.\"\nmsgstr  \"Zumirajte sa tri prsta.\"\n\n#: lib/logitech_receiver/settings_templates.py:948\nmsgid   \"Zoom with two fingers\"\nmsgstr  \"Zumirajte sa dva prsta.\"\n\n#: lib/logitech_receiver/settings_templates.py:966\nmsgid   \"Pixel zone\"\nmsgstr  \"Zona piksela\"\n\n#: lib/logitech_receiver/settings_templates.py:967\nmsgid   \"Ratio zone\"\nmsgstr  \"Zona omera\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Scale factor\"\nmsgstr  \"Faktor veličine\"\n\n#: lib/logitech_receiver/settings_templates.py:968\nmsgid   \"Sets the cursor speed.\"\nmsgstr  \"Podešava brzinu pokazivača.\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left\"\nmsgstr  \"Levo\"\n\n#: lib/logitech_receiver/settings_templates.py:972\nmsgid   \"Left-most coordinate.\"\nmsgstr  \"Najučestalija leva koordinata.\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom\"\nmsgstr  \"Dno\"\n\n#: lib/logitech_receiver/settings_templates.py:973\nmsgid   \"Bottom coordinate.\"\nmsgstr  \"Donja koordinata.\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width\"\nmsgstr  \"Širina\"\n\n#: lib/logitech_receiver/settings_templates.py:974\nmsgid   \"Width.\"\nmsgstr  \"Širina\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height\"\nmsgstr  \"Visina\"\n\n#: lib/logitech_receiver/settings_templates.py:975\nmsgid   \"Height.\"\nmsgstr  \"Visina.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Cursor speed.\"\nmsgstr  \"Brzina kursora.\"\n\n#: lib/logitech_receiver/settings_templates.py:976\nmsgid   \"Scale\"\nmsgstr  \"Skala\"\n\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid   \"Gestures\"\nmsgstr  \"Geste\"\n\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid   \"Tweak the mouse/touchpad behaviour.\"\nmsgstr  \"Podesite ponašanje miša/tačpeda.\"\n\n#: lib/logitech_receiver/settings_templates.py:1000\nmsgid   \"Gestures Diversion\"\nmsgstr  \"Preusmjeravanje gesta\"\n\n#: lib/logitech_receiver/settings_templates.py:1001\nmsgid   \"Divert mouse/touchpad gestures.\"\nmsgstr  \"Preusmeri ponašanje miša/tačpeda.\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\nmsgid   \"Gesture params\"\nmsgstr  \"Parametri pokreta\"\n\n#: lib/logitech_receiver/settings_templates.py:1019\nmsgid   \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr  \"Promenite numeričke parametre miša/tačpeda.\"\n\n#: lib/logitech_receiver/settings_templates.py:1044\nmsgid   \"M-Key LEDs\"\nmsgstr  \"LED osvetljenje M-tastera\"\n\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid   \"Control the M-Key LEDs.\"\nmsgstr  \"Kontrolišite LED osvetljenje M-tastera.\"\n\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1077\nmsgid   \"May need G Keys diverted to be effective.\"\nmsgstr  \"Možda će biti potrebno ponovo preusmeriti taster G da bi bili \"\n        \"efikasni.\"\n\n#: lib/logitech_receiver/settings_templates.py:1053\n#, python-format\nmsgid   \"Lights up the %s key.\"\nmsgstr  \"Osvetli %s taster.\"\n\n#: lib/logitech_receiver/settings_templates.py:1074\nmsgid   \"MR-Key LED\"\nmsgstr  \"LED MR-tastera\"\n\n#: lib/logitech_receiver/settings_templates.py:1076\nmsgid   \"Control the MR-Key LED.\"\nmsgstr  \"Kontroliše LED osvetljenje MR-tastera.\"\n\n#: lib/logitech_receiver/settings_templates.py:1095\nmsgid   \"Persistent Key/Button Mapping\"\nmsgstr  \"Trajno mapiranje tastera/dugmada\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid   \"Permanently change the mapping for the key or button.\"\nmsgstr  \"Trajno promenite mapiranje za taster ili dugme.\"\n\n#: lib/logitech_receiver/settings_templates.py:1098\nmsgid   \"Changing important keys or buttons (such as for the left mouse \"\n        \"button) can result in an unusable system.\"\nmsgstr  \"Promena važnih tastera ili dugmadi (kao što je levi taster miša) \"\n        \"može rezultiraju nestabilnim sistemom.\"\n\n#: lib/logitech_receiver/settings_templates.py:1157\nmsgid   \"Sidetone\"\nmsgstr  \"Bočni ton\"\n\n#: lib/logitech_receiver/settings_templates.py:1158\nmsgid   \"Set sidetone level.\"\nmsgstr  \"Podesite nivo bočnih tonova.\"\n\n#: lib/logitech_receiver/settings_templates.py:1167\nmsgid   \"Equalizer\"\nmsgstr  \"Ekvilajzer\"\n\n#: lib/logitech_receiver/settings_templates.py:1168\nmsgid   \"Set equalizer levels.\"\nmsgstr  \"Podesite nivo ekvilajzera.\"\n\n#: lib/logitech_receiver/settings_templates.py:1191\nmsgid   \"Hz\"\nmsgstr  \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1197\nmsgid   \"Power Management\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1198\nmsgid   \"Power off in minutes (0 for never).\"\nmsgstr  \"\"\n\n#: lib/logitech_receiver/status.py:114\nmsgid   \"No paired devices.\"\nmsgstr  \"Nema uparenih uređaja\"\n\n#: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622\n#, python-format\nmsgid   \"%(count)s paired device.\"\nmsgid_plural    \"%(count)s paired devices.\"\nmsgstr[0]       \"%(count)s uparen uređaj.\"\nmsgstr[1]       \"%(count)s uparena uređaja.\"\n\n#: lib/logitech_receiver/status.py:170\n#, python-format\nmsgid   \"Battery: %(level)s\"\nmsgstr  \"Baterija: %(level)s\"\n\n#: lib/logitech_receiver/status.py:172\n#, python-format\nmsgid   \"Battery: %(percent)d%%\"\nmsgstr  \"Baterija: %(percent)d%%\"\n\n#: lib/logitech_receiver/status.py:184\n#, python-format\nmsgid   \"Lighting: %(level)s lux\"\nmsgstr  \"Osvetljenje %(level)s lux\"\n\n#: lib/logitech_receiver/status.py:239\n#, python-format\nmsgid   \"Battery: %(level)s (%(status)s)\"\nmsgstr  \"Baterija: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/status.py:241\n#, python-format\nmsgid   \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr  \"Baterija: %(percent)d%% (%(status)s)\"\n\n#: lib/solaar/ui/__init__.py:52\nmsgid   \"Permissions error\"\nmsgstr  \"Greška u dozvolama\"\n\n#: lib/solaar/ui/__init__.py:54\n#, python-format\nmsgid   \"Found a Logitech receiver or device (%s), but did not have \"\n        \"permission to open it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:55\nmsgid   \"If you've just installed Solaar, try disconnecting the receiver or \"\n        \"device and then reconnecting it.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:58\nmsgid   \"Cannot connect to device error\"\nmsgstr  \"Ne mogu da se povežem sa uređajem, greška\"\n\n#: lib/solaar/ui/__init__.py:60\n#, python-format\nmsgid   \"Found a Logitech receiver or device at %s, but encountered an error \"\n        \"connecting to it.\"\nmsgstr  \"Pronašli smo Logitech prijemnik ili uređaj na %s, ali smo naišli na \"\n        \"greškuprilikom povezivanja.\"\n\n#: lib/solaar/ui/__init__.py:61\nmsgid   \"Try disconnecting the device and then reconnecting it or turning it \"\n        \"off and then on.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/__init__.py:64\nmsgid   \"Unpairing failed\"\nmsgstr  \"Uparivanje neuspelo\"\n\n#: lib/solaar/ui/__init__.py:66\n#, python-brace-format\nmsgid   \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr  \"Odparivanje %{device} sa %{receiver} nije uspelo.\"\n\n#: lib/solaar/ui/__init__.py:67\nmsgid   \"The receiver returned an error, with no further details.\"\nmsgstr  \"Prijemnik je vratio grešku, bez dodatnih detalja.\"\n\n#: lib/solaar/ui/__init__.py:177\nmsgid   \"Another Solaar process is already running so just expose its window\"\nmsgstr  \"Još jedan Solaar proces je već pokrenut, pa samo otvorite njegov \"\n        \"prozor\"\n\n#: lib/solaar/ui/about.py:36\nmsgid   \"Manages Logitech receivers,\\n\"\n        \"keyboards, mice, and tablets.\"\nmsgstr  \"Upravlja Logitech prijemnicima,\\n\"\n        \"tastature, miševi i tableti.\"\n\n#: lib/solaar/ui/about.py:44\nmsgid   \"Additional Programming\"\nmsgstr  \"Dodatno programiranje\"\n\n#: lib/solaar/ui/about.py:45\nmsgid   \"GUI design\"\nmsgstr  \"GUI dizajn\"\n\n#: lib/solaar/ui/about.py:47\nmsgid   \"Testing\"\nmsgstr  \"Testiranje\"\n\n#: lib/solaar/ui/about.py:54\nmsgid   \"Logitech documentation\"\nmsgstr  \"Logitech dokumentacija\"\n\n#: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89\n#: lib/solaar/ui/window.py:197\nmsgid   \"Unpair\"\nmsgstr  \"Odspoji\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150\nmsgid   \"Cancel\"\nmsgstr  \"Poništi\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Complete - ENTER to change\"\nmsgstr  \"Završeno - pritisnite ENTER da biste promenili\"\n\n#: lib/solaar/ui/config_panel.py:212\nmsgid   \"Incomplete\"\nmsgstr  \"Nepotpuno\"\n\n#: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507\n#, python-format\nmsgid   \"%d value\"\nmsgid_plural    \"%d values\"\nmsgstr[0]       \"%d vrednost\"\nmsgstr[1]       \"%d vrednosti\"\n\n#: lib/solaar/ui/config_panel.py:518\nmsgid   \"Changes allowed\"\nmsgstr  \"Promene dozvoljene\"\n\n#: lib/solaar/ui/config_panel.py:519\nmsgid   \"No changes allowed\"\nmsgstr  \"Promene zabranjene\"\n\n#: lib/solaar/ui/config_panel.py:520\nmsgid   \"Ignore this setting\"\nmsgstr  \"Ignoriši ovu postavku\"\n\n#: lib/solaar/ui/config_panel.py:565\nmsgid   \"Working\"\nmsgstr  \"Radim\"\n\n#: lib/solaar/ui/config_panel.py:568\nmsgid   \"Read/write operation failed.\"\nmsgstr  \"Operacija čitanja/pisanja nije uspela.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"Built-in rules\"\nmsgstr  \"Ugrađena pravila\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid   \"User-defined rules\"\nmsgstr  \"Korisnički definisana pravila\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083\nmsgid   \"Rule\"\nmsgstr  \"Pravilo\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509\n#: lib/solaar/ui/diversion_rules.py:636\nmsgid   \"Sub-rule\"\nmsgstr  \"Podpravilo\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid   \"[empty]\"\nmsgstr  \"[prazno]\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid   \"Solaar Rule Editor\"\nmsgstr  \"Solaar uređivač pravila\"\n\n#: lib/solaar/ui/diversion_rules.py:141\nmsgid   \"Make changes permanent?\"\nmsgstr  \"Želite li da promene budu trajne?\"\n\n#: lib/solaar/ui/diversion_rules.py:146\nmsgid   \"Yes\"\nmsgstr  \"Da\"\n\n#: lib/solaar/ui/diversion_rules.py:148\nmsgid   \"No\"\nmsgstr  \"Ne\"\n\n#: lib/solaar/ui/diversion_rules.py:153\nmsgid   \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr  \"Ako izaberete Ne, promene će biti izgubljene kada se Solaar zatvori.\"\n\n#: lib/solaar/ui/diversion_rules.py:201\nmsgid   \"Save changes\"\nmsgstr  \"Spremi promene\"\n\n#: lib/solaar/ui/diversion_rules.py:206\nmsgid   \"Discard changes\"\nmsgstr  \"Odbaci promene\"\n\n#: lib/solaar/ui/diversion_rules.py:372\nmsgid   \"Insert here\"\nmsgstr  \"Unesi ovde\"\n\n#: lib/solaar/ui/diversion_rules.py:374\nmsgid   \"Insert above\"\nmsgstr  \"Unesi iznad\"\n\n#: lib/solaar/ui/diversion_rules.py:376\nmsgid   \"Insert below\"\nmsgstr  \"Unesi ispod\"\n\n#: lib/solaar/ui/diversion_rules.py:382\nmsgid   \"Insert new rule here\"\nmsgstr  \"Unesi novo pravilo ovde\"\n\n#: lib/solaar/ui/diversion_rules.py:384\nmsgid   \"Insert new rule above\"\nmsgstr  \"Unesi novo pravilo iznad\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid   \"Insert new rule below\"\nmsgstr  \"Unesi novo pravilo ispod\"\n\n#: lib/solaar/ui/diversion_rules.py:427\nmsgid   \"Paste here\"\nmsgstr  \"Zalepi ovde\"\n\n#: lib/solaar/ui/diversion_rules.py:429\nmsgid   \"Paste above\"\nmsgstr  \"Zalepi iznad\"\n\n#: lib/solaar/ui/diversion_rules.py:431\nmsgid   \"Paste below\"\nmsgstr  \"Zalepi ispod\"\n\n#: lib/solaar/ui/diversion_rules.py:437\nmsgid   \"Paste rule here\"\nmsgstr  \"Zalepi pravilo ovde\"\n\n#: lib/solaar/ui/diversion_rules.py:439\nmsgid   \"Paste rule above\"\nmsgstr  \"Zalepi pravilo iznad\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid   \"Paste rule below\"\nmsgstr  \"Zalepi pravilo ispod\"\n\n#: lib/solaar/ui/diversion_rules.py:445\nmsgid   \"Paste rule\"\nmsgstr  \"Zalepi pravilo\"\n\n#: lib/solaar/ui/diversion_rules.py:474\nmsgid   \"Flatten\"\nmsgstr  \"Poravnaj\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid   \"Insert\"\nmsgstr  \"Unesi\"\n\n#: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638\n#: lib/solaar/ui/diversion_rules.py:1126\nmsgid   \"Or\"\nmsgstr  \"Ili\"\n\n#: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637\n#: lib/solaar/ui/diversion_rules.py:1111\nmsgid   \"And\"\nmsgstr  \"I\"\n\n#: lib/solaar/ui/diversion_rules.py:513\nmsgid   \"Condition\"\nmsgstr  \"Stanje\"\n\n#: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292\nmsgid   \"Feature\"\nmsgstr  \"Značajka\"\n\n#: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328\nmsgid   \"Report\"\nmsgstr  \"Izveštaj\"\n\n#: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204\nmsgid   \"Process\"\nmsgstr  \"Proces\"\n\n#: lib/solaar/ui/diversion_rules.py:518\nmsgid   \"Mouse process\"\nmsgstr  \"Proces miša\"\n\n#: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366\nmsgid   \"Modifiers\"\nmsgstr  \"Modifikatori\"\n\n#: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419\nmsgid   \"Key\"\nmsgstr  \"Taster\"\n\n#: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461\nmsgid   \"KeyIsDown\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260\nmsgid   \"Active\"\nmsgstr  \"Радан\"\n\n#: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218\n#: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323\nmsgid   \"Device\"\nmsgstr  \"Uređaj\"\n\n#: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297\nmsgid   \"Host\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339\nmsgid   \"Setting\"\nmsgstr  \"Postavka\"\n\n#: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477\n#: lib/solaar/ui/diversion_rules.py:1526\nmsgid   \"Test\"\nmsgstr  \"Test\"\n\n#: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643\nmsgid   \"Test bytes\"\nmsgstr  \"Testiraj bajtove\"\n\n#: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736\nmsgid   \"Mouse Gesture\"\nmsgstr  \"Gesta miša\"\n\n#: lib/solaar/ui/diversion_rules.py:532\nmsgid   \"Action\"\nmsgstr  \"Akcija\"\n\n#: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845\nmsgid   \"Key press\"\nmsgstr  \"Pritisak tipke\"\n\n#: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897\nmsgid   \"Mouse scroll\"\nmsgstr  \"Pomeranje miša\"\n\n#: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959\nmsgid   \"Mouse click\"\nmsgstr  \"Klik mišem\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid   \"Set\"\nmsgstr  \"Postavi\"\n\n#: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030\nmsgid   \"Execute\"\nmsgstr  \"Izvrši\"\n\n#: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158\nmsgid   \"Later\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid   \"Insert new rule\"\nmsgstr  \"Unesi novo pravilo\"\n\n#: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686\n#: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989\nmsgid   \"Delete\"\nmsgstr  \"Obriši\"\n\n#: lib/solaar/ui/diversion_rules.py:610\nmsgid   \"Negate\"\nmsgstr  \"Negiraj\"\n\n#: lib/solaar/ui/diversion_rules.py:634\nmsgid   \"Wrap with\"\nmsgstr  \"Zamotajte sa\"\n\n#: lib/solaar/ui/diversion_rules.py:656\nmsgid   \"Cut\"\nmsgstr  \"Izreži\"\n\n#: lib/solaar/ui/diversion_rules.py:671\nmsgid   \"Paste\"\nmsgstr  \"Zalepi\"\n\n#: lib/solaar/ui/diversion_rules.py:683\nmsgid   \"Copy\"\nmsgstr  \"Kopiraj\"\n\n#: lib/solaar/ui/diversion_rules.py:1063\nmsgid   \"This editor does not support the selected rule component yet.\"\nmsgstr  \"Ovaj tekstualni uređivač još uvek ne podržava izabranu komponentu \"\n        \"pravila.\"\n\n#: lib/solaar/ui/diversion_rules.py:1138\nmsgid   \"Number of seconds to delay.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1177\nmsgid   \"Not\"\nmsgstr  \"Ne\"\n\n#: lib/solaar/ui/diversion_rules.py:1187\nmsgid   \"X11 active process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1218\nmsgid   \"X11 mouse process. For use in X11 only.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1235\nmsgid   \"MouseProcess\"\nmsgstr  \"Proces miša\"\n\n#: lib/solaar/ui/diversion_rules.py:1260\nmsgid   \"Feature name of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1308\nmsgid   \"Report number of notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1342\nmsgid   \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1383\nmsgid   \"Diverted key or button depressed or released.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1392\nmsgid   \"Key down\"\nmsgstr  \"Tipka za dolje\"\n\n#: lib/solaar/ui/diversion_rules.py:1395\nmsgid   \"Key up\"\nmsgstr  \"Tipka za gore\"\n\n#: lib/solaar/ui/diversion_rules.py:1436\nmsgid   \"Diverted key or button is currently down.\\n\"\n        \"Use the Key/Button Diversion and Divert G Keys settings to divert \"\n        \"keys and buttons.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1475\nmsgid   \"Test condition on notification triggering rule processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1479\nmsgid   \"Parameter\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1542\nmsgid   \"begin (inclusive)\"\nmsgstr  \"početak (uključiv)\"\n\n#: lib/solaar/ui/diversion_rules.py:1543\nmsgid   \"end (exclusive)\"\nmsgstr  \"završetak (isključiv)\"\n\n#: lib/solaar/ui/diversion_rules.py:1552\nmsgid   \"range\"\nmsgstr  \"domet\"\n\n#: lib/solaar/ui/diversion_rules.py:1554\nmsgid   \"minimum\"\nmsgstr  \"minimum\"\n\n#: lib/solaar/ui/diversion_rules.py:1555\nmsgid   \"maximum\"\nmsgstr  \"maximum\"\n\n#: lib/solaar/ui/diversion_rules.py:1557\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr  \"bajtovi %(0)d do %(1)d, u dometu od %(2)d do %(3)d\"\n\n#: lib/solaar/ui/diversion_rules.py:1562\nmsgid   \"mask\"\nmsgstr  \"mask\"\n\n#: lib/solaar/ui/diversion_rules.py:1563\n#, python-format\nmsgid   \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr  \"bajtovi %(0)d do %(1)d, maska %(2)d\"\n\n#: lib/solaar/ui/diversion_rules.py:1573\nmsgid   \"Bit or range test on bytes in notification message triggering rule \"\n        \"processing.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1583\nmsgid   \"type\"\nmsgstr  \"tip\"\n\n#: lib/solaar/ui/diversion_rules.py:1666\nmsgid   \"Mouse gesture with optional initiating button followed by zero or \"\n        \"more mouse movements.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1671\nmsgid   \"Add movement\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1764\nmsgid   \"Simulate a chorded key click or depress or release.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1769\nmsgid   \"Add key\"\nmsgstr  \"Dodaj tipku\"\n\n#: lib/solaar/ui/diversion_rules.py:1772\nmsgid   \"Click\"\nmsgstr  \"Kliknite\"\n\n#: lib/solaar/ui/diversion_rules.py:1775\nmsgid   \"Depress\"\nmsgstr  \"Odpustite\"\n\n#: lib/solaar/ui/diversion_rules.py:1778\nmsgid   \"Release\"\nmsgstr  \"Odpustite\"\n\n#: lib/solaar/ui/diversion_rules.py:1861\nmsgid   \"Simulate a mouse scroll.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1918\nmsgid   \"Simulate a mouse click.\\n\"\n        \"On Wayland requires write access to /dev/uinput.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1921\nmsgid   \"Button\"\nmsgstr  \"Taster\"\n\n#: lib/solaar/ui/diversion_rules.py:1922\nmsgid   \"Count and Action\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1972\nmsgid   \"Execute a command with arguments.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:1975\nmsgid   \"Add argument\"\nmsgstr  \"Dodajte argument\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"Toggle\"\nmsgstr  \"Uključi/Isključi\"\n\n#: lib/solaar/ui/diversion_rules.py:2050\nmsgid   \"True\"\nmsgstr  \"Istina\"\n\n#: lib/solaar/ui/diversion_rules.py:2051\nmsgid   \"False\"\nmsgstr  \"Laž\"\n\n#: lib/solaar/ui/diversion_rules.py:2065\nmsgid   \"Unsupported setting\"\nmsgstr  \"Nepodržana postavka\"\n\n#: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242\n#: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570\n#: lib/solaar/ui/diversion_rules.py:2588\nmsgid   \"Originating device\"\nmsgstr  \"Izvorni uređaj\"\n\n#: lib/solaar/ui/diversion_rules.py:2256\nmsgid   \"Device is active and its settings can be changed.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2266\nmsgid   \"Device that originated the current notification.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2280\nmsgid   \"Name of host computer.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2347\nmsgid   \"Value\"\nmsgstr  \"Vrednost\"\n\n#: lib/solaar/ui/diversion_rules.py:2355\nmsgid   \"Item\"\nmsgstr  \"Stavka\"\n\n#: lib/solaar/ui/diversion_rules.py:2630\nmsgid   \"Change setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/diversion_rules.py:2647\nmsgid   \"Setting on device\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318\n#: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739\nmsgid   \"offline\"\nmsgstr  \"ugašeno\"\n\n#: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256\n#: lib/solaar/ui/pair_window.py:288\n#, python-format\nmsgid   \"%(receiver_name)s: pair new device\"\nmsgstr  \"%(receiver_name)s: uparite novi uređaj\"\n\n#: lib/solaar/ui/pair_window.py:123\n#, python-format\nmsgid   \"Enter passcode on %(name)s.\"\nmsgstr  \"Unesite lozinku na %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:126\n#, python-format\nmsgid   \"Type %(passcode)s and then press the enter key.\"\nmsgstr  \"Unesite %(passcode)s, a zatim pritisnite tipku enter.\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"left\"\nmsgstr  \"levo\"\n\n#: lib/solaar/ui/pair_window.py:129\nmsgid   \"right\"\nmsgstr  \"desno\"\n\n#: lib/solaar/ui/pair_window.py:131\n#, python-format\nmsgid   \"Press %(code)s\\n\"\n        \"and then press left and right buttons simultaneously.\"\nmsgstr  \"Pritisnite %(code)s\\n\"\n        \"a zatim istovremeno pritisnite levo i desno dugme.\"\n\n#: lib/solaar/ui/pair_window.py:188\nmsgid   \"Pairing failed\"\nmsgstr  \"Uparivanje neuspelo\"\n\n#: lib/solaar/ui/pair_window.py:190\nmsgid   \"Make sure your device is within range, and has a decent battery \"\n        \"charge.\"\nmsgstr  \"Uverite se da je vaš uređaj u dometu i da ima pristojno punjenje \"\n        \"baterije.\"\n\n#: lib/solaar/ui/pair_window.py:192\nmsgid   \"A new device was detected, but it is not compatible with this \"\n        \"receiver.\"\nmsgstr  \"Otkriven je novi uređaj, ali nije kompatibilan sa ovim prijemnikom.\"\n\n#: lib/solaar/ui/pair_window.py:194\nmsgid   \"More paired devices than receiver can support.\"\nmsgstr  \"Više uparenih uređaja nego što prijemnik može da podrži.\"\n\n#: lib/solaar/ui/pair_window.py:196\nmsgid   \"No further details are available about the error.\"\nmsgstr  \"Nisu dostupni dodatni detalji o grešci.\"\n\n#: lib/solaar/ui/pair_window.py:210\nmsgid   \"Found a new device:\"\nmsgstr  \"Pronađen novi uređaj:\"\n\n#: lib/solaar/ui/pair_window.py:235\nmsgid   \"The wireless link is not encrypted\"\nmsgstr  \"Bežična veza nije šifrovana\"\n\n#: lib/solaar/ui/pair_window.py:264\nmsgid   \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:266\nmsgid   \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:268\nmsgid   \"Other receivers are only compatible with a few devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:270\nmsgid   \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/pair_window.py:274\nmsgid   \"Press a pairing button or key until the pairing light flashes \"\n        \"quickly.\"\nmsgstr  \"Pritisnite dugme ili taster za uparivanje dok lampica za uparivanje \"\n        \"ne počne brzo da treperi.\"\n\n#: lib/solaar/ui/pair_window.py:276\nmsgid   \"You may have to first turn the device off and on again.\"\nmsgstr  \"Možda ćete morati prvo da isključite i ponovo uključite uređaj.\"\n\n#: lib/solaar/ui/pair_window.py:278\nmsgid   \"Turn on the device you want to pair.\"\nmsgstr  \"Uključite uređaj koji želite da uparite.\"\n\n#: lib/solaar/ui/pair_window.py:280\nmsgid   \"If the device is already turned on, turn it off and on again.\"\nmsgstr  \"Ako je uređaj već uključen, isključite ga i ponovo uključite.\"\n\n#: lib/solaar/ui/pair_window.py:283\n#, python-format\nmsgid   \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"\\n\"\n        \"\\n\"\n        \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"\\n\"\n        \"\\n\"\n        \"Ovaj prijemnik ima još %d uparivanje.\"\nmsgstr[1]       \"\\n\"\n        \"\\n\"\n        \"Ovaj prijemnik ima još %d uparivanja.\"\n\n#: lib/solaar/ui/pair_window.py:286\nmsgid   \"\\n\"\n        \"Cancelling at this point will not use up a pairing.\"\nmsgstr  \"\\n\"\n        \"Otkazivanje u ovom trenutku neće potrošiti uparivanje.\"\n\n#: lib/solaar/ui/tray.py:58\nmsgid   \"No supported device found\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319\n#, python-format\nmsgid   \"About %s\"\nmsgstr  \"O %s\"\n\n#: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317\n#, python-format\nmsgid   \"Quit %s\"\nmsgstr  \"Zatvori %s\"\n\n#: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305\nmsgid   \"no receiver\"\nmsgstr  \"nema prijemnika\"\n\n#: lib/solaar/ui/tray.py:321\nmsgid   \"no status\"\nmsgstr  \"nema statusa\"\n\n#: lib/solaar/ui/window.py:96\nmsgid   \"Scanning\"\nmsgstr  \"Skeniranje\"\n\n#: lib/solaar/ui/window.py:129\nmsgid   \"Battery\"\nmsgstr  \"Baterija\"\n\n#: lib/solaar/ui/window.py:132\nmsgid   \"Wireless Link\"\nmsgstr  \"Bežična veza\"\n\n#: lib/solaar/ui/window.py:136\nmsgid   \"Lighting\"\nmsgstr  \"Osvetljenje\"\n\n#: lib/solaar/ui/window.py:170\nmsgid   \"Show Technical Details\"\nmsgstr  \"Prikaži tehničke detalje\"\n\n#: lib/solaar/ui/window.py:186\nmsgid   \"Pair new device\"\nmsgstr  \"Uparite novi uređaj\"\n\n#: lib/solaar/ui/window.py:205\nmsgid   \"Select a device\"\nmsgstr  \"Odaberite uređaj\"\n\n#: lib/solaar/ui/window.py:322\nmsgid   \"Rule Editor\"\nmsgstr  \"Tekstualni uređivač prava\"\n\n#: lib/solaar/ui/window.py:533\nmsgid   \"Path\"\nmsgstr  \"Put\"\n\n#: lib/solaar/ui/window.py:536\nmsgid   \"USB ID\"\nmsgstr  \"USB ID\"\n\n#: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541\n#: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563\nmsgid   \"Serial\"\nmsgstr  \"Serijski\"\n\n#: lib/solaar/ui/window.py:545\nmsgid   \"Index\"\nmsgstr  \"Indeks\"\n\n#: lib/solaar/ui/window.py:547\nmsgid   \"Wireless PID\"\nmsgstr  \"Wireless PID\"\n\n#: lib/solaar/ui/window.py:549\nmsgid   \"Product ID\"\nmsgstr  \"Product ID\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Protocol\"\nmsgstr  \"Protokol\"\n\n#: lib/solaar/ui/window.py:551\nmsgid   \"Unknown\"\nmsgstr  \"Nepoznato\"\n\n#: lib/solaar/ui/window.py:554\n#, python-format\nmsgid   \"%(rate)d ms (%(rate_hz)dHz)\"\nmsgstr  \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#: lib/solaar/ui/window.py:554\nmsgid   \"Polling rate\"\nmsgstr  \"Brzina pozivanja\"\n\n#: lib/solaar/ui/window.py:565\nmsgid   \"Unit ID\"\nmsgstr  \"Unit ID\"\n\n#: lib/solaar/ui/window.py:576\nmsgid   \"none\"\nmsgstr  \"nema\"\n\n#: lib/solaar/ui/window.py:577\nmsgid   \"Notifications\"\nmsgstr  \"Obaveštenja\"\n\n#: lib/solaar/ui/window.py:621\nmsgid   \"No device paired.\"\nmsgstr  \"Nijedan uređaj nije uparen.\"\n\n#: lib/solaar/ui/window.py:628\n#, python-format\nmsgid   \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural    \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0]       \"Do %(max_count)s uređaj može da se upari sa ovim prijemnikom.\"\nmsgstr[1]       \"Do %(max_count)s uređaja može da se upari sa ovim \"\n        \"prijemnikom.\"\n\n#: lib/solaar/ui/window.py:634\nmsgid   \"Only one device can be paired to this receiver.\"\nmsgstr  \"Samo jedan uređaj može biti uparen sa ovim prijemnikom.\"\n\n#: lib/solaar/ui/window.py:638\n#, python-format\nmsgid   \"This receiver has %d pairing remaining.\"\nmsgid_plural    \"This receiver has %d pairings remaining.\"\nmsgstr[0]       \"Ovaj prijemnik ima još %d uparivanje.\"\nmsgstr[1]       \"Ovaj prijemnik ima još %d uparivanja.\"\n\n#: lib/solaar/ui/window.py:692\nmsgid   \"Battery Voltage\"\nmsgstr  \"Voltaža baterije\"\n\n#: lib/solaar/ui/window.py:694\nmsgid   \"Voltage reported by battery\"\nmsgstr  \"Napon koji javlja baterija\"\n\n#: lib/solaar/ui/window.py:696\nmsgid   \"Battery Level\"\nmsgstr  \"Nivo baterije\"\n\n#: lib/solaar/ui/window.py:698\nmsgid   \"Approximate level reported by battery\"\nmsgstr  \"Baterija prijavljuje približan nivo\"\n\n#: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707\nmsgid   \"next reported \"\nmsgstr  \"sledeći izveštaj \"\n\n#: lib/solaar/ui/window.py:708\nmsgid   \" and next level to be reported.\"\nmsgstr  \" i sledeći nivo koji treba izvesti.\"\n\n#: lib/solaar/ui/window.py:713\nmsgid   \"last known\"\nmsgstr  \"poslednje poznato\"\n\n#: lib/solaar/ui/window.py:724\nmsgid   \"encrypted\"\nmsgstr  \"šifrovano\"\n\n#: lib/solaar/ui/window.py:726\nmsgid   \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr  \"Bežična veza između ovog uređaja i njegovog prijemnika je šifrovana.\"\n\n#: lib/solaar/ui/window.py:728\nmsgid   \"not encrypted\"\nmsgstr  \"nije šifrovano\"\n\n#: lib/solaar/ui/window.py:732\nmsgid   \"The wireless link between this device and its receiver is not \"\n        \"encrypted.\\n\"\n        \"This is a security issue for pointing devices, and a major security \"\n        \"issue for text-input devices.\"\nmsgstr  \"\"\n\n#: lib/solaar/ui/window.py:748\n#, python-format\nmsgid   \"%(light_level)d lux\"\nmsgstr  \"%(light_level)d lux\"\n\n#~ msgid        \"Add action\"\n#~ msgstr       \"Dodaj akciju\"\n\n#~ msgid        \"Adjust the DPI by sliding the mouse horizontally while \"\n#~      \"holding the button down.\"\n#~ msgstr       \"Podesite DPI pomeranjem miša horizontalno dok držite \"\n#~      \"tasterza dolje.\"\n\n#~ msgid        \"Automatically switch the mouse wheel between ratchet and \"\n#~      \"freespin mode.\\n\"\n#~      \"The mouse wheel is always free at 0, and always ratcheted at 50\"\n#~ msgstr       \"Automatski prebacite točkić miša između režima ratchet i \"\n#~      \"slobodnog načina. \\n\"\n#~      \"Točak miša je uvek slobodan na 0, i uvek zaključan na 50\"\n\n#~ msgid        \"Battery information unknown.\"\n#~ msgstr       \"Informacije o bateriji nepoznate.\"\n\n#~ msgid        \"Count\"\n#~ msgstr       \"Brojilo\"\n\n#~ msgid        \"DPI Sliding Adjustment\"\n#~ msgstr       \"DPI klizno podešavanje\"\n\n#, python-format\n#~ msgid        \"Found a Logitech Receiver (%s), but did not have permission \"\n#~      \"to open it.\"\n#~ msgstr       \"Pronašao sam Logitech prijemnik (%s), ali nisam imao dozvolu \"\n#~      \"da ga otvorim.\"\n\n#~ msgid        \"If you've just installed Solaar, try removing the receiver \"\n#~      \"and plugging it back in.\"\n#~ msgstr       \"Ako ste upravo instalirali Solaar, pokušajte da odspojite \"\n#~      \"prijemnik i priključite gaponovo.\"\n\n#~ msgid        \"No Logitech device found\"\n#~ msgstr       \"Nije pronađen nijedan Logitech uređaj\"\n\n#~ msgid        \"Scroll Wheel Rachet\"\n#~ msgstr       \"Ustavljanje pomicanja kotačića\"\n\n#~ msgid        \"Send a gesture by sliding the mouse while holding the button \"\n#~      \"down.\"\n#~ msgstr       \"Pošaljite pokret prevlačenjem miša dok držite dugme za dole.\"\n\n#~ msgid        \"The wireless link between this device and its receiver is \"\n#~      \"not encrypted.\\n\"\n#~      \"\\n\"\n#~      \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~      \"security issue.\\n\"\n#~      \"\\n\"\n#~      \"It is, however, a major security issue for text-input devices \"\n#~      \"(keyboards, numpads),\\n\"\n#~      \"because typed text can be sniffed inconspicuously by 3rd parties \"\n#~      \"within range.\"\n#~ msgstr       \"Bežična veza između ovog uređaja i njegovog prijemnika nije \"\n#~      \"šifrovana.\\n\"\n#~      \"\\n\"\n#~      \"Za pokazivačke uređaje (miševi, kuglice za praćenje, dodirne table) \"\n#~      \"ovo je manji bezbednosni problem.\\n\"\n#~      \"Međutim, to je glavni bezbednosni problem za uređaje za unos teksta \"\n#~      \"(tastature, numeričke podloge),\\n\"\n#~      \"jer otkucani tekst mogu neprimetno da nanjuše treće strane u dometu\"\n\n#~ msgid        \"Try removing the device and plugging it back in or turning \"\n#~      \"it off and then on.\"\n#~ msgstr       \"Pokušajte da odspojite uređaj i ponovo ga uključite ili \"\n#~      \"isključite, a zatimupalite.\"\n\n#~ msgid        \"unknown\"\n#~ msgstr       \"nepoznato\"\n"
  },
  {
    "path": "po/sv.po",
    "content": "# Swedish translations for solaar package.\n# Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2013.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 1.0.3\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-01 21:43+0300\\n\"\n\"PO-Revision-Date: 2025-12-13 08:04+0100\\n\"\n\"Last-Translator: Daniel Nylander <github@danielnylander.se>\\n\"\n\"Language-Team: none\\n\"\n\"Language: sv\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Poedit-Basepath: /pwr/Solaar/po\\n\"\n\"X-Poedit-SearchPath-0: /pwr/Solaar/po\\n\"\n\n#: lib/logitech_receiver/base_usb.py:52\nmsgid \"Bolt Receiver\"\nmsgstr \"Bolt-mottagare\"\n\n#: lib/logitech_receiver/base_usb.py:64\nmsgid \"Unifying Receiver\"\nmsgstr \"Unifying-mottagare\"\n\n#: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87\n#: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113\nmsgid \"Nano Receiver\"\nmsgstr \"Nano-mottagare\"\n\n#: lib/logitech_receiver/base_usb.py:125\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Lightspeed-mottagare\"\n\n#: lib/logitech_receiver/base_usb.py:135\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"EX100-mottagare 27 Mhz\"\n\n#: lib/logitech_receiver/common.py:649\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"Batteri: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:652\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"Batteri: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:1048\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid \"Disabled\"\nmsgstr \"Inaktiverad\"\n\n#: lib/logitech_receiver/hidpp20.py:1049\nmsgid \"Static\"\nmsgstr \"Statisk\"\n\n#: lib/logitech_receiver/hidpp20.py:1050\nmsgid \"Pulse\"\nmsgstr \"Pulsera\"\n\n#: lib/logitech_receiver/hidpp20.py:1051\nmsgid \"Cycle\"\nmsgstr \"Växla\"\n\n#: lib/logitech_receiver/hidpp20.py:1052\nmsgid \"Boot\"\nmsgstr \"Boot\"\n\n#: lib/logitech_receiver/hidpp20.py:1053\nmsgid \"Demo\"\nmsgstr \"Demo\"\n\n#: lib/logitech_receiver/hidpp20.py:1055\nmsgid \"Breathe\"\nmsgstr \"Andas\"\n\n#: lib/logitech_receiver/hidpp20.py:1058\nmsgid \"Ripple\"\nmsgstr \"Krusning\"\n\n#: lib/logitech_receiver/hidpp20.py:1059\nmsgid \"Decomposition\"\nmsgstr \"Nedbrytning\"\n\n#: lib/logitech_receiver/hidpp20.py:1060\nmsgid \"Signature1\"\nmsgstr \"Signatur1\"\n\n#: lib/logitech_receiver/hidpp20.py:1061\nmsgid \"Signature2\"\nmsgstr \"Signatur2\"\n\n#: lib/logitech_receiver/hidpp20.py:1062\nmsgid \"CycleS\"\nmsgstr \"CycleS\"\n\n#: lib/logitech_receiver/hidpp20.py:1126\nmsgid \"Unknown Location\"\nmsgstr \"Okänd plats\"\n\n#: lib/logitech_receiver/hidpp20.py:1127\nmsgid \"Primary\"\nmsgstr \"Primär\"\n\n#: lib/logitech_receiver/hidpp20.py:1128\nmsgid \"Logo\"\nmsgstr \"Logotyp\"\n\n#: lib/logitech_receiver/hidpp20.py:1129\nmsgid \"Left Side\"\nmsgstr \"Vänster sida\"\n\n#: lib/logitech_receiver/hidpp20.py:1130\nmsgid \"Right Side\"\nmsgstr \"Höger sida\"\n\n#: lib/logitech_receiver/hidpp20.py:1131\nmsgid \"Combined\"\nmsgstr \"Kombinerad\"\n\n#: lib/logitech_receiver/hidpp20.py:1132\nmsgid \"Primary 1\"\nmsgstr \"Primär 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1133\nmsgid \"Primary 2\"\nmsgstr \"Primär 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1134\nmsgid \"Primary 3\"\nmsgstr \"Primär 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1135\nmsgid \"Primary 4\"\nmsgstr \"Primär 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1136\nmsgid \"Primary 5\"\nmsgstr \"Primär 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1137\nmsgid \"Primary 6\"\nmsgstr \"Primär 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"tom\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"kritisk\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"låg\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"genomsnitt\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"god\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"full\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"urladdning\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"uppladdning\"\n\n#: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700\nmsgid \"charging\"\nmsgstr \"laddar\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"laddar inte\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"nästan full\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"laddad\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"långsam laddning\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"invalid battery\"\nmsgstr \"batterifel\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"termiskt fel\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"fel\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"standard\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"snabb\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"långsam\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"enheten svarade inte\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"enheten stöds inte\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"för många enheter\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"tidsgräns för sekvens överskreds\"\n\n#: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555\nmsgid \"Firmware\"\nmsgstr \"Fast programvara\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"Startladdare\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"Hårdvara\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"Annan\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"Vänster knapp\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"Höger knapp\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"Mittenknapp\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"Tillbakaknapp\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"Framåtknapp\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"Mus gestknapp\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"Smart skift\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"DPI-växel\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"Vänster lutning\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"Höger lutning\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"Vänsterklick\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"Högerklick\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"Mus mittenknapp\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"Mus tillbakaknapp\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"Mus framåtknapp\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"Gestknapp navigering\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"Vänster musrullningsknapp\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"Höger musrullningsknapp\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"nedtryckt\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"släpptes\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"connected\"\nmsgstr \"ansluten\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"disconnected\"\nmsgstr \"frånkopplad\"\n\n#: lib/logitech_receiver/notifications.py:182\nmsgid \"unpaired\"\nmsgstr \"inte parkopplad\"\n\n#: lib/logitech_receiver/notifications.py:231\nmsgid \"powered on\"\nmsgstr \"påslagen\"\n\n#: lib/logitech_receiver/notifications.py:283\nmsgid \"ADC measurement notification\"\nmsgstr \"ADC-mätningsmeddelande\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:483\nmsgid \"pairing lock is closed\"\nmsgstr \"parkopplingslåset är stängt\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:483\nmsgid \"pairing lock is open\"\nmsgstr \"parkopplingslåset är öppet\"\n\n#: lib/logitech_receiver/notifications.py:446\nmsgid \"discovery lock is closed\"\nmsgstr \"upptäcktslåset är stängt\"\n\n#: lib/logitech_receiver/notifications.py:446\nmsgid \"discovery lock is open\"\nmsgstr \"upptäcktslåset är öppet\"\n\n#: lib/logitech_receiver/receiver.py:437\nmsgid \"No paired devices.\"\nmsgstr \"Inga parkopplade enheter.\"\n\n#: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s parkopplad enhet.\"\nmsgstr[1] \"%(count)s parkopplade enheter.\"\n\n#: lib/logitech_receiver/settings.py:602\nmsgid \"register\"\nmsgstr \"registrera\"\n\n#: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654\nmsgid \"feature\"\nmsgstr \"funktion\"\n\n#: lib/logitech_receiver/settings_templates.py:138\nmsgid \"Swap Fx function\"\nmsgstr \"Byt Fx-funktion\"\n\n#: lib/logitech_receiver/settings_templates.py:141\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"När de är inställda kommer F1..F12-tangenterna att aktivera sin \"\n\"specialfunktion,\\n\"\n\"och du måste hålla ner FN-tangenten för att aktivera deras standardfunktion.\"\n\n#: lib/logitech_receiver/settings_templates.py:146\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"När de inte är inställda kommer F1..F12-tangenterna att aktivera sin \"\n\"standardfunktion,\\n\"\n\"och du måste hålla ner FN-tangenten för att aktivera deras specialfunktion.\"\n\n#: lib/logitech_receiver/settings_templates.py:154\nmsgid \"Hand Detection\"\nmsgstr \"Handavkänning\"\n\n#: lib/logitech_receiver/settings_templates.py:155\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"Tänd belysning när händerna hålls över tangentbordet.\"\n\n#: lib/logitech_receiver/settings_templates.py:162\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"Rullningshjul mjuk rullning\"\n\n#: lib/logitech_receiver/settings_templates.py:163\n#: lib/logitech_receiver/settings_templates.py:410\n#: lib/logitech_receiver/settings_templates.py:439\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"Högkänsligt läge för vertikal rullning med hjulet.\"\n\n#: lib/logitech_receiver/settings_templates.py:170\nmsgid \"Side Scrolling\"\nmsgstr \"Sidrullning\"\n\n#: lib/logitech_receiver/settings_templates.py:172\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"Vid inaktivering skickas anpassade knapphändelser om du trycker på hjulet i \"\n\"sidled\\n\"\n\"istället för standardhändelserna för sidrullning.\"\n\n#: lib/logitech_receiver/settings_templates.py:182\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"Känslighet (DPI - äldre möss)\"\n\n#: lib/logitech_receiver/settings_templates.py:183\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"Musrörelsekänslighet\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid \"Backlight Timed\"\nmsgstr \"Bakgrundsbelysning tidsinställd\"\n\n#: lib/logitech_receiver/settings_templates.py:257\n#: lib/logitech_receiver/settings_templates.py:397\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"Ställ in belysningstid för tangentbordet.\"\n\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid \"Backlight\"\nmsgstr \"Bakbelysning\"\n\n#: lib/logitech_receiver/settings_templates.py:269\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"\"\n\"Belysningsnivå på tangentbordet.  Ändringar som görs tillämpas endast i \"\n\"manuellt läge.\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid \"Automatic\"\nmsgstr \"Automatiskt\"\n\n#: lib/logitech_receiver/settings_templates.py:303\nmsgid \"Manual\"\nmsgstr \"Manuellt\"\n\n#: lib/logitech_receiver/settings_templates.py:305\nmsgid \"Enabled\"\nmsgstr \"Aktiverad\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid \"Backlight Level\"\nmsgstr \"Bakgrundsbelysningsnivå\"\n\n#: lib/logitech_receiver/settings_templates.py:312\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"Belysningsnivå på tangentbordet i manuellt läge.\"\n\n#: lib/logitech_receiver/settings_templates.py:369\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"Fördröjning av bakgrundsbelysning händer ute\"\n\n#: lib/logitech_receiver/settings_templates.py:370\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"\"\n\"Fördröjning i sekunder tills bakgrundsbelysningen tonar ut när händerna tas \"\n\"bort från tangentbordet.\"\n\n#: lib/logitech_receiver/settings_templates.py:378\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"Fördröjning av bakgrundsbelysning händer inne\"\n\n#: lib/logitech_receiver/settings_templates.py:379\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"\"\n\"Fördröjning i sekunder tills bakgrundsbelysningen tonar ut när händerna är \"\n\"nära tangentbordet.\"\n\n#: lib/logitech_receiver/settings_templates.py:387\nmsgid \"Backlight Delay Powered\"\nmsgstr \"Fördröjning av bakgrundsbelysning extern ström\"\n\n#: lib/logitech_receiver/settings_templates.py:388\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"\"\n\"Fördröjning i sekunder tills bakgrundsbelysningen tonar ut med extern \"\n\"strömförsörjning.\"\n\n#: lib/logitech_receiver/settings_templates.py:396\nmsgid \"Backlight (Seconds)\"\nmsgstr \"Bakgrundsbelysning (sekunder)\"\n\n#: lib/logitech_receiver/settings_templates.py:408\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"Rullningshjul hög upplösning\"\n\n#: lib/logitech_receiver/settings_templates.py:412\n#: lib/logitech_receiver/settings_templates.py:441\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"Ställ in att ignorera om rullningen är onormalt snabb eller långsam\"\n\n#: lib/logitech_receiver/settings_templates.py:419\n#: lib/logitech_receiver/settings_templates.py:450\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"Rullhjulsavledning\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Få rullhjulet att skicka LOWRES_WHEEL HID++-aviseringar (som utlöser Solaar-\"\n\"regler men som annars ignoreras).\"\n\n#: lib/logitech_receiver/settings_templates.py:428\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"Rullhjulets riktning\"\n\n#: lib/logitech_receiver/settings_templates.py:429\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"Invertera riktning för vertikal rullning med hjul.\"\n\n#: lib/logitech_receiver/settings_templates.py:437\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"Rullhjulsupplösning\"\n\n#: lib/logitech_receiver/settings_templates.py:452\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Få rullhjulet att skicka HIRES_WHEEL HID++-aviseringar (som utlöser Solaar-\"\n\"regler men som annars ignoreras).\"\n\n#: lib/logitech_receiver/settings_templates.py:461\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"Känslighet (pekarhastighet)\"\n\n#: lib/logitech_receiver/settings_templates.py:462\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"Hastighetsmultiplikator för mus (256 är normal multiplikator).\"\n\n#: lib/logitech_receiver/settings_templates.py:472\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"Tumhjulsavledning\"\n\n#: lib/logitech_receiver/settings_templates.py:474\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Få tumhjulet att skicka THUMB_WHEEL HID++-aviseringar (som utlöser Solaar-\"\n\"regler men som annars ignoreras).\"\n\n#: lib/logitech_receiver/settings_templates.py:483\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"Tumhjulets riktning\"\n\n#: lib/logitech_receiver/settings_templates.py:484\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"Invertera tumhjulets rullningsriktning.\"\n\n#: lib/logitech_receiver/settings_templates.py:504\nmsgid \"Onboard Profiles\"\nmsgstr \"Inbyggda profiler\"\n\n#: lib/logitech_receiver/settings_templates.py:505\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"\"\n\"Aktivera en inbyggd profil som styr rapporteringsfrekvens, känslighet och \"\n\"knappfunktioner\"\n\n#: lib/logitech_receiver/settings_templates.py:549\n#: lib/logitech_receiver/settings_templates.py:582\nmsgid \"Report Rate\"\nmsgstr \"Rapporteringsfrekvens\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\nmsgid \"Frequency of device movement reports\"\nmsgstr \"Frekvens för rapporter om enhetsrörelser\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1421\n#: lib/logitech_receiver/settings_templates.py:1452\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"\"\n\"Kan behöva inbyggda profiler inställda på Inaktivera för att vara effektiva.\"\n\n#: lib/logitech_receiver/settings_templates.py:612\nmsgid \"Divert crown events\"\nmsgstr \"Avled kronhändelser\"\n\n#: lib/logitech_receiver/settings_templates.py:613\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Få kronan att skicka CROWN HID++-meddelanden (som utlöser Solaar-regler men \"\n\"annars ignoreras).\"\n\n#: lib/logitech_receiver/settings_templates.py:621\nmsgid \"Crown smooth scroll\"\nmsgstr \"Kronans mjuka rullning\"\n\n#: lib/logitech_receiver/settings_templates.py:622\nmsgid \"Set crown smooth scroll\"\nmsgstr \"Ställ in kronans mjuka rullning\"\n\n#: lib/logitech_receiver/settings_templates.py:630\nmsgid \"Divert G and M Keys\"\nmsgstr \"Omdirigera G- och M-tangenterna\"\n\n#: lib/logitech_receiver/settings_templates.py:631\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Gör så att tangenterna G och M skickar HID++-meddelanden (som aktiverar \"\n\"Solaar-regler men annars ignoreras).\"\n\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"Rullningshjul spärrat\"\n\n#: lib/logitech_receiver/settings_templates.py:646\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"\"\n\"Växla mushjulet mellan hastighetskontrollerad spärrning och alltid fri snurr.\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Freespinning\"\nmsgstr \"Fri snurrning\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Ratcheted\"\nmsgstr \"Spärrad\"\n\n#: lib/logitech_receiver/settings_templates.py:655\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"Rullningshjulets spärrhastighet\"\n\n#: lib/logitech_receiver/settings_templates.py:657\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"Använd mushjulets hastighet för att växla mellan spärrad och fri snurrning.\\n\"\n\"Mushjulet är alltid spärrat till 50.\"\n\n#: lib/logitech_receiver/settings_templates.py:707\nmsgid \"Scroll Wheel Ratchet Torque\"\nmsgstr \"Vridmoment för rullhjulsspärr\"\n\n#: lib/logitech_receiver/settings_templates.py:708\nmsgid \"Change the torque needed to overcome the ratchet.\"\nmsgstr \"Ändra vridmomentet som behövs för att övervinna spärren.\"\n\n#: lib/logitech_receiver/settings_templates.py:743\nmsgid \"Key/Button Actions\"\nmsgstr \"Tangent-/knappåtgärder\"\n\n#: lib/logitech_receiver/settings_templates.py:745\nmsgid \"Change the action for the key or button.\"\nmsgstr \"Ändra åtgärden för tangenten eller knappen.\"\n\n#: lib/logitech_receiver/settings_templates.py:747\nmsgid \"Overridden by diversion.\"\nmsgstr \"Åsidosatt av avledning.\"\n\n#: lib/logitech_receiver/settings_templates.py:749\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"\"\n\"Ändring av viktiga åtgärder (som för vänster musknapp) kan resultera i ett \"\n\"oanvändbart system.\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid \"Key/Button Diversion\"\nmsgstr \"Tangent/knapp avledning\"\n\n#: lib/logitech_receiver/settings_templates.py:925\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse \"\n\"Gestures or Sliding DPI\"\nmsgstr \"\"\n\"Få tangenten eller knappen att skicka HID++-aviseringar (vidarekopplade) \"\n\"eller initiera musgester eller glidande DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Diverted\"\nmsgstr \"Avledd\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\nmsgid \"Mouse Gestures\"\nmsgstr \"Musgester\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Regular\"\nmsgstr \"Regelbunden\"\n\n#: lib/logitech_receiver/settings_templates.py:928\nmsgid \"Sliding DPI\"\nmsgstr \"Glidande DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"Känslighet (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:1123\nmsgid \"Sensitivity Switching\"\nmsgstr \"Känslighetsväxling\"\n\n#: lib/logitech_receiver/settings_templates.py:1125\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key \"\n\"or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\"Växla den aktuella känsligheten och den ihågkomna känsligheten när knappen \"\n\"eller knappen trycks ned.\\n\"\n\"Om det inte finns någon ihågkommen känslighet, kom ihåg bara den aktuella \"\n\"känsligheten\"\n\n#: lib/logitech_receiver/settings_templates.py:1129\nmsgid \"Off\"\nmsgstr \"Av\"\n\n#: lib/logitech_receiver/settings_templates.py:1160\nmsgid \"Disable keys\"\nmsgstr \"Inaktivera tangenter\"\n\n#: lib/logitech_receiver/settings_templates.py:1161\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"Inaktivera specifika tangentbordstangenter.\"\n\n#: lib/logitech_receiver/settings_templates.py:1164\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"Inaktiverar tangenten %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1177\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid \"Set OS\"\nmsgstr \"Ställ in OS\"\n\n#: lib/logitech_receiver/settings_templates.py:1178\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid \"Change keys to match OS.\"\nmsgstr \"Ändra tangenter för att matcha OS.\"\n\n#: lib/logitech_receiver/settings_templates.py:1247\nmsgid \"Change Host\"\nmsgstr \"Byt värd\"\n\n#: lib/logitech_receiver/settings_templates.py:1248\nmsgid \"Switch connection to a different host\"\nmsgstr \"Byt anslutning till en annan värd\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Performs a left click.\"\nmsgstr \"Utför ett vänsterklick.\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Single tap\"\nmsgstr \"Enkelt tryck\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Performs a right click.\"\nmsgstr \"Utför ett högerklick.\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Single tap with two fingers\"\nmsgstr \"Enkelt tryck med två fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1274\nmsgid \"Single tap with three fingers\"\nmsgstr \"Enkelt tryck med tre fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Double tap\"\nmsgstr \"Dubbeltryck\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Performs a double click.\"\nmsgstr \"Utför ett dubbelklick.\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid \"Double tap with two fingers\"\nmsgstr \"Dubbeltryck med två fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Double tap with three fingers\"\nmsgstr \"Dubbeltryck med tre fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"Dra objekt genom att dra fingret efter att ha dubbelklickat.\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Tap and drag\"\nmsgstr \"Tryck och dra\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"Tryck och dra med två fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"Dra objekt genom att dra fingrarna efter att du dubbelklickat.\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"Tryck och dra med tre fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1291\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"Inaktivera tryck- och kantgester\"\n\n#: lib/logitech_receiver/settings_templates.py:1292\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"\"\n\"Inaktiverade tryck- och kantgester (motsvarar att trycka på Fn+vänsterklick).\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\nmsgid \"Scroll with one finger\"\nmsgstr \"Bläddra med ett finger\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scrolls.\"\nmsgstr \"Rullningar.\"\n\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scroll with two fingers\"\nmsgstr \"Rulla med två fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"Rulla horisontellt med två fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scrolls horizontally.\"\nmsgstr \"Rullar horisontellt.\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"Rulla vertikalt med två fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scrolls vertically.\"\nmsgstr \"Rullar vertikalt.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"Inverterar rullningsriktningen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Natural scrolling\"\nmsgstr \"Naturlig rullning\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"Aktiverar tumhjulet.\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Thumbwheel\"\nmsgstr \"Tumhjul\"\n\n#: lib/logitech_receiver/settings_templates.py:1311\n#: lib/logitech_receiver/settings_templates.py:1315\nmsgid \"Swipe from the top edge\"\nmsgstr \"Svep från den övre kanten\"\n\n#: lib/logitech_receiver/settings_templates.py:1312\nmsgid \"Swipe from the left edge\"\nmsgstr \"Svep från vänstra kanten\"\n\n#: lib/logitech_receiver/settings_templates.py:1313\nmsgid \"Swipe from the right edge\"\nmsgstr \"Svep från den högra kanten\"\n\n#: lib/logitech_receiver/settings_templates.py:1314\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"Svep från den nedre kanten\"\n\n#: lib/logitech_receiver/settings_templates.py:1316\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"Svep två fingrar från den vänstra kanten\"\n\n#: lib/logitech_receiver/settings_templates.py:1317\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"Svep två fingrar från den högra kanten\"\n\n#: lib/logitech_receiver/settings_templates.py:1318\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"Svep två fingrar från den nedre kanten\"\n\n#: lib/logitech_receiver/settings_templates.py:1319\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"Svep två fingrar från den övre kanten\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"Nyp för att zooma ut; sprid för att zooma in.\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\nmsgid \"Zoom with two fingers.\"\nmsgstr \"Zooma med två fingrar.\"\n\n#: lib/logitech_receiver/settings_templates.py:1321\nmsgid \"Pinch to zoom out.\"\nmsgstr \"Nyp för att zooma ut.\"\n\n#: lib/logitech_receiver/settings_templates.py:1322\nmsgid \"Spread to zoom in.\"\nmsgstr \"Sprid för att zooma in.\"\n\n#: lib/logitech_receiver/settings_templates.py:1323\nmsgid \"Zoom with three fingers.\"\nmsgstr \"Zooma med tre fingrar.\"\n\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Zoom with two fingers\"\nmsgstr \"Zooma med två fingrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1342\nmsgid \"Pixel zone\"\nmsgstr \"Pixelzon\"\n\n#: lib/logitech_receiver/settings_templates.py:1343\nmsgid \"Ratio zone\"\nmsgstr \"Ratiozon\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Scale factor\"\nmsgstr \"Skalfaktor\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Sets the cursor speed.\"\nmsgstr \"Ställer in markörhastigheten.\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left\"\nmsgstr \"Vänster\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left-most coordinate.\"\nmsgstr \"Koordinaten längst till vänster.\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom\"\nmsgstr \"Nedre\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom coordinate.\"\nmsgstr \"Nedre koordinat.\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width\"\nmsgstr \"Bredd\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width.\"\nmsgstr \"Bredd.\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height\"\nmsgstr \"Höjd\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height.\"\nmsgstr \"Höjd.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Cursor speed.\"\nmsgstr \"Markörhastighet.\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Scale\"\nmsgstr \"Skala\"\n\n#: lib/logitech_receiver/settings_templates.py:1358\nmsgid \"Gestures\"\nmsgstr \"Gester\"\n\n#: lib/logitech_receiver/settings_templates.py:1359\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"Justera musens/pekplattans beteende.\"\n\n#: lib/logitech_receiver/settings_templates.py:1375\nmsgid \"Gestures Diversion\"\nmsgstr \"Avledning av gester\"\n\n#: lib/logitech_receiver/settings_templates.py:1376\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"Avleda mus-/pekplattagester.\"\n\n#: lib/logitech_receiver/settings_templates.py:1392\nmsgid \"Gesture params\"\nmsgstr \"Gestparametrar\"\n\n#: lib/logitech_receiver/settings_templates.py:1393\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"Ändra numeriska parametrar för en mus/pekplatta.\"\n\n#: lib/logitech_receiver/settings_templates.py:1417\nmsgid \"M-Key LEDs\"\nmsgstr \"M-Key LED:ar\"\n\n#: lib/logitech_receiver/settings_templates.py:1419\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"Styr M-Key LED:ar.\"\n\n#: lib/logitech_receiver/settings_templates.py:1423\n#: lib/logitech_receiver/settings_templates.py:1454\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"Kan behöva omdirigera G-tangenter för att vara effektiva.\"\n\n#: lib/logitech_receiver/settings_templates.py:1429\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"Lyser upp tangenten %s.\"\n\n#: lib/logitech_receiver/settings_templates.py:1448\nmsgid \"MR-Key LED\"\nmsgstr \"MR-Key LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1450\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"Styr MR-Key LED.\"\n\n#: lib/logitech_receiver/settings_templates.py:1471\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"Ihållande nyckel/knappkartläggning\"\n\n#: lib/logitech_receiver/settings_templates.py:1473\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"Ändra kartläggningen för nyckeln eller knappen permanent.\"\n\n#: lib/logitech_receiver/settings_templates.py:1475\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"\"\n\"Att ändra viktiga tangenter eller knappar (som för vänster musknapp) kan \"\n\"resultera i ett oanvändbart system.\"\n\n#: lib/logitech_receiver/settings_templates.py:1532\nmsgid \"Sidetone\"\nmsgstr \"Sidoton\"\n\n#: lib/logitech_receiver/settings_templates.py:1533\nmsgid \"Set sidetone level.\"\nmsgstr \"Ställ in sidotonsnivå.\"\n\n#: lib/logitech_receiver/settings_templates.py:1542\nmsgid \"Equalizer\"\nmsgstr \"Utjämnare\"\n\n#: lib/logitech_receiver/settings_templates.py:1543\nmsgid \"Set equalizer levels.\"\nmsgstr \"Ställ in utjämningsnivåer.\"\n\n#: lib/logitech_receiver/settings_templates.py:1565\nmsgid \"Hz\"\nmsgstr \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1571\nmsgid \"Power Management\"\nmsgstr \"Strömhantering\"\n\n#: lib/logitech_receiver/settings_templates.py:1572\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"Stäng av på några minuter (0 för aldrig).\"\n\n#: lib/logitech_receiver/settings_templates.py:1584\nmsgid \"Brightness Control\"\nmsgstr \"Ljusstyrkekontroll\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\nmsgid \"Control overall brightness\"\nmsgstr \"Kontrollera allmän ljusstyrka\"\n\n#: lib/logitech_receiver/settings_templates.py:1628\n#: lib/logitech_receiver/settings_templates.py:1681\nmsgid \"LED Control\"\nmsgstr \"LED-kontroll\"\n\n#: lib/logitech_receiver/settings_templates.py:1629\n#: lib/logitech_receiver/settings_templates.py:1682\nmsgid \"Switch control of LED zones between device and Solaar\"\nmsgstr \"Växla styrning av LED-zoner mellan enhet och Solaar\"\n\n#: lib/logitech_receiver/settings_templates.py:1644\n#: lib/logitech_receiver/settings_templates.py:1692\nmsgid \"LED Zone Effects\"\nmsgstr \"LED-zoneffekter\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr \"LED-kontrollen måste ställas in på Solaar för att fungera.\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"Set effect for LED Zone\"\nmsgstr \"Ställ in effekt för LED-zon\"\n\n#: lib/logitech_receiver/settings_templates.py:1647\nmsgid \"Color\"\nmsgstr \"Färg\"\n\n#: lib/logitech_receiver/settings_templates.py:1648\nmsgid \"Speed\"\nmsgstr \"Hastighet\"\n\n#: lib/logitech_receiver/settings_templates.py:1649\nmsgid \"Period\"\nmsgstr \"Period\"\n\n#: lib/logitech_receiver/settings_templates.py:1650\nmsgid \"Intensity\"\nmsgstr \"Intensitet\"\n\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid \"Ramp\"\nmsgstr \"Ramp\"\n\n#: lib/logitech_receiver/settings_templates.py:1666\nmsgid \"LEDs\"\nmsgstr \"LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1703\nmsgid \"Per-key Lighting\"\nmsgstr \"Belysning per tangent\"\n\n#: lib/logitech_receiver/settings_templates.py:1704\nmsgid \"Control per-key lighting.\"\nmsgstr \"Kontrollera belysning per tangent.\"\n\n#: lib/logitech_receiver/settings_templates.py:1786\nmsgid \"Force Sensing Buttons\"\nmsgstr \"Kraftavkännande knappar\"\n\n#: lib/logitech_receiver/settings_templates.py:1787\nmsgid \"Change the force required to activate button.\"\nmsgstr \"Ändra den kraft som krävs för att aktivera knappen.\"\n\n#: lib/logitech_receiver/settings_templates.py:1804\nmsgid \"Force Sensing Button\"\nmsgstr \"Kraftavkännande knapp\"\n\n#: lib/logitech_receiver/settings_templates.py:1814\nmsgid \"Haptic Feeback Level\"\nmsgstr \"Haptisk återkopplingsnivå\"\n\n#: lib/logitech_receiver/settings_templates.py:1815\nmsgid \"Change power of haptic feedback.  (Zero to turn off.)\"\nmsgstr \"\"\n\"Ändra styrkan på den haptiska återkopplingen.  (Noll för att stänga av.)\"\n\n#: lib/logitech_receiver/settings_templates.py:1857\nmsgid \"Play Haptic Waveform\"\nmsgstr \"Spela upp haptisk vågform\"\n\n#: lib/logitech_receiver/settings_templates.py:1858\nmsgid \"Tell device to play a haptic waveform.\"\nmsgstr \"Be enheten att spela upp en haptisk vågform.\"\n\n#: lib/solaar/ui/__init__.py:120\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"En annan Solaar-process körs redan så bara exponera dess fönster\"\n\n#: lib/solaar/ui/about/model.py:36\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"Hanterar Logitech-mottagare,\\n\"\n\"tangentbord, möss och surfplattor.\"\n\n#: lib/solaar/ui/about/model.py:63\nmsgid \"Additional Programming\"\nmsgstr \"Ytterligare programmering\"\n\n#: lib/solaar/ui/about/model.py:64\nmsgid \"GUI design\"\nmsgstr \"Grafisk design av användargränssnitt\"\n\n#: lib/solaar/ui/about/model.py:66\nmsgid \"Testing\"\nmsgstr \"Testning\"\n\n#: lib/solaar/ui/about/model.py:74\nmsgid \"Logitech documentation\"\nmsgstr \"Logitech-dokumentation\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92\n#: lib/solaar/ui/window.py:208\nmsgid \"Unpair\"\nmsgstr \"Bryt parkoppling\"\n\n#: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141\nmsgid \"Cancel\"\nmsgstr \"Avbryt\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Permissions error\"\nmsgstr \"Behörighetsfel\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"\"\n\"Hittade en Logitech-mottagare eller enhet (%s), men hade inte behörighet att \"\n\"öppna den.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"\"\n\"Om du precis har installerat Solaar, försök att koppla bort mottagaren eller \"\n\"enheten och sedan återansluta den.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Cannot connect to device error\"\nmsgstr \"Kan inte ansluta till enhet-fel\"\n\n#: lib/solaar/ui/common.py:51\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"Hittade en Logitech-mottagare eller enhet på %s, men stötte på ett fel vid \"\n\"anslutning till den.\"\n\n#: lib/solaar/ui/common.py:53\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"\"\n\"Försök att koppla bort enheten och sedan återansluta den eller stänga av och \"\n\"sedan på den.\"\n\n#: lib/solaar/ui/common.py:56\nmsgid \"Unpairing failed\"\nmsgstr \"Kunde inte bryta parkoppling\"\n\n#: lib/solaar/ui/common.py:58\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"Misslyckades att bryta parkoppling mellan %{device} och %{receiver}.\"\n\n#: lib/solaar/ui/common.py:63\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"Mottagaren rapporterade ett fel, utan ytterligare detaljer.\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Complete - ENTER to change\"\nmsgstr \"Komplett - ENTER för att ändra\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Incomplete\"\nmsgstr \"Ofullständig\"\n\n#: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d värde\"\nmsgstr[1] \"%d värden\"\n\n#: lib/solaar/ui/config_panel.py:642\nmsgid \"Changes allowed\"\nmsgstr \"Ändringar tillåtna\"\n\n#: lib/solaar/ui/config_panel.py:643\nmsgid \"No changes allowed\"\nmsgstr \"Inga ändringar tillåtna\"\n\n#: lib/solaar/ui/config_panel.py:644\nmsgid \"Ignore this setting\"\nmsgstr \"Ignorera denna inställning\"\n\n#: lib/solaar/ui/config_panel.py:690\nmsgid \"Working\"\nmsgstr \"Fungerar\"\n\n#: lib/solaar/ui/config_panel.py:693\nmsgid \"Read/write operation failed.\"\nmsgstr \"Läs-/skrivoperationen misslyckades.\"\n\n#: lib/solaar/ui/desktop_notifications.py:112\nmsgid \"unspecified reason\"\nmsgstr \"ospecificerad anledning\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"Built-in rules\"\nmsgstr \"Inbyggda regler\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"User-defined rules\"\nmsgstr \"Användardefinierade regler\"\n\n#: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126\nmsgid \"Rule\"\nmsgstr \"Regel\"\n\n#: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382\n#: lib/solaar/ui/diversion_rules.py:509\nmsgid \"Sub-rule\"\nmsgstr \"Underregel\"\n\n#: lib/solaar/ui/diversion_rules.py:108\nmsgid \"[empty]\"\nmsgstr \"[tom]\"\n\n#: lib/solaar/ui/diversion_rules.py:132\nmsgid \"Make changes permanent?\"\nmsgstr \"Göra ändringarna permanenta?\"\n\n#: lib/solaar/ui/diversion_rules.py:137\nmsgid \"Yes\"\nmsgstr \"Ja\"\n\n#: lib/solaar/ui/diversion_rules.py:139\nmsgid \"No\"\nmsgstr \"Nej\"\n\n#: lib/solaar/ui/diversion_rules.py:144\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"Om du väljer Nej kommer ändringar att gå förlorade när Solaar stängs.\"\n\n#: lib/solaar/ui/diversion_rules.py:273\nmsgid \"Paste here\"\nmsgstr \"Klistra in här\"\n\n#: lib/solaar/ui/diversion_rules.py:275\nmsgid \"Paste above\"\nmsgstr \"Klistra in ovan\"\n\n#: lib/solaar/ui/diversion_rules.py:277\nmsgid \"Paste below\"\nmsgstr \"Klistra in nedan\"\n\n#: lib/solaar/ui/diversion_rules.py:283\nmsgid \"Paste rule here\"\nmsgstr \"Klistra in regeln här\"\n\n#: lib/solaar/ui/diversion_rules.py:285\nmsgid \"Paste rule above\"\nmsgstr \"Klistra in regeln ovan\"\n\n#: lib/solaar/ui/diversion_rules.py:287\nmsgid \"Paste rule below\"\nmsgstr \"Klistra in regeln nedan\"\n\n#: lib/solaar/ui/diversion_rules.py:291\nmsgid \"Paste rule\"\nmsgstr \"Klistra in regel\"\n\n#: lib/solaar/ui/diversion_rules.py:306\nmsgid \"Insert here\"\nmsgstr \"Infoga här\"\n\n#: lib/solaar/ui/diversion_rules.py:308\nmsgid \"Insert above\"\nmsgstr \"Infoga ovan\"\n\n#: lib/solaar/ui/diversion_rules.py:310\nmsgid \"Insert below\"\nmsgstr \"Infoga nedan\"\n\n#: lib/solaar/ui/diversion_rules.py:316\nmsgid \"Insert new rule here\"\nmsgstr \"Infoga ny regel här\"\n\n#: lib/solaar/ui/diversion_rules.py:318\nmsgid \"Insert new rule above\"\nmsgstr \"Infoga ny regel ovan\"\n\n#: lib/solaar/ui/diversion_rules.py:320\nmsgid \"Insert new rule below\"\nmsgstr \"Infoga ny regel nedan\"\n\n#: lib/solaar/ui/diversion_rules.py:347\nmsgid \"Flatten\"\nmsgstr \"Platta till\"\n\n#: lib/solaar/ui/diversion_rules.py:380\nmsgid \"Insert\"\nmsgstr \"Infoga\"\n\n#: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511\n#: lib/solaar/ui/diversion_rules.py:1158\nmsgid \"Or\"\nmsgstr \"Eller\"\n\n#: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510\n#: lib/solaar/ui/diversion_rules.py:1144\nmsgid \"And\"\nmsgstr \"Och\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid \"Condition\"\nmsgstr \"Villkor\"\n\n#: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154\nmsgid \"Feature\"\nmsgstr \"Funktion\"\n\n#: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188\nmsgid \"Report\"\nmsgstr \"Rapport\"\n\n#: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69\nmsgid \"Process\"\nmsgstr \"Process\"\n\n#: lib/solaar/ui/diversion_rules.py:391\nmsgid \"Mouse process\"\nmsgstr \"Musprocess\"\n\n#: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225\nmsgid \"Modifiers\"\nmsgstr \"Modifierare\"\n\n#: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277\nmsgid \"Key\"\nmsgstr \"Tangent\"\n\n#: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318\nmsgid \"KeyIsDown\"\nmsgstr \"KeyIsDown\"\n\n#: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432\nmsgid \"Active\"\nmsgstr \"Aktiv\"\n\n#: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390\n#: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487\nmsgid \"Device\"\nmsgstr \"Enhet\"\n\n#: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467\nmsgid \"Host\"\nmsgstr \"Värd\"\n\n#: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506\nmsgid \"Setting\"\nmsgstr \"Inställning\"\n\n#: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333\n#: lib/solaar/ui/rule_conditions.py:382\nmsgid \"Test\"\nmsgstr \"Testa\"\n\n#: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507\nmsgid \"Test bytes\"\nmsgstr \"Testa byte\"\n\n#: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608\nmsgid \"Mouse Gesture\"\nmsgstr \"Musgest\"\n\n#: lib/solaar/ui/diversion_rules.py:405\nmsgid \"Action\"\nmsgstr \"Åtgärd\"\n\n#: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138\nmsgid \"Key press\"\nmsgstr \"Knapptryckning\"\n\n#: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191\nmsgid \"Mouse scroll\"\nmsgstr \"Musrullning\"\n\n#: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256\nmsgid \"Mouse click\"\nmsgstr \"Musklick\"\n\n#: lib/solaar/ui/diversion_rules.py:410\nmsgid \"Set\"\nmsgstr \"Ställ in\"\n\n#: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328\nmsgid \"Execute\"\nmsgstr \"Utför\"\n\n#: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189\nmsgid \"Later\"\nmsgstr \"Senare\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid \"Insert new rule\"\nmsgstr \"Infoga ny regel\"\n\n#: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82\n#: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556\nmsgid \"Delete\"\nmsgstr \"Ta bort\"\n\n#: lib/solaar/ui/diversion_rules.py:483\nmsgid \"Negate\"\nmsgstr \"Negera\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid \"Wrap with\"\nmsgstr \"Omslut med\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid \"Cut\"\nmsgstr \"Klipp ut\"\n\n#: lib/solaar/ui/diversion_rules.py:553\nmsgid \"Paste\"\nmsgstr \"Klistra in\"\n\n#: lib/solaar/ui/diversion_rules.py:559\nmsgid \"Copy\"\nmsgstr \"Kopiera\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Solaar regelredigerare\"\n\n#: lib/solaar/ui/diversion_rules.py:668\nmsgid \"Save changes\"\nmsgstr \"Spara ändringar\"\n\n#: lib/solaar/ui/diversion_rules.py:673\nmsgid \"Discard changes\"\nmsgstr \"Släng ändringar\"\n\n#: lib/solaar/ui/diversion_rules.py:1104\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"Denna redigerare stöder inte den valda regelkomponenten ännu.\"\n\n#: lib/solaar/ui/diversion_rules.py:1169\nmsgid \"\"\n\"Number of seconds to delay.  Delay between 0 and 1 is done with higher \"\n\"precision.\"\nmsgstr \"\"\n\"Antal sekunder att fördröja.  Fördröjning mellan 0 och 1 görs med högre \"\n\"precision.\"\n\n#: lib/solaar/ui/diversion_rules.py:1207\nmsgid \"Not\"\nmsgstr \"Inte\"\n\n#: lib/solaar/ui/diversion_rules.py:1238\nmsgid \"Toggle\"\nmsgstr \"Växla\"\n\n#: lib/solaar/ui/diversion_rules.py:1239\nmsgid \"True\"\nmsgstr \"Sant\"\n\n#: lib/solaar/ui/diversion_rules.py:1240\nmsgid \"False\"\nmsgstr \"Falskt\"\n\n#: lib/solaar/ui/diversion_rules.py:1253\nmsgid \"Unsupported setting\"\nmsgstr \"Inställning som inte stöds\"\n\n#: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415\n#: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748\n#: lib/solaar/ui/diversion_rules.py:1766\nmsgid \"Originating device\"\nmsgstr \"Ursprungsenhet\"\n\n#: lib/solaar/ui/diversion_rules.py:1428\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"Enheten är aktiv och dess inställningar kan ändras.\"\n\n#: lib/solaar/ui/diversion_rules.py:1437\nmsgid \"Device that originated the current notification.\"\nmsgstr \"Enhet som skapade det aktuella meddelandet.\"\n\n#: lib/solaar/ui/diversion_rules.py:1450\nmsgid \"Name of host computer.\"\nmsgstr \"Namn på värddator.\"\n\n#: lib/solaar/ui/diversion_rules.py:1520\nmsgid \"Value\"\nmsgstr \"Värde\"\n\n#: lib/solaar/ui/diversion_rules.py:1529\nmsgid \"Item\"\nmsgstr \"Objekt\"\n\n#: lib/solaar/ui/diversion_rules.py:1808\nmsgid \"Change setting on device\"\nmsgstr \"Ändra inställning på enheten\"\n\n#: lib/solaar/ui/diversion_rules.py:1824\nmsgid \"Setting on device\"\nmsgstr \"Inställning på enheten\"\n\n#: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: parkoppla ny enhet\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Bolt-mottagare är endast kompatibla med Bolt-enheter.\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"\"\n\"Tryck på en parkopplingstangent eller -knapp tills parkopplingslampan \"\n\"blinkar snabbt.\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"Unifying-mottagare är endast kompatibla med Unifying-enheter.\"\n\n#: lib/solaar/ui/pair_window.py:53\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"Andra mottagare är endast kompatibla med ett fåtal enheter.\"\n\n#: lib/solaar/ui/pair_window.py:55\nmsgid \"For most devices, turn on the device you want to pair.\"\nmsgstr \"För de flesta enheter, slå på den enhet du vill para ihop.\"\n\n#: lib/solaar/ui/pair_window.py:56\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"Om enheten redan är påslagen, stäng av och sätt på den igen.\"\n\n#: lib/solaar/ui/pair_window.py:58\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"Enheten får inte parkopplas med en närliggande påslagen mottagare.\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid \"\"\n\"For devices with multiple channels, press, hold, and release the button for \"\n\"the channel you wish to pair\\n\"\n\"or use the channel switch button to select a channel and then press, hold, \"\n\"and release the channel switch button.\"\nmsgstr \"\"\n\"För enheter med flera kanaler, tryck, håll ned och släpp knappen för den \"\n\"kanal du vill para ihop eller använd\\n\"\n\"kanalväxlingsknappen för att välja en kanal och tryck sedan, håll ned och \"\n\"släpp kanalväxlingsknappen.\"\n\n#: lib/solaar/ui/pair_window.py:68\nmsgid \"The channel indicator light should be blinking rapidly.\"\nmsgstr \"Lampan för kanalindikator ska blinka snabbt.\"\n\n#: lib/solaar/ui/pair_window.py:72\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"Denna mottagare har %d parkoppling kvar.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"Denna mottagare har %d parkopplingar kvar.\"\n\n#: lib/solaar/ui/pair_window.py:78\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"Avbrytning vid detta tillfälle kommer inte att förbruka en parkoppling.\"\n\n#: lib/solaar/ui/pair_window.py:168\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"Ange lösenkoden på %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:171\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"Skriv %(passcode)s och tryck sedan på enter-tangenten.\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"left\"\nmsgstr \"vänster\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"right\"\nmsgstr \"höger\"\n\n#: lib/solaar/ui/pair_window.py:178\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"Tryck på %(code)s\\n\"\n\"och tryck sedan på vänster och höger knappar samtidigt.\"\n\n#: lib/solaar/ui/pair_window.py:221\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"Den trådlösa anslutningen är inte krypterad\"\n\n#: lib/solaar/ui/pair_window.py:226\nmsgid \"Found a new device:\"\nmsgstr \"Hittade en ny enhet:\"\n\n#: lib/solaar/ui/pair_window.py:247\nmsgid \"Pairing failed\"\nmsgstr \"Parkoppling misslyckades\"\n\n#: lib/solaar/ui/pair_window.py:249\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"\"\n\"Se till att din enhet är inom räckhåll och har tillräckligt laddat batteri.\"\n\n#: lib/solaar/ui/pair_window.py:251\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"\"\n\"En ny enhet upptäcktes, men den är inte kompatibel med denna mottagare.\"\n\n#: lib/solaar/ui/pair_window.py:253\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"Fler parkopplade enheter än vad mottagaren kan stöda.\"\n\n#: lib/solaar/ui/pair_window.py:255\nmsgid \"No further details are available about the error.\"\nmsgstr \"Inga ytterligare detaljer finns tillgängliga om felet.\"\n\n#: lib/solaar/ui/rule_actions.py:54\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simulera ett ackorderat tangentklick eller tryck ner eller släpp.\\n\"\n\"I Wayland krävs skrivåtkomst till /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:60\nmsgid \"Add key\"\nmsgstr \"Lägg till tangent\"\n\n#: lib/solaar/ui/rule_actions.py:63\nmsgid \"Click\"\nmsgstr \"Klick\"\n\n#: lib/solaar/ui/rule_actions.py:66\nmsgid \"Depress\"\nmsgstr \"Tryck ned\"\n\n#: lib/solaar/ui/rule_actions.py:69\nmsgid \"Release\"\nmsgstr \"Släppa\"\n\n#: lib/solaar/ui/rule_actions.py:153\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simulera en musrullning.\\n\"\n\"I Wayland krävs skrivåtkomst till /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:211\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Simulera ett musklick.\\n\"\n\"I Wayland krävs skrivåtkomst till /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:216\nmsgid \"Button\"\nmsgstr \"Knapp\"\n\n#: lib/solaar/ui/rule_actions.py:218\nmsgid \"Action (and Count, if click)\"\nmsgstr \"Åtgärd (och räkna, om klick)\"\n\n#: lib/solaar/ui/rule_actions.py:269\nmsgid \"Execute a command with arguments.\"\nmsgstr \"Utför ett kommando med argument.\"\n\n#: lib/solaar/ui/rule_actions.py:273\nmsgid \"Add argument\"\nmsgstr \"Lägg till argument\"\n\n#: lib/solaar/ui/rule_conditions.py:52\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"X11 aktiv process. Endast för användning i X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:82\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"X11 musprocess. Endast för användning i X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:99\nmsgid \"MouseProcess\"\nmsgstr \"MouseProcess\"\n\n#: lib/solaar/ui/rule_conditions.py:123\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"Funktionsnamn för avisering som utlöser regelbearbetning.\"\n\n#: lib/solaar/ui/rule_conditions.py:169\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"Rapportnummer för avisering som utlöser regelbearbetning.\"\n\n#: lib/solaar/ui/rule_conditions.py:201\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"Aktiva tangentbordsmodifierare. Inte alltid tillgängligt i Wayland.\"\n\n#: lib/solaar/ui/rule_conditions.py:241\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Omdirigerad knapp eller knapp nedtryckt eller släppt.\\n\"\n\"Använd inställningarna för vidarekoppling av tangent/knapp och \"\n\"vidarekoppling av G-tangenter för att vidarekoppla tangenter och knappar.\"\n\n#: lib/solaar/ui/rule_conditions.py:250\nmsgid \"Key down\"\nmsgstr \"Tangent ner\"\n\n#: lib/solaar/ui/rule_conditions.py:253\nmsgid \"Key up\"\nmsgstr \"Tangent upp\"\n\n#: lib/solaar/ui/rule_conditions.py:293\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Vidarekopplad nyckel eller knapp är för närvarande nere.\\n\"\n\"Använd inställningarna för vidarekoppling av tangent/knapp och \"\n\"vidarekoppling av G-tangenter för att vidarekoppla tangenter och knappar.\"\n\n#: lib/solaar/ui/rule_conditions.py:331\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"Testvillkor för meddelande som utlöser regelbearbetning.\"\n\n#: lib/solaar/ui/rule_conditions.py:335\nmsgid \"Parameter\"\nmsgstr \"Parameter\"\n\n#: lib/solaar/ui/rule_conditions.py:408\nmsgid \"begin (inclusive)\"\nmsgstr \"börja (inklusive)\"\n\n#: lib/solaar/ui/rule_conditions.py:409\nmsgid \"end (exclusive)\"\nmsgstr \"slut (exklusivt)\"\n\n#: lib/solaar/ui/rule_conditions.py:417\nmsgid \"range\"\nmsgstr \"omfång\"\n\n#: lib/solaar/ui/rule_conditions.py:420\nmsgid \"minimum\"\nmsgstr \"minimum\"\n\n#: lib/solaar/ui/rule_conditions.py:421\nmsgid \"maximum\"\nmsgstr \"maximum\"\n\n#: lib/solaar/ui/rule_conditions.py:423\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"byte %(0)d till %(1)d, från %(2)d till %(3)d\"\n\n#: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427\nmsgid \"mask\"\nmsgstr \"mask\"\n\n#: lib/solaar/ui/rule_conditions.py:428\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"byte %(0)d till %(1)d, mask %(2)d\"\n\n#: lib/solaar/ui/rule_conditions.py:437\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\"Bit- eller omfångstest på byte i aviseringsmeddelande som utlöser \"\n\"regelbearbetning.\"\n\n#: lib/solaar/ui/rule_conditions.py:447\nmsgid \"type\"\nmsgstr \"typ\"\n\n#: lib/solaar/ui/rule_conditions.py:535\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"\"\n\"Musgest med valfri initieringsknapp följt av noll eller fler musrörelser.\"\n\n#: lib/solaar/ui/rule_conditions.py:541\nmsgid \"Add movement\"\nmsgstr \"Lägg till rörelse\"\n\n#: lib/solaar/ui/tray.py:55\nmsgid \"No supported device found\"\nmsgstr \"Ingen enhet som stöds hittades\"\n\n#: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328\n#, python-format\nmsgid \"About %s\"\nmsgstr \"Om %s\"\n\n#: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"Avsluta %s\"\n\n#: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281\nmsgid \"no receiver\"\nmsgstr \"ingen mottagare\"\n\n#: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299\n#: lib/solaar/ui/window.py:728\nmsgid \"offline\"\nmsgstr \"frånkopplad\"\n\n#: lib/solaar/ui/tray.py:297\nmsgid \"no status\"\nmsgstr \"ingen status\"\n\n#: lib/solaar/ui/window.py:110\nmsgid \"Scanning\"\nmsgstr \"Skannar\"\n\n#: lib/solaar/ui/window.py:141\nmsgid \"Battery\"\nmsgstr \"Batteri\"\n\n#: lib/solaar/ui/window.py:144\nmsgid \"Wireless Link\"\nmsgstr \"Trådlös anslutning\"\n\n#: lib/solaar/ui/window.py:148\nmsgid \"Lighting\"\nmsgstr \"Belysning\"\n\n#: lib/solaar/ui/window.py:182\nmsgid \"Show Technical Details\"\nmsgstr \"Visa tekniska detaljer\"\n\n#: lib/solaar/ui/window.py:198\nmsgid \"Pair new device\"\nmsgstr \"Parkoppla ny enhet\"\n\n#: lib/solaar/ui/window.py:216\nmsgid \"Select a device\"\nmsgstr \"Välj en enhet\"\n\n#: lib/solaar/ui/window.py:331\nmsgid \"Rule Editor\"\nmsgstr \"Regelredigerare\"\n\n#: lib/solaar/ui/window.py:522\nmsgid \"Path\"\nmsgstr \"Sökväg\"\n\n#: lib/solaar/ui/window.py:524\nmsgid \"USB ID\"\nmsgstr \"USB-ID\"\n\n#: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529\n#: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546\nmsgid \"Serial\"\nmsgstr \"Seriell\"\n\n#: lib/solaar/ui/window.py:533\nmsgid \"Index\"\nmsgstr \"Index\"\n\n#: lib/solaar/ui/window.py:535\nmsgid \"Wireless PID\"\nmsgstr \"Trådlös-PID\"\n\n#: lib/solaar/ui/window.py:537\nmsgid \"Product ID\"\nmsgstr \"Produkt-ID\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Protocol\"\nmsgstr \"Protokoll\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Unknown\"\nmsgstr \"Okänd\"\n\n#: lib/solaar/ui/window.py:541\nmsgid \"Polling rate\"\nmsgstr \"Uppdateringshastighet\"\n\n#: lib/solaar/ui/window.py:548\nmsgid \"Unit ID\"\nmsgstr \"Enhets-ID\"\n\n#: lib/solaar/ui/window.py:559\nmsgid \"none\"\nmsgstr \"ingen\"\n\n#: lib/solaar/ui/window.py:560\nmsgid \"Notifications\"\nmsgstr \"Aviseringar\"\n\n#: lib/solaar/ui/window.py:604\nmsgid \"No device paired.\"\nmsgstr \"Ingen enhet parkopplad.\"\n\n#: lib/solaar/ui/window.py:613\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"Upp till %(max_count)s enhet kan parkopplas med denna mottagare.\"\nmsgstr[1] \"Upp till %(max_count)s enheter kan parkopplas med denna mottagare.\"\n\n#: lib/solaar/ui/window.py:620\nmsgid \"Only one device can be paired to this receiver.\"\nmsgstr \"Endast en enhet kan parkopplas ihop med denna mottagare.\"\n\n#: lib/solaar/ui/window.py:624\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"Denna mottagare har %d parkoppling kvar.\"\nmsgstr[1] \"Denna mottagare har %d parkopplingar kvar.\"\n\n#: lib/solaar/ui/window.py:681\nmsgid \"Battery Voltage\"\nmsgstr \"Batterispänning\"\n\n#: lib/solaar/ui/window.py:683\nmsgid \"Voltage reported by battery\"\nmsgstr \"Spänning rapporterad av batteri\"\n\n#: lib/solaar/ui/window.py:685\nmsgid \"Battery Level\"\nmsgstr \"Batterinivå\"\n\n#: lib/solaar/ui/window.py:687\nmsgid \"Approximate level reported by battery\"\nmsgstr \"Ungefärlig nivå rapporterad av batteriet\"\n\n#: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696\nmsgid \"next reported \"\nmsgstr \"nästa rapporterade \"\n\n#: lib/solaar/ui/window.py:697\nmsgid \" and next level to be reported.\"\nmsgstr \" och nästa nivå som ska rapporteras.\"\n\n#: lib/solaar/ui/window.py:702\nmsgid \"last known\"\nmsgstr \"senast kända\"\n\n#: lib/solaar/ui/window.py:713\nmsgid \"encrypted\"\nmsgstr \"krypterad\"\n\n#: lib/solaar/ui/window.py:715\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"\"\n\"Den trådlösa anslutningen mellan denna enheten och dess mottagare är \"\n\"krypterad.\"\n\n#: lib/solaar/ui/window.py:717\nmsgid \"not encrypted\"\nmsgstr \"inte krypterad\"\n\n#: lib/solaar/ui/window.py:721\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"Den trådlösa anslutningen mellan den här enheten och dess mottagare är inte \"\n\"krypterad.\\n\"\n\"Detta är ett säkerhetsproblem för pekdon och ett stort säkerhetsproblem för \"\n\"enheter för textinmatning.\"\n\n#: lib/solaar/ui/window.py:737\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d lux\"\n\n#~ msgid \"Turn illumination on or off on keyboard.\"\n#~ msgstr \"Slå på eller stäng av belysningen på tangentbordet.\"\n\n#~ msgid \"\"\n#~ \"Enable onboard profiles, which often control report rate and keyboard \"\n#~ \"lighting\"\n#~ msgstr \"\"\n#~ \"Aktivera inbyggda profiler, som ofta styr rapporthastighet och \"\n#~ \"tangentbordsbelysning\"\n\n#~ msgid \"Polling Rate (ms)\"\n#~ msgstr \"Uppdateringsfrekvens (ms)\"\n\n#~ msgid \"Frequency of device polling, in milliseconds\"\n#~ msgstr \"Frekvens för enhetsavfrågning, i millisekunder\"\n\n#~ msgid \"Divert G Keys\"\n#~ msgstr \"Avleda G-tangenter\"\n\n#~ msgid \"\"\n#~ \"Make G keys send GKEY HID++ notifications (which trigger Solaar rules but \"\n#~ \"are otherwise ignored).\"\n#~ msgstr \"\"\n#~ \"Få G-tangenter att skicka GKEY HID++-aviseringar (som utlöser Solaar-\"\n#~ \"regler men som annars ignoreras).\"\n\n#~ msgid \"May also make M keys and MR key send HID++ notifications\"\n#~ msgstr \"\"\n#~ \"Kan också få M-tangenter och MR-tangenten att skicka HID++-aviseringar\"\n\n#, python-format\n#~ msgid \"Battery: %(level)s\"\n#~ msgstr \"Batteri: %(level)s\"\n\n#, python-format\n#~ msgid \"Battery: %(percent)d%%\"\n#~ msgstr \"Batteri: %(percent)d%%\"\n\n#, python-format\n#~ msgid \"Lighting: %(level)s lux\"\n#~ msgstr \"Belysning: %(level)s lux\"\n\n#~ msgid \"Number of seconds to delay.\"\n#~ msgstr \"Antal sekunder att fördröja.\"\n\n#~ msgid \"Count and Action\"\n#~ msgstr \"Antal och åtgärd\"\n\n#~ msgid \"You may have to first turn the device off and on again.\"\n#~ msgstr \"Du kanske först måste stänga av enheten och slå på den igen.\"\n\n#~ msgid \"Turn on the device you want to pair.\"\n#~ msgstr \"Slå på enheten du vill parkoppla.\"\n\n#, python-format\n#~ msgid \"%(rate)d ms (%(rate_hz)dHz)\"\n#~ msgstr \"%(rate)d ms (%(rate_hz)dHz)\"\n\n#~ msgid \"\"\n#~ \"\\n\"\n#~ \"\\n\"\n#~ \"This receiver has %d pairing(s) remaining.\"\n#~ msgstr \"\"\n#~ \"\\n\"\n#~ \"\\n\"\n#~ \"Denna mottagare har %d parning(er) kvar.\"\n\n#~ msgid \" paired devices.\"\n#~ msgstr \"parkopplade enheter.\"\n\n#~ msgid \"%(battery_level)s\"\n#~ msgstr \"%(battery_level)s\"\n\n#~ msgid \"%(battery_percent)d%%\"\n#~ msgstr \"%(battery_percent)d%%\"\n\n#~ msgid \"1 paired device.\"\n#~ msgstr \"1 parkopplad enhet.\"\n\n#~ msgid \"Actions\"\n#~ msgstr \"Åtgärder\"\n\n#~ msgid \"\"\n#~ \"Automatically switch the mouse wheel between ratchet and freespin mode.\\n\"\n#~ \"The mouse wheel is always free at 0, and always locked at 50\"\n#~ msgstr \"\"\n#~ \"Växla automatiskt mushjulet mellan spärr- och frispinn-läge.\\n\"\n#~ \"Mushjulet är alltid fritt vid 0 och låses alltid vid 50\"\n\n#~ msgid \"Count\"\n#~ msgstr \"Antal\"\n\n#~ msgid \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr \"Stänger effektivt av tumrullning i Linux.\"\n\n#~ msgid \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr \"Stänger effektivt av rullning i Linux.\"\n\n#~ msgid \"\"\n#~ \"For more information see the Solaar installation directions\\n\"\n#~ \"at https://pwr-solaar.github.io/Solaar/installation\"\n#~ msgstr \"\"\n#~ \"Mer information finns i Solaar-installationsanvisningarna\\n\"\n#~ \"på https://pwr-solaar.github.io/Solaar/installation\"\n\n#, python-format\n#~ msgid \"\"\n#~ \"Found a Logitech Receiver (%s), but did not have permission to open it.\"\n#~ msgstr \"\"\n#~ \"En Logitech mottagare hittades (%s), fast saknar behörighet till att \"\n#~ \"öppna den.\"\n\n#~ msgid \"Found a new device\"\n#~ msgstr \"Ny enhet har hittats\"\n\n#~ msgid \"HID++ Scrolling\"\n#~ msgstr \"HID++ rullning\"\n\n#~ msgid \"HID++ Thumb Scrolling\"\n#~ msgstr \"HID++ thumrullning\"\n\n#~ msgid \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr \"HID ++ -läge för horisontell rullning med tumhjulet.\"\n\n#~ msgid \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr \"HID++ läge för vertikal rullning med hjulet.\"\n\n#~ msgid \"High Resolution Scrolling\"\n#~ msgstr \"Rullning med hög upplösning\"\n\n#~ msgid \"High Resolution Wheel Invert\"\n#~ msgstr \"Invertera hög hjulupplösning\"\n\n#~ msgid \"High-sensitivity wheel invert direction for vertical scroll.\"\n#~ msgstr \"Invertera riktning för vertikal rullning med hög känslighet.\"\n\n#~ msgid \"High-sensitivity wheel invert mode for vertical scroll.\"\n#~ msgstr \"Inverteringsläge med hög känslighet för vertikal rullning.\"\n\n#~ msgid \"\"\n#~ \"If the device is already turned on,\\n\"\n#~ \"turn if off and on again.\"\n#~ msgstr \"\"\n#~ \"Om enheten redan är igång,\\n\"\n#~ \"stäng av den och sätt på den igen.\"\n\n#~ msgid \"If the device is already turned on, turn if off and on again.\"\n#~ msgstr \"Om enheten redan är påslagen, stäng av og slå den på igen.\"\n\n#~ msgid \"\"\n#~ \"If you've just installed Solaar, try removing the receiver and plugging \"\n#~ \"it back in.\"\n#~ msgstr \"\"\n#~ \"Om du just installerade solaar, prova koppla ur mottagaren och anslut den \"\n#~ \"sedan igen.\"\n\n#~ msgid \"Invert thumb scroll direction.\"\n#~ msgstr \"Invertera tumrulleriktningen.\"\n\n#~ msgid \"No Logitech receiver found\"\n#~ msgstr \"Ingen Logitech mottagare hittades\"\n\n#~ msgid \"No device paired\"\n#~ msgstr \"Inga enheter parkopplade\"\n\n#~ msgid \"Only one device can be paired to this receiver\"\n#~ msgstr \"Bara en enhet kan parkopplas till den här mottagaren\"\n\n#~ msgid \"\"\n#~ \"Shows status of devices connected\\n\"\n#~ \"through wireless Logitech receivers.\"\n#~ msgstr \"\"\n#~ \"Visar status för enheter kopplade till\\n\"\n#~ \"din trådlösa Logitech mottagare.\"\n\n#~ msgid \"Smooth Scrolling\"\n#~ msgstr \"Mjuk rullning\"\n\n#~ msgid \"Solaar depends on a udev file that is not present\"\n#~ msgstr \"Solaar beror på en udev-fil som inte finns\"\n\n#~ msgid \"The receiver only supports %d paired device(s).\"\n#~ msgstr \"Mottagaren klarar bara %d parkopplad(e) enhet(er).\"\n\n#~ msgid \"The receiver was unplugged.\"\n#~ msgstr \"Mottagaren kopplades ur.\"\n\n#~ msgid \"\"\n#~ \"The wireless link between this device and its receiver is not encrypted.\\n\"\n#~ \"\\n\"\n#~ \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~ \"security issue.\\n\"\n#~ \"\\n\"\n#~ \"It is, however, a major security issue for text-input devices (keyboards, \"\n#~ \"numpads),\\n\"\n#~ \"because typed text can be sniffed inconspicuously by 3rd parties within \"\n#~ \"range.\"\n#~ msgstr \"\"\n#~ \"Den trådlösa anslutningen mellan den här enheten och mottagaren är \"\n#~ \"okrypterad\\n\"\n#~ \"\\n\"\n#~ \"För pekdon (möss, styrkulor, pekplattor), är detta inget stort \"\n#~ \"säkerhetsproblem.\\n\"\n#~ \"\\n\"\n#~ \"Men för textinmatande enheter (tangentbord, numpads) är denna \"\n#~ \"säkerhetsbrist\\n\"\n#~ \"allvarlig, eftersom skriven text obemärkt kan fångas upp av tredje part \"\n#~ \"som\\n\"\n#~ \"befinner sig inom enhetens räckhåll.\"\n\n#~ msgid \"This receiver has %d pairing(s) remaining.\"\n#~ msgstr \"Denna mottagare har %d parning(er) kvar.\"\n\n#~ msgid \"Thumb Scroll Invert\"\n#~ msgstr \"Invertera tumrullningen\"\n\n#~ msgid \"USB id\"\n#~ msgstr \"USB-id\"\n\n#~ msgid \"Unexpected device number (%s) in notification %s.\"\n#~ msgstr \"Oväntat enhetsnummer (%s) i meddelandet %s.\"\n\n#~ msgid \"Up to %d devices can be paired to this receiver\"\n#~ msgstr \"Upp till %d enheter kan parkopplas till mottagaren\"\n\n#~ msgid \"Wheel Resolution\"\n#~ msgstr \"Hjulupplösning\"\n\n#~ msgid \"closed\"\n#~ msgstr \"inaktiverat\"\n\n#~ msgid \"height\"\n#~ msgstr \"höjd\"\n\n#~ msgid \"lux\"\n#~ msgstr \"lux\"\n\n#~ msgid \"next \"\n#~ msgstr \"nästa \"\n\n#~ msgid \"open\"\n#~ msgstr \"aktiverat\"\n\n#~ msgid \"pair new device\"\n#~ msgstr \"parkoppla ny enhet\"\n\n#~ msgid \"paired devices\"\n#~ msgstr \"parkopplade enheter\"\n\n#~ msgid \"pairing lock is \"\n#~ msgstr \"parkopplingslåset är \"\n\n#~ msgid \"unknown\"\n#~ msgstr \"okänd\"\n\n#~ msgid \"width\"\n#~ msgstr \"bredd\"\n"
  },
  {
    "path": "po/tr.po",
    "content": "# Turkish translations for solaar package.\n# Copyright (C) 2015 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2015.\n#\n# Behzat Erte, <b3hzat@gmail.com>, 2015.\n# Osman Karagöz, <osmank3@gmail.com>, 2024.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 0.9.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-07-01 13:49+0800\\n\"\n\"PO-Revision-Date: 2024-11-17 16:01+0300\\n\"\n\"Last-Translator: Osman Karagöz <osmank3@gmail.com>\\n\"\n\"Language-Team: \\n\"\n\"Language: tr\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.4.2\\n\"\n\"X-Poedit-SourceCharset: UTF-8\\n\"\n\n#: lib/logitech_receiver/base_usb.py:45\nmsgid \"Bolt Receiver\"\nmsgstr \"Bolt Alıcı\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid \"Unifying Receiver\"\nmsgstr \"Unifying Alıcı\"\n\n#: lib/logitech_receiver/base_usb.py:68 lib/logitech_receiver/base_usb.py:80\n#: lib/logitech_receiver/base_usb.py:93 lib/logitech_receiver/base_usb.py:106\n#: lib/logitech_receiver/base_usb.py:119\nmsgid \"Nano Receiver\"\nmsgstr \"Nano Alıcı\"\n\n#: lib/logitech_receiver/base_usb.py:131\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Lightspeed Alıcı\"\n\n#: lib/logitech_receiver/base_usb.py:141\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"EX100 27 Mhz Alıcı\"\n\n#: lib/logitech_receiver/common.py:610\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"Pil: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:613\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"Pil: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:921\n#: lib/logitech_receiver/settings_templates.py:283\nmsgid \"Disabled\"\nmsgstr \"Devredışı\"\n\n#: lib/logitech_receiver/hidpp20.py:922\nmsgid \"Static\"\nmsgstr \"Sabit\"\n\n#: lib/logitech_receiver/hidpp20.py:923\nmsgid \"Pulse\"\nmsgstr \"Nabız\"\n\n#: lib/logitech_receiver/hidpp20.py:924\nmsgid \"Cycle\"\nmsgstr \"Döngü\"\n\n#: lib/logitech_receiver/hidpp20.py:925\nmsgid \"Boot\"\nmsgstr \"Önyükleme\"\n\n#: lib/logitech_receiver/hidpp20.py:926\nmsgid \"Demo\"\nmsgstr \"Demo\"\n\n#: lib/logitech_receiver/hidpp20.py:927\nmsgid \"Breathe\"\nmsgstr \"Nefes\"\n\n#: lib/logitech_receiver/hidpp20.py:928\nmsgid \"Ripple\"\nmsgstr \"Dalgalanma\"\n\n#: lib/logitech_receiver/hidpp20.py:929\nmsgid \"Decomposition\"\nmsgstr \"Ayrışma\"\n\n#: lib/logitech_receiver/hidpp20.py:930\nmsgid \"Signature1\"\nmsgstr \"İmza1\"\n\n#: lib/logitech_receiver/hidpp20.py:931\nmsgid \"Signature2\"\nmsgstr \"İmza2\"\n\n#: lib/logitech_receiver/hidpp20.py:932\nmsgid \"CycleS\"\nmsgstr \"DöngüS\"\n\n#: lib/logitech_receiver/hidpp20.py:996\nmsgid \"Unknown Location\"\nmsgstr \"Bilinmeyen Konum\"\n\n#: lib/logitech_receiver/hidpp20.py:997\nmsgid \"Primary\"\nmsgstr \"Birincil\"\n\n#: lib/logitech_receiver/hidpp20.py:998\nmsgid \"Logo\"\nmsgstr \"Logo\"\n\n#: lib/logitech_receiver/hidpp20.py:999\nmsgid \"Left Side\"\nmsgstr \"Sola Taraf\"\n\n#: lib/logitech_receiver/hidpp20.py:1000\nmsgid \"Right Side\"\nmsgstr \"Sağ Taraf\"\n\n#: lib/logitech_receiver/hidpp20.py:1001\nmsgid \"Combined\"\nmsgstr \"Birleşik\"\n\n#: lib/logitech_receiver/hidpp20.py:1002\nmsgid \"Primary 1\"\nmsgstr \"Birincil 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1003\nmsgid \"Primary 2\"\nmsgstr \"Birincil 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1004\nmsgid \"Primary 3\"\nmsgstr \"Birincil 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1005\nmsgid \"Primary 4\"\nmsgstr \"Birincil 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1006\nmsgid \"Primary 5\"\nmsgstr \"Birincil 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1007\nmsgid \"Primary 6\"\nmsgstr \"Birincil 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"boş\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"kritik\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"az\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"ortalama\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"iyi\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"dolu\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"boşalıyor\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"yeniden şarj ediliyor\"\n\n#: lib/logitech_receiver/i18n.py:37\nmsgid \"charging\"\nmsgstr \"şarj ediliyor\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"şarj edilmiyor\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"nerdeyse dolu\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"şarj edildi\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"yavaş yeniden şarj edilme\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"invalid battery\"\nmsgstr \"geçersiz pil\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"sıcaklık hatası\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"hata\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"standart\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"hızlı\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"yavaş\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"aygıt zaman aşımı\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"aygıt desteklenmiyor\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"çok fazla aygıt\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"sıralama zaman aşımı\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid \"Firmware\"\nmsgstr \"Donanım Yazılımı\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"Önyükleme Yazılımı\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"Donanım\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"Diğer\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"Sol Düğme\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"Sag Düğme\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"Orta Düğme\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"Geri Düğmesi\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"İleri Düğmesi\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"Fare Hareketi Düğmesi\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"Akıllı Kaydırma\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"DPI Anahtarı\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"Sola Eğme\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"Sağa Eğme\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"Sol Tıklama\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"Sağ Tıklama\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"Fare Orta Düğmesi\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"Fare Geri Düğmesi\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"Fare İleri Düğmesi\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"Hareket Düğmesi Navigasyonu\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"Fare Tekerleği Sol Düğmesi\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"Fare Tekerleği Sağ Düğmesi\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"basıldı\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"bırakıldı\"\n\n#: lib/logitech_receiver/notifications.py:64\n#: lib/logitech_receiver/notifications.py:116\nmsgid \"pairing lock is closed\"\nmsgstr \"eşleştirme kilidi kapalı\"\n\n#: lib/logitech_receiver/notifications.py:64\n#: lib/logitech_receiver/notifications.py:116\nmsgid \"pairing lock is open\"\nmsgstr \"eşleştirme kilidi açık\"\n\n#: lib/logitech_receiver/notifications.py:81\nmsgid \"discovery lock is closed\"\nmsgstr \"keşif kilidi kapalı\"\n\n#: lib/logitech_receiver/notifications.py:81\nmsgid \"discovery lock is open\"\nmsgstr \"keşif kilidi açık\"\n\n#: lib/logitech_receiver/notifications.py:210 lib/solaar/listener.py:238\nmsgid \"connected\"\nmsgstr \"bağlı\"\n\n#: lib/logitech_receiver/notifications.py:210 lib/solaar/listener.py:238\nmsgid \"disconnected\"\nmsgstr \"bağlantı kesildi\"\n\n#: lib/logitech_receiver/notifications.py:236\nmsgid \"unpaired\"\nmsgstr \"eşleşmemiş\"\n\n#: lib/logitech_receiver/notifications.py:283\nmsgid \"powered on\"\nmsgstr \"açık\"\n\n#: lib/logitech_receiver/receiver.py:371\nmsgid \"No paired devices.\"\nmsgstr \"Eşleşmiş aygıt yok.\"\n\n#: lib/logitech_receiver/receiver.py:373 lib/solaar/ui/window.py:604\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s eşleşmiş aygıt.\"\nmsgstr[1] \"%(count)s eşleşmiş aygıt.\"\n\n#: lib/logitech_receiver/settings.py:611\nmsgid \"register\"\nmsgstr \"kaydet\"\n\n#: lib/logitech_receiver/settings.py:625 lib/logitech_receiver/settings.py:651\nmsgid \"feature\"\nmsgstr \"özellik\"\n\n#: lib/logitech_receiver/settings_templates.py:122\nmsgid \"Swap Fx function\"\nmsgstr \"Fx işlevlerini ters çevir\"\n\n#: lib/logitech_receiver/settings_templates.py:125\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"F1..F12 tuşları özel işlevler için ayarlandığında,\\n\"\n\"FN tuşuna basılı tutarak standart işlevlerini aktif edebilirsiniz.\"\n\n#: lib/logitech_receiver/settings_templates.py:130\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"F1..F12 tuşları standart işlevler için ayarlandığında,\\n\"\n\"FN tuşuna basılı tutarak özel işlevlerini aktif edebilirsiniz.\"\n\n#: lib/logitech_receiver/settings_templates.py:138\nmsgid \"Hand Detection\"\nmsgstr \"El Algılama\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"Eller klavyenin üzerindeyken aydınlanmayı aç.\"\n\n#: lib/logitech_receiver/settings_templates.py:146\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"Kaydırma Tekerleği Yumuşak Kaydırma\"\n\n#: lib/logitech_receiver/settings_templates.py:147\n#: lib/logitech_receiver/settings_templates.py:394\n#: lib/logitech_receiver/settings_templates.py:423\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"Tekerleğin dikey kaydırılması için yüksek hasasiyet modu.\"\n\n#: lib/logitech_receiver/settings_templates.py:154\nmsgid \"Side Scrolling\"\nmsgstr \"Yatay Kaydırma\"\n\n#: lib/logitech_receiver/settings_templates.py:156\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"Devredışı olduğunda, tekerleğin yanına basmak standart yatay kaydırma komutu \"\n\"yerine\\n\"\n\"özel tuş komutunu gönderir.\"\n\n#: lib/logitech_receiver/settings_templates.py:166\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"Hassasiyet (DPI - eski fare)\"\n\n#: lib/logitech_receiver/settings_templates.py:167\n#: lib/logitech_receiver/settings_templates.py:955\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"Fare hareketi hassasiyeti\"\n\n#: lib/logitech_receiver/settings_templates.py:240\nmsgid \"Backlight Timed\"\nmsgstr \"Zamanlanmış Aydınlatma\"\n\n#: lib/logitech_receiver/settings_templates.py:241\n#: lib/logitech_receiver/settings_templates.py:381\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"Klavye için aydınlatma zaman aşımı.\"\n\n#: lib/logitech_receiver/settings_templates.py:252\nmsgid \"Backlight\"\nmsgstr \"Aydınlatma\"\n\n#: lib/logitech_receiver/settings_templates.py:253\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"\"\n\"Klavyedeki aydınlatma düzeyi. Değişiklikler sadece Elle modunda uygulanır.\"\n\n#: lib/logitech_receiver/settings_templates.py:285\nmsgid \"Automatic\"\nmsgstr \"Otomatik\"\n\n#: lib/logitech_receiver/settings_templates.py:287\nmsgid \"Manual\"\nmsgstr \"Elle\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid \"Enabled\"\nmsgstr \"Etkin\"\n\n#: lib/logitech_receiver/settings_templates.py:295\nmsgid \"Backlight Level\"\nmsgstr \"Aydınlatma Düzeyi\"\n\n#: lib/logitech_receiver/settings_templates.py:296\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"Elle modundaki klavye aydınlatma düzeyi.\"\n\n#: lib/logitech_receiver/settings_templates.py:353\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"Eller Çekildiğinde Aydınlatma Gecikmesi\"\n\n#: lib/logitech_receiver/settings_templates.py:354\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"\"\n\"Eller klavyeden uzaklaştırıldığında aydınlatmanın solması için gecikme.\"\n\n#: lib/logitech_receiver/settings_templates.py:362\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"Eller Yaklaştırıldığında Aydıtlatma Gecikmesi\"\n\n#: lib/logitech_receiver/settings_templates.py:363\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"Eller klavyeye yaklaştırıldığında aydınlatmanın solması için gecikme.\"\n\n#: lib/logitech_receiver/settings_templates.py:371\nmsgid \"Backlight Delay Powered\"\nmsgstr \"Güce Bağlandığında Aydınlatma Gecikmesi\"\n\n#: lib/logitech_receiver/settings_templates.py:372\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"Güce bağlandığında aydınlatmanın solması için gecikme.\"\n\n#: lib/logitech_receiver/settings_templates.py:380\nmsgid \"Backlight (Seconds)\"\nmsgstr \"Aydınlatma (Saniye)\"\n\n#: lib/logitech_receiver/settings_templates.py:392\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"Kaydırma Tekerleği Yüksek Çözünürlük\"\n\n#: lib/logitech_receiver/settings_templates.py:396\n#: lib/logitech_receiver/settings_templates.py:425\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"Kaydırma aşırı yavaş veya hızlıysa yoksaymak için ayarla\"\n\n#: lib/logitech_receiver/settings_templates.py:403\n#: lib/logitech_receiver/settings_templates.py:434\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"Kaydırma Tekerleği Yönlendirme\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Kaydırma tekerleğinin LOWRES_WHEEL HID++ bildirimler göndermesini sağlar (bu \"\n\"bildirimler Solaar kurallarını tetikler, ancak diğer durumlarda görmezden \"\n\"gelinir).\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"Kaydırma Tekerleği Yönü\"\n\n#: lib/logitech_receiver/settings_templates.py:413\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"Kaydırma tekerleği ile dikey kaydırma yönünü tersine çevirir.\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"Kaydırma Tekerleği Çözünürlüğü\"\n\n#: lib/logitech_receiver/settings_templates.py:436\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Kaydırma tekerleğinin HIRES_WHEEL HID++ bildirimler göndermesini sağlar (bu \"\n\"bildirimler Solaar kurallarını tetikler, ancak diğer durumlarda görmezden \"\n\"gelinir).\"\n\n#: lib/logitech_receiver/settings_templates.py:445\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"Hassasiyet (İşaretçi Hızı)\"\n\n#: lib/logitech_receiver/settings_templates.py:446\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"Fare için hız çarpanı (256 normal çarpandır).\"\n\n#: lib/logitech_receiver/settings_templates.py:456\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"Başparmak Tekerleği Yönlendirme\"\n\n#: lib/logitech_receiver/settings_templates.py:458\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Başparmak tekerleğinin THUMB_WHEEL HID++ bildirimler göndermesini sağlar (bu \"\n\"bildirimler Solaar kurallarını tetikler, ancak diğer durumlarda görmezden \"\n\"gelinir).\"\n\n#: lib/logitech_receiver/settings_templates.py:467\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"Başparmak Tekerleği Yönü\"\n\n#: lib/logitech_receiver/settings_templates.py:468\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"Kaydırma tekerleği ile başparmak kaydırma yönünü tersine çevirir.\"\n\n#: lib/logitech_receiver/settings_templates.py:488\nmsgid \"Onboard Profiles\"\nmsgstr \"Yerleşik Profiller\"\n\n#: lib/logitech_receiver/settings_templates.py:489\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"\"\n\"Yerleşik profilleri etkinleştir, bu rapor hızını, hassasiyeti ve düğme \"\n\"etkinliğini kontrol eder\"\n\n#: lib/logitech_receiver/settings_templates.py:533\n#: lib/logitech_receiver/settings_templates.py:566\nmsgid \"Report Rate\"\nmsgstr \"Rapor Hızı\"\n\n#: lib/logitech_receiver/settings_templates.py:535\n#: lib/logitech_receiver/settings_templates.py:568\nmsgid \"Frequency of device movement reports\"\nmsgstr \"Aygıt hareketlerinin rapor sıklığı\"\n\n#: lib/logitech_receiver/settings_templates.py:535\n#: lib/logitech_receiver/settings_templates.py:568\n#: lib/logitech_receiver/settings_templates.py:983\n#: lib/logitech_receiver/settings_templates.py:1357\n#: lib/logitech_receiver/settings_templates.py:1388\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"\"\n\"Etkili olabilmesi için Yerleşik Profillerin devredışı bırakılması \"\n\"gerekebilir.\"\n\n#: lib/logitech_receiver/settings_templates.py:596\nmsgid \"Divert crown events\"\nmsgstr \"Kadran etkinliklerini yönlendir\"\n\n#: lib/logitech_receiver/settings_templates.py:597\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Kadranın CROWN HID++ bildirimler göndermesini sağlar (bu bildirimler Solaar \"\n\"kurallarını tetikler, ancak diğer durumlarda görmezden gelinir).\"\n\n#: lib/logitech_receiver/settings_templates.py:605\nmsgid \"Crown smooth scroll\"\nmsgstr \"Kadran yumuşak kaydırma\"\n\n#: lib/logitech_receiver/settings_templates.py:606\nmsgid \"Set crown smooth scroll\"\nmsgstr \"Kadranın yumuşak kaydırmasını ayarla\"\n\n#: lib/logitech_receiver/settings_templates.py:614\nmsgid \"Divert G and M Keys\"\nmsgstr \"G ve M Tuşlarını Yönlendir\"\n\n#: lib/logitech_receiver/settings_templates.py:615\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"G ve M Tuşlarının HID++ bildirimler göndermesini sağlar (bu bildirimler \"\n\"Solaar kurallarını tetikler, ancak diğer durumlarda görmezden gelinir).\"\n\n#: lib/logitech_receiver/settings_templates.py:629\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"Kaydırma Tekerleği Dönüşü\"\n\n#: lib/logitech_receiver/settings_templates.py:630\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"\"\n\"Fare Tekerleğini, hız kontrollü dişli kaydırma ile sürekli serbest dönüş \"\n\"arasında değiştir.\"\n\n#: lib/logitech_receiver/settings_templates.py:632\nmsgid \"Freespinning\"\nmsgstr \"Serbest Dönüş\"\n\n#: lib/logitech_receiver/settings_templates.py:632\nmsgid \"Ratcheted\"\nmsgstr \"Dişli\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"Kaydırma Tekerleği Dişli Hızı\"\n\n#: lib/logitech_receiver/settings_templates.py:641\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"Fare tekerleği hızını kullanarak dişli kaydırma ile serbest dönüş arasında \"\n\"geçiş yap.\\n\"\n\"Fare tekerleği, 50 hızda her zaman dişli kaydırmalı olur.\"\n\n#: lib/logitech_receiver/settings_templates.py:690\nmsgid \"Key/Button Actions\"\nmsgstr \"Tuş/Düğme Eylemleri\"\n\n#: lib/logitech_receiver/settings_templates.py:692\nmsgid \"Change the action for the key or button.\"\nmsgstr \"Tuş veya düğmenin eylemini değiştirir.\"\n\n#: lib/logitech_receiver/settings_templates.py:694\nmsgid \"Overridden by diversion.\"\nmsgstr \"Yönlendirmeyle geçersiz kılındı.\"\n\n#: lib/logitech_receiver/settings_templates.py:696\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"\"\n\"Önemli eylemleri değiştirmek (farenin sol tuşu gibi) sistemde \"\n\"kararsızlıklara yol açabilir.\"\n\n#: lib/logitech_receiver/settings_templates.py:862\nmsgid \"Key/Button Diversion\"\nmsgstr \"Tuş/Düğme Yönlendirme\"\n\n#: lib/logitech_receiver/settings_templates.py:863\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse \"\n\"Gestures or Sliding DPI\"\nmsgstr \"\"\n\"Tuş veya düğmenin HID++ bildirimleri (yönlendirmeler) veya Fare Hareketleri \"\n\"başlatmalar veya Kaydırma DPI'si\"\n\n#: lib/logitech_receiver/settings_templates.py:866\n#: lib/logitech_receiver/settings_templates.py:867\n#: lib/logitech_receiver/settings_templates.py:868\nmsgid \"Diverted\"\nmsgstr \"Yönlendirilmiş\"\n\n#: lib/logitech_receiver/settings_templates.py:866\n#: lib/logitech_receiver/settings_templates.py:867\nmsgid \"Mouse Gestures\"\nmsgstr \"Fare Hareketleri\"\n\n#: lib/logitech_receiver/settings_templates.py:866\n#: lib/logitech_receiver/settings_templates.py:867\n#: lib/logitech_receiver/settings_templates.py:868\nmsgid \"Regular\"\nmsgstr \"Normal\"\n\n#: lib/logitech_receiver/settings_templates.py:866\nmsgid \"Sliding DPI\"\nmsgstr \"Kaydırma DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:954\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"Hassasiyet (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:1059\nmsgid \"Sensitivity Switching\"\nmsgstr \"Hassasiyet Değiştirme\"\n\n#: lib/logitech_receiver/settings_templates.py:1061\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key \"\n\"or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\"Şuanki hassasiyeti ve hatırlanan hassasiyeti tuş veya düğmeye basıldığında \"\n\"değiştir.\\n\"\n\"Eğer hatırlanan hassasiyet yoksa sadece şuanki hassasiyeti hatırla\"\n\n#: lib/logitech_receiver/settings_templates.py:1065\nmsgid \"Off\"\nmsgstr \"Kapalı\"\n\n#: lib/logitech_receiver/settings_templates.py:1096\nmsgid \"Disable keys\"\nmsgstr \"Tuşları devredışı bırak\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"Özel klavye tuşlarını devredışı bırak.\"\n\n#: lib/logitech_receiver/settings_templates.py:1100\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"%s tuşunu devredışı bırakır.\"\n\n#: lib/logitech_receiver/settings_templates.py:1113\n#: lib/logitech_receiver/settings_templates.py:1170\nmsgid \"Set OS\"\nmsgstr \"İşletim Sistemi Ayarla\"\n\n#: lib/logitech_receiver/settings_templates.py:1114\n#: lib/logitech_receiver/settings_templates.py:1171\nmsgid \"Change keys to match OS.\"\nmsgstr \"Tuşları eşleşen işletim sistemine göre değiştir.\"\n\n#: lib/logitech_receiver/settings_templates.py:1183\nmsgid \"Change Host\"\nmsgstr \"Bağlanılan Bilgisayarı Değiştir\"\n\n#: lib/logitech_receiver/settings_templates.py:1184\nmsgid \"Switch connection to a different host\"\nmsgstr \"Bağlantıyı başka bilgisayara değiştir\"\n\n#: lib/logitech_receiver/settings_templates.py:1208\nmsgid \"Performs a left click.\"\nmsgstr \"Sol tıklama eylemi gerçekleştirir.\"\n\n#: lib/logitech_receiver/settings_templates.py:1208\nmsgid \"Single tap\"\nmsgstr \"Tek dokunma\"\n\n#: lib/logitech_receiver/settings_templates.py:1209\nmsgid \"Performs a right click.\"\nmsgstr \"Sağ tıklama eylemi gerçekleştirir.\"\n\n#: lib/logitech_receiver/settings_templates.py:1209\nmsgid \"Single tap with two fingers\"\nmsgstr \"İki parmakla tek dokunma\"\n\n#: lib/logitech_receiver/settings_templates.py:1210\nmsgid \"Single tap with three fingers\"\nmsgstr \"Üç parmakla tek dokunma\"\n\n#: lib/logitech_receiver/settings_templates.py:1214\nmsgid \"Double tap\"\nmsgstr \"Çift dokunma\"\n\n#: lib/logitech_receiver/settings_templates.py:1214\nmsgid \"Performs a double click.\"\nmsgstr \"Çift tıklama eylemi gerçekleştirir.\"\n\n#: lib/logitech_receiver/settings_templates.py:1215\nmsgid \"Double tap with two fingers\"\nmsgstr \"İki parmakla çift dokunma\"\n\n#: lib/logitech_receiver/settings_templates.py:1216\nmsgid \"Double tap with three fingers\"\nmsgstr \"Üç parmakla çift dokunma\"\n\n#: lib/logitech_receiver/settings_templates.py:1219\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"Çift tıklama eylemi ile nesneleri taşı.\"\n\n#: lib/logitech_receiver/settings_templates.py:1219\nmsgid \"Tap and drag\"\nmsgstr \"Dokun ve taşı\"\n\n#: lib/logitech_receiver/settings_templates.py:1221\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"İki parmakla dokun ve taşı\"\n\n#: lib/logitech_receiver/settings_templates.py:1222\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"Çift tıklama eylemi ile nesneleri taşı.\"\n\n#: lib/logitech_receiver/settings_templates.py:1224\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"Üç parmakla dokun ve taşı\"\n\n#: lib/logitech_receiver/settings_templates.py:1227\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"Dokunma ve kenar hareketlerini baskıla\"\n\n#: lib/logitech_receiver/settings_templates.py:1228\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"\"\n\"Dokunma ve kenar hareketlerini devredışı bırakır (Fn + SolTıklama ile \"\n\"aynıdır).\"\n\n#: lib/logitech_receiver/settings_templates.py:1230\nmsgid \"Scroll with one finger\"\nmsgstr \"Bir parmakla kaydır\"\n\n#: lib/logitech_receiver/settings_templates.py:1230\n#: lib/logitech_receiver/settings_templates.py:1231\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid \"Scrolls.\"\nmsgstr \"Kaydırır.\"\n\n#: lib/logitech_receiver/settings_templates.py:1231\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid \"Scroll with two fingers\"\nmsgstr \"İki parmakla kaydır\"\n\n#: lib/logitech_receiver/settings_templates.py:1232\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"İki parmakla yatay kaydır\"\n\n#: lib/logitech_receiver/settings_templates.py:1232\nmsgid \"Scrolls horizontally.\"\nmsgstr \"Yatay kaydırır.\"\n\n#: lib/logitech_receiver/settings_templates.py:1233\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"İki parmakla dikey kaydır\"\n\n#: lib/logitech_receiver/settings_templates.py:1233\nmsgid \"Scrolls vertically.\"\nmsgstr \"Dikey kaydırır.\"\n\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"Kaydırma yönünü ters çevir.\"\n\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid \"Natural scrolling\"\nmsgstr \"Doğal kaydırma\"\n\n#: lib/logitech_receiver/settings_templates.py:1236\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"Başparmak tekerleğini etkinleştirir.\"\n\n#: lib/logitech_receiver/settings_templates.py:1236\nmsgid \"Thumbwheel\"\nmsgstr \"Başparmak Tekerleği\"\n\n#: lib/logitech_receiver/settings_templates.py:1247\n#: lib/logitech_receiver/settings_templates.py:1251\nmsgid \"Swipe from the top edge\"\nmsgstr \"Üst kenardan vuruş\"\n\n#: lib/logitech_receiver/settings_templates.py:1248\nmsgid \"Swipe from the left edge\"\nmsgstr \"Sol kenardan vuruş\"\n\n#: lib/logitech_receiver/settings_templates.py:1249\nmsgid \"Swipe from the right edge\"\nmsgstr \"Sağ kenardan vuruş\"\n\n#: lib/logitech_receiver/settings_templates.py:1250\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"Alt kenardan vuruş\"\n\n#: lib/logitech_receiver/settings_templates.py:1252\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"Sol kenardan iki parmak vuruş\"\n\n#: lib/logitech_receiver/settings_templates.py:1253\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"Sağ kenardan iki parmak vuruş\"\n\n#: lib/logitech_receiver/settings_templates.py:1254\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"Alt kenardan iki parmak vuruş\"\n\n#: lib/logitech_receiver/settings_templates.py:1255\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"Üst kenardan iki parmak vuruş\"\n\n#: lib/logitech_receiver/settings_templates.py:1256\n#: lib/logitech_receiver/settings_templates.py:1260\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"Uzaklaşmak için sıkıştırın, yakınlaştırmak için yayın.\"\n\n#: lib/logitech_receiver/settings_templates.py:1256\nmsgid \"Zoom with two fingers.\"\nmsgstr \"İki parmakla yakınlaştırma.\"\n\n#: lib/logitech_receiver/settings_templates.py:1257\nmsgid \"Pinch to zoom out.\"\nmsgstr \"Uzaklaştırmak için sıkıştırın.\"\n\n#: lib/logitech_receiver/settings_templates.py:1258\nmsgid \"Spread to zoom in.\"\nmsgstr \"Yakınlaştırmak için yayın.\"\n\n#: lib/logitech_receiver/settings_templates.py:1259\nmsgid \"Zoom with three fingers.\"\nmsgstr \"Üç parmakla yakınlaştırma.\"\n\n#: lib/logitech_receiver/settings_templates.py:1260\nmsgid \"Zoom with two fingers\"\nmsgstr \"İki parmakla yakınlaştır\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Pixel zone\"\nmsgstr \"Piksel alanı\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid \"Ratio zone\"\nmsgstr \"Oran alanı\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Scale factor\"\nmsgstr \"Ölçek katsayısı\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Sets the cursor speed.\"\nmsgstr \"İmleç hızını ayarla.\"\n\n#: lib/logitech_receiver/settings_templates.py:1284\nmsgid \"Left\"\nmsgstr \"Sol\"\n\n#: lib/logitech_receiver/settings_templates.py:1284\nmsgid \"Left-most coordinate.\"\nmsgstr \"En soldaki koordinat.\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid \"Bottom\"\nmsgstr \"Alt\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid \"Bottom coordinate.\"\nmsgstr \"Alt koordinat.\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid \"Width\"\nmsgstr \"Genişlik\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid \"Width.\"\nmsgstr \"Genişlik.\"\n\n#: lib/logitech_receiver/settings_templates.py:1287\nmsgid \"Height\"\nmsgstr \"Yükseklik\"\n\n#: lib/logitech_receiver/settings_templates.py:1287\nmsgid \"Height.\"\nmsgstr \"Yükseklik.\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid \"Cursor speed.\"\nmsgstr \"İmleç hızı.\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid \"Scale\"\nmsgstr \"Ölçek\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\nmsgid \"Gestures\"\nmsgstr \"Hareketler\"\n\n#: lib/logitech_receiver/settings_templates.py:1295\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"Fare/dokunmatik yüzey davranışında ince ayar yapın.\"\n\n#: lib/logitech_receiver/settings_templates.py:1311\nmsgid \"Gestures Diversion\"\nmsgstr \"Hareketleri Yönlendir\"\n\n#: lib/logitech_receiver/settings_templates.py:1312\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"Fare/dokunmatik yüzey hareketlerini yönlendirir.\"\n\n#: lib/logitech_receiver/settings_templates.py:1328\nmsgid \"Gesture params\"\nmsgstr \"Hareket parametreleri\"\n\n#: lib/logitech_receiver/settings_templates.py:1329\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"Fare/dokunmatik yüzey sayısal parametrelerini değiştir.\"\n\n#: lib/logitech_receiver/settings_templates.py:1353\nmsgid \"M-Key LEDs\"\nmsgstr \"M-Tuşu LED'leri\"\n\n#: lib/logitech_receiver/settings_templates.py:1355\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"M-Tuşu LED'lerini kontrol eder.\"\n\n#: lib/logitech_receiver/settings_templates.py:1359\n#: lib/logitech_receiver/settings_templates.py:1390\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"G Tuşlarını yönlendirmek etkili olabilir.\"\n\n#: lib/logitech_receiver/settings_templates.py:1365\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"%s tuşunu aydınlat.\"\n\n#: lib/logitech_receiver/settings_templates.py:1384\nmsgid \"MR-Key LED\"\nmsgstr \"MR-Tuşu LED'i\"\n\n#: lib/logitech_receiver/settings_templates.py:1386\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"MR-Tuşu LED'inin kontrol eder.\"\n\n#: lib/logitech_receiver/settings_templates.py:1407\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"Kalıcı Tuş/Düğme Haritalama\"\n\n#: lib/logitech_receiver/settings_templates.py:1409\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"Tuş veya düğmenin haritalamasını kalıcı olarak değiştir.\"\n\n#: lib/logitech_receiver/settings_templates.py:1411\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"\"\n\"Önemli tuşları veya düğmeleri değiştirmek (farenin sol tuşu gibi) sistemde \"\n\"kararsızlıklara yol açabilir.\"\n\n#: lib/logitech_receiver/settings_templates.py:1468\nmsgid \"Sidetone\"\nmsgstr \"Yan ton\"\n\n#: lib/logitech_receiver/settings_templates.py:1469\nmsgid \"Set sidetone level.\"\nmsgstr \"Yan ton seviyesini ayarla.\"\n\n#: lib/logitech_receiver/settings_templates.py:1478\nmsgid \"Equalizer\"\nmsgstr \"Ekolayzer\"\n\n#: lib/logitech_receiver/settings_templates.py:1479\nmsgid \"Set equalizer levels.\"\nmsgstr \"Ekolayzer seviyesini ayarla.\"\n\n#: lib/logitech_receiver/settings_templates.py:1501\nmsgid \"Hz\"\nmsgstr \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1507\nmsgid \"Power Management\"\nmsgstr \"Güç Yönetimi\"\n\n#: lib/logitech_receiver/settings_templates.py:1508\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"Dakika cinsinden kapanma süresi (asla kapanmaması için 0).\"\n\n#: lib/logitech_receiver/settings_templates.py:1519\nmsgid \"Brightness Control\"\nmsgstr \"Parlaklık Kontrolü\"\n\n#: lib/logitech_receiver/settings_templates.py:1520\nmsgid \"Control overall brightness\"\nmsgstr \"Genel parlaklığı kontrol et\"\n\n#: lib/logitech_receiver/settings_templates.py:1563\n#: lib/logitech_receiver/settings_templates.py:1617\nmsgid \"LED Control\"\nmsgstr \"LED Kontrolü\"\n\n#: lib/logitech_receiver/settings_templates.py:1564\n#: lib/logitech_receiver/settings_templates.py:1618\nmsgid \"Switch control of LED zones between device and Solaar\"\nmsgstr \"LED bölgelerinin kontrolünü aygıt ile Solaar arasında değiştir\"\n\n#: lib/logitech_receiver/settings_templates.py:1579\n#: lib/logitech_receiver/settings_templates.py:1628\nmsgid \"LED Zone Effects\"\nmsgstr \"LED Bölge Efektleri\"\n\n#: lib/logitech_receiver/settings_templates.py:1580\n#: lib/logitech_receiver/settings_templates.py:1629\nmsgid \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr \"LED kontrolünün etkili olabilmesi için Solaar seçilmelidir.\"\n\n#: lib/logitech_receiver/settings_templates.py:1580\n#: lib/logitech_receiver/settings_templates.py:1629\nmsgid \"Set effect for LED Zone\"\nmsgstr \"LED Bölgesi için efekt ayarla\"\n\n#: lib/logitech_receiver/settings_templates.py:1583\nmsgid \"Speed\"\nmsgstr \"Hız\"\n\n#: lib/logitech_receiver/settings_templates.py:1584\nmsgid \"Period\"\nmsgstr \"Sıklık\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\nmsgid \"Intensity\"\nmsgstr \"Yoğunluk\"\n\n#: lib/logitech_receiver/settings_templates.py:1586\nmsgid \"Ramp\"\nmsgstr \"Eğim\"\n\n#: lib/logitech_receiver/settings_templates.py:1602\nmsgid \"LEDs\"\nmsgstr \"LEDler\"\n\n#: lib/logitech_receiver/settings_templates.py:1639\nmsgid \"Per-key Lighting\"\nmsgstr \"Tuş başına Aydınlatma\"\n\n#: lib/logitech_receiver/settings_templates.py:1640\nmsgid \"Control per-key lighting.\"\nmsgstr \"Tuş başına aydınlatmayı kontrol et.\"\n\n#: lib/solaar/ui/__init__.py:103\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"Başka bir Solaar işlemi çalışıyor, sadece onun penceresini görünür yap\"\n\n#: lib/solaar/ui/about.py:34\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"Logitech alıcılarını, klavyelerini,\\n\"\n\"farelerini ve tabletlerini yönetir.\"\n\n#: lib/solaar/ui/about.py:43\nmsgid \"Additional Programming\"\nmsgstr \"Ek Programlama\"\n\n#: lib/solaar/ui/about.py:44\nmsgid \"GUI design\"\nmsgstr \"GUI tasarımı\"\n\n#: lib/solaar/ui/about.py:46\nmsgid \"Testing\"\nmsgstr \"Sınama\"\n\n#: lib/solaar/ui/about.py:54\nmsgid \"Logitech documentation\"\nmsgstr \"Logitech belgeleri\"\n\n#: lib/solaar/ui/action.py:83 lib/solaar/ui/action.py:87\n#: lib/solaar/ui/window.py:189\nmsgid \"Unpair\"\nmsgstr \"Eşleşmeyi Kaldır\"\n\n#: lib/solaar/ui/action.py:86 lib/solaar/ui/diversion_rules.py:103\nmsgid \"Cancel\"\nmsgstr \"Vazgeç\"\n\n#: lib/solaar/ui/common.py:35\nmsgid \"Permissions error\"\nmsgstr \"Yetki hatası\"\n\n#: lib/solaar/ui/common.py:37\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"Bir Logitech aygıtı (%s) bulundu ama açmak için yetki yok.\"\n\n#: lib/solaar/ui/common.py:39\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"\"\n\"Eğer Solaar'ı yeni kurmuşsanız, aygıtı veya alıcıyı tekrar bağlamayı deneyin.\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Cannot connect to device error\"\nmsgstr \"Aygıta bağlanılamıyor\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"%s konumunda bir Logitech alıcısı veya aygıtı bulundu, ancak buna \"\n\"bağlanırken bir hatayla karşılaşıldı.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"Aygıtı tekrar bağlamayı deneyin veya kapatıp açın.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Unpairing failed\"\nmsgstr \"Eşleştirme kaldırılamadı\"\n\n#: lib/solaar/ui/common.py:51\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"%{device} ve %{receiver} eşleştirmesi kaldırılamadı.\"\n\n#: lib/solaar/ui/common.py:53\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"Alıcı hata verdi, bu hata hakkında ayrıntı mevcut değil.\"\n\n#: lib/solaar/ui/config_panel.py:228\nmsgid \"Complete - ENTER to change\"\nmsgstr \"Tamamlanmış - Değiştirmek için ENTER'a basın\"\n\n#: lib/solaar/ui/config_panel.py:228\nmsgid \"Incomplete\"\nmsgstr \"Tamamlanmamış\"\n\n#: lib/solaar/ui/config_panel.py:470 lib/solaar/ui/config_panel.py:522\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d değer\"\nmsgstr[1] \"%d değer\"\n\n#: lib/solaar/ui/config_panel.py:603\nmsgid \"Changes allowed\"\nmsgstr \"Değişiklikler kabul ediliyor\"\n\n#: lib/solaar/ui/config_panel.py:604\nmsgid \"No changes allowed\"\nmsgstr \"Değişiklik kabul edilmiyor\"\n\n#: lib/solaar/ui/config_panel.py:605\nmsgid \"Ignore this setting\"\nmsgstr \"Bu ayarı görmezden gel\"\n\n#: lib/solaar/ui/config_panel.py:649\nmsgid \"Working\"\nmsgstr \"Çalışıyor\"\n\n#: lib/solaar/ui/config_panel.py:652\nmsgid \"Read/write operation failed.\"\nmsgstr \"Okuma/yazma işlemi yapılamadı.\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid \"Built-in rules\"\nmsgstr \"Varolan kurallar\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid \"User-defined rules\"\nmsgstr \"Kullanıcı tanımlı kurallar\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1033\nmsgid \"Rule\"\nmsgstr \"Kural\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:545\n#: lib/solaar/ui/diversion_rules.py:672\nmsgid \"Sub-rule\"\nmsgstr \"Alt Kural\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid \"[empty]\"\nmsgstr \"[boş]\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid \"Make changes permanent?\"\nmsgstr \"Değişiklikleri kalıcı yap?\"\n\n#: lib/solaar/ui/diversion_rules.py:99\nmsgid \"Yes\"\nmsgstr \"Evet\"\n\n#: lib/solaar/ui/diversion_rules.py:101\nmsgid \"No\"\nmsgstr \"Hayır\"\n\n#: lib/solaar/ui/diversion_rules.py:106\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"Hayır'ı seçerseniz, Solaar kapatıldığında değişiklikler kaybolacaktır.\"\n\n#: lib/solaar/ui/diversion_rules.py:167\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Solar Kural Editörü\"\n\n#: lib/solaar/ui/diversion_rules.py:260\nmsgid \"Save changes\"\nmsgstr \"Değişiklikleri kaydet\"\n\n#: lib/solaar/ui/diversion_rules.py:265\nmsgid \"Discard changes\"\nmsgstr \"Değişiklikleri gözardı et\"\n\n#: lib/solaar/ui/diversion_rules.py:404\nmsgid \"Insert here\"\nmsgstr \"Buraya ekle\"\n\n#: lib/solaar/ui/diversion_rules.py:406\nmsgid \"Insert above\"\nmsgstr \"Yukarıya ekle\"\n\n#: lib/solaar/ui/diversion_rules.py:408\nmsgid \"Insert below\"\nmsgstr \"Aşağıya ekle\"\n\n#: lib/solaar/ui/diversion_rules.py:414\nmsgid \"Insert new rule here\"\nmsgstr \"Buraya yeni kural ekle\"\n\n#: lib/solaar/ui/diversion_rules.py:416\nmsgid \"Insert new rule above\"\nmsgstr \"Yukarıya yeni kural ekle\"\n\n#: lib/solaar/ui/diversion_rules.py:418\nmsgid \"Insert new rule below\"\nmsgstr \"Aşağıya yeni kural ekle\"\n\n#: lib/solaar/ui/diversion_rules.py:463\nmsgid \"Paste here\"\nmsgstr \"Buraya yapıştır\"\n\n#: lib/solaar/ui/diversion_rules.py:465\nmsgid \"Paste above\"\nmsgstr \"Yukarı yapıştır\"\n\n#: lib/solaar/ui/diversion_rules.py:467\nmsgid \"Paste below\"\nmsgstr \"Aşağıya yapıştır\"\n\n#: lib/solaar/ui/diversion_rules.py:473\nmsgid \"Paste rule here\"\nmsgstr \"Kuralı buraya yapıştır\"\n\n#: lib/solaar/ui/diversion_rules.py:475\nmsgid \"Paste rule above\"\nmsgstr \"Kuralı yukarı yapıştır\"\n\n#: lib/solaar/ui/diversion_rules.py:477\nmsgid \"Paste rule below\"\nmsgstr \"Kuralı aşağıya yapıştır\"\n\n#: lib/solaar/ui/diversion_rules.py:481\nmsgid \"Paste rule\"\nmsgstr \"Kuralı yapıştır\"\n\n#: lib/solaar/ui/diversion_rules.py:510\nmsgid \"Flatten\"\nmsgstr \"Kapsamdan çıkar\"\n\n#: lib/solaar/ui/diversion_rules.py:543\nmsgid \"Insert\"\nmsgstr \"Ekle\"\n\n#: lib/solaar/ui/diversion_rules.py:546 lib/solaar/ui/diversion_rules.py:674\n#: lib/solaar/ui/diversion_rules.py:1065\nmsgid \"Or\"\nmsgstr \"Veya\"\n\n#: lib/solaar/ui/diversion_rules.py:547 lib/solaar/ui/diversion_rules.py:673\n#: lib/solaar/ui/diversion_rules.py:1051\nmsgid \"And\"\nmsgstr \"Ve\"\n\n#: lib/solaar/ui/diversion_rules.py:549\nmsgid \"Condition\"\nmsgstr \"Durum\"\n\n#: lib/solaar/ui/diversion_rules.py:551 lib/solaar/ui/rule_conditions.py:146\nmsgid \"Feature\"\nmsgstr \"Özellik\"\n\n#: lib/solaar/ui/diversion_rules.py:552 lib/solaar/ui/rule_conditions.py:181\nmsgid \"Report\"\nmsgstr \"Rapor\"\n\n#: lib/solaar/ui/diversion_rules.py:553 lib/solaar/ui/rule_conditions.py:60\nmsgid \"Process\"\nmsgstr \"İşlem\"\n\n#: lib/solaar/ui/diversion_rules.py:554\nmsgid \"Mouse process\"\nmsgstr \"Fare İşlemi\"\n\n#: lib/solaar/ui/diversion_rules.py:555 lib/solaar/ui/rule_conditions.py:218\nmsgid \"Modifiers\"\nmsgstr \"Değiştiriciler\"\n\n#: lib/solaar/ui/diversion_rules.py:556 lib/solaar/ui/rule_conditions.py:270\nmsgid \"Key\"\nmsgstr \"Tuş\"\n\n#: lib/solaar/ui/diversion_rules.py:557 lib/solaar/ui/rule_conditions.py:311\nmsgid \"KeyIsDown\"\nmsgstr \"TuşBasılı\"\n\n#: lib/solaar/ui/diversion_rules.py:558 lib/solaar/ui/diversion_rules.py:1359\nmsgid \"Active\"\nmsgstr \"Etkin\"\n\n#: lib/solaar/ui/diversion_rules.py:559 lib/solaar/ui/diversion_rules.py:1316\n#: lib/solaar/ui/diversion_rules.py:1368 lib/solaar/ui/diversion_rules.py:1418\nmsgid \"Device\"\nmsgstr \"Aygıt\"\n\n#: lib/solaar/ui/diversion_rules.py:560 lib/solaar/ui/diversion_rules.py:1394\nmsgid \"Host\"\nmsgstr \"Bilgisayar\"\n\n#: lib/solaar/ui/diversion_rules.py:561 lib/solaar/ui/diversion_rules.py:1436\nmsgid \"Setting\"\nmsgstr \"Ayar\"\n\n#: lib/solaar/ui/diversion_rules.py:562 lib/solaar/ui/rule_conditions.py:326\n#: lib/solaar/ui/rule_conditions.py:375\nmsgid \"Test\"\nmsgstr \"Sınama\"\n\n#: lib/solaar/ui/diversion_rules.py:563 lib/solaar/ui/rule_conditions.py:500\nmsgid \"Test bytes\"\nmsgstr \"Sınama baytları\"\n\n#: lib/solaar/ui/diversion_rules.py:564 lib/solaar/ui/rule_conditions.py:601\nmsgid \"Mouse Gesture\"\nmsgstr \"Fare Hareketi\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid \"Action\"\nmsgstr \"Eylem\"\n\n#: lib/solaar/ui/diversion_rules.py:570 lib/solaar/ui/rule_actions.py:132\nmsgid \"Key press\"\nmsgstr \"Tuş basımı\"\n\n#: lib/solaar/ui/diversion_rules.py:571 lib/solaar/ui/rule_actions.py:183\nmsgid \"Mouse scroll\"\nmsgstr \"Fare kaydırma\"\n\n#: lib/solaar/ui/diversion_rules.py:572 lib/solaar/ui/rule_actions.py:244\nmsgid \"Mouse click\"\nmsgstr \"Fare tıklaması\"\n\n#: lib/solaar/ui/diversion_rules.py:573\nmsgid \"Set\"\nmsgstr \"Belirle\"\n\n#: lib/solaar/ui/diversion_rules.py:574 lib/solaar/ui/rule_actions.py:314\nmsgid \"Execute\"\nmsgstr \"Uygula\"\n\n#: lib/solaar/ui/diversion_rules.py:575 lib/solaar/ui/diversion_rules.py:1096\nmsgid \"Later\"\nmsgstr \"Sonra\"\n\n#: lib/solaar/ui/diversion_rules.py:604\nmsgid \"Insert new rule\"\nmsgstr \"Yeni kural ekle\"\n\n#: lib/solaar/ui/diversion_rules.py:624 lib/solaar/ui/rule_actions.py:74\n#: lib/solaar/ui/rule_actions.py:273 lib/solaar/ui/rule_conditions.py:548\nmsgid \"Delete\"\nmsgstr \"Sil\"\n\n#: lib/solaar/ui/diversion_rules.py:646\nmsgid \"Negate\"\nmsgstr \"Olumsuzla\"\n\n#: lib/solaar/ui/diversion_rules.py:670\nmsgid \"Wrap with\"\nmsgstr \"Kapsa\"\n\n#: lib/solaar/ui/diversion_rules.py:692\nmsgid \"Cut\"\nmsgstr \"Kes\"\n\n#: lib/solaar/ui/diversion_rules.py:707\nmsgid \"Paste\"\nmsgstr \"Yapıştır\"\n\n#: lib/solaar/ui/diversion_rules.py:713\nmsgid \"Copy\"\nmsgstr \"Kopyala\"\n\n#: lib/solaar/ui/diversion_rules.py:1014\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"Seçilen kural bileşeni henüz desteklenmiyor.\"\n\n#: lib/solaar/ui/diversion_rules.py:1076\nmsgid \"\"\n\"Number of seconds to delay.  Delay between 0 and 1 is done with higher \"\n\"precision.\"\nmsgstr \"\"\n\"Saniye cinsinden gecikme süresi.  0 ile 1 arasındaki gecikmeler daha yüksek \"\n\"hassasiyetle yapılır.\"\n\n#: lib/solaar/ui/diversion_rules.py:1114\nmsgid \"Not\"\nmsgstr \"Değil\"\n\n#: lib/solaar/ui/diversion_rules.py:1145\nmsgid \"Toggle\"\nmsgstr \"Değiştir\"\n\n#: lib/solaar/ui/diversion_rules.py:1146\nmsgid \"True\"\nmsgstr \"Doğru\"\n\n#: lib/solaar/ui/diversion_rules.py:1147\nmsgid \"False\"\nmsgstr \"Yanlış\"\n\n#: lib/solaar/ui/diversion_rules.py:1160\nmsgid \"Unsupported setting\"\nmsgstr \"Desteklenmeyen ayar\"\n\n#: lib/solaar/ui/diversion_rules.py:1322 lib/solaar/ui/diversion_rules.py:1342\n#: lib/solaar/ui/diversion_rules.py:1424 lib/solaar/ui/diversion_rules.py:1669\n#: lib/solaar/ui/diversion_rules.py:1687\nmsgid \"Originating device\"\nmsgstr \"Kaynak aygıt\"\n\n#: lib/solaar/ui/diversion_rules.py:1355\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"Aygıt etkin ve ayarları değiştirilebilir.\"\n\n#: lib/solaar/ui/diversion_rules.py:1364\nmsgid \"Device that originated the current notification.\"\nmsgstr \"Mevcut bildirimin kaynağı olan aygıt.\"\n\n#: lib/solaar/ui/diversion_rules.py:1377\nmsgid \"Name of host computer.\"\nmsgstr \"Bilgisayarın adı.\"\n\n#: lib/solaar/ui/diversion_rules.py:1445\nmsgid \"Value\"\nmsgstr \"Değer\"\n\n#: lib/solaar/ui/diversion_rules.py:1454\nmsgid \"Item\"\nmsgstr \"Öge\"\n\n#: lib/solaar/ui/diversion_rules.py:1728\nmsgid \"Change setting on device\"\nmsgstr \"Aygıtın ayarını değiştir\"\n\n#: lib/solaar/ui/diversion_rules.py:1744\nmsgid \"Setting on device\"\nmsgstr \"Aygıtta ayar\"\n\n#: lib/solaar/ui/notify.py:115\nmsgid \"unspecified reason\"\nmsgstr \"tanımlanmamış sebep\"\n\n#: lib/solaar/ui/pair_window.py:37 lib/solaar/ui/pair_window.py:155\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: yeni aygıtı eşleştir\"\n\n#: lib/solaar/ui/pair_window.py:39\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Bolt alıcılar sadece Bolt aygıtlarla uyumludur.\"\n\n#: lib/solaar/ui/pair_window.py:41\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"\"\n\"Eşleşme ışığı hızlıca yanıp sönene kadar eşleşme düğmesi ya da tuşuna basın.\"\n\n#: lib/solaar/ui/pair_window.py:44\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"Unifying alıcılar sadece Unifying aygıtlarla uyumludur.\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"Diğer alıcılar sadece az miktarda aygıtla uyumludur.\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid \"Turn on the device you want to pair.\"\nmsgstr \"Eşleştirmek istediğiniz aygıtı açın.\"\n\n#: lib/solaar/ui/pair_window.py:49\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"Aygıt yakınlarda açık olan bir alıcıyla eşleşmemiş olmalıdır.\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"Aygıt zaten açıksa, kapatıp tekrar açın.\"\n\n#: lib/solaar/ui/pair_window.py:55\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"Bu alıcı %d aygıtla daha eşleşebilir.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"Bu alıcı %d aygıtla daha eşleşebilir.\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"Bu adımda vezgeçerseniz eşleşme kullanılamayacak.\"\n\n#: lib/solaar/ui/pair_window.py:156\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"%(name)s üzerinde geçiş kodunu girin.\"\n\n#: lib/solaar/ui/pair_window.py:159\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"%(passcode)s yazın ve Enter tuşuna basın.\"\n\n#: lib/solaar/ui/pair_window.py:162\nmsgid \"left\"\nmsgstr \"sol\"\n\n#: lib/solaar/ui/pair_window.py:162\nmsgid \"right\"\nmsgstr \"sağ\"\n\n#: lib/solaar/ui/pair_window.py:164\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"%(code)s basın\\n\"\n\"ve sonra sağ ve sol tuşlarına aynı anda basın.\"\n\n#: lib/solaar/ui/pair_window.py:195\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"Kablosuz bağlantı şifrelenmemiş\"\n\n#: lib/solaar/ui/pair_window.py:200\nmsgid \"Found a new device:\"\nmsgstr \"Yeni bir aygıt bulundu:\"\n\n#: lib/solaar/ui/pair_window.py:221\nmsgid \"Pairing failed\"\nmsgstr \"Eşleşme başarısız\"\n\n#: lib/solaar/ui/pair_window.py:223\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"\"\n\"Aygıtınızın kapsama alanı içerisinde olduğundan, pilin çalıştığından veya \"\n\"şarjının tam olduğundan emin olun.\"\n\n#: lib/solaar/ui/pair_window.py:225\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"Aygıt algılandı fakat bu alıcı ile uyumlu değil.\"\n\n#: lib/solaar/ui/pair_window.py:227\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"Alıcının destekleyebileceğinden daha fazla eşleştirilmiş aygıt.\"\n\n#: lib/solaar/ui/pair_window.py:229\nmsgid \"No further details are available about the error.\"\nmsgstr \"Hata hakkında daha fazla ayrıntı mevcut değil.\"\n\n#: lib/solaar/ui/rule_actions.py:48\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Akorlu tuş tıklaması, basması veya bırakması öykün.\\n\"\n\"Wayland'da /dev/uinput'a yazma yetkisi gerektirir.\"\n\n#: lib/solaar/ui/rule_actions.py:53\nmsgid \"Add key\"\nmsgstr \"Tuş ekle\"\n\n#: lib/solaar/ui/rule_actions.py:56\nmsgid \"Click\"\nmsgstr \"Tıklama\"\n\n#: lib/solaar/ui/rule_actions.py:59\nmsgid \"Depress\"\nmsgstr \"Basma\"\n\n#: lib/solaar/ui/rule_actions.py:62\nmsgid \"Release\"\nmsgstr \"Bırakma\"\n\n#: lib/solaar/ui/rule_actions.py:147\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Fare kayrıdması öykün.\\n\"\n\"Wayland'da /dev/uinput'a yazma yetkisi gerektirir.\"\n\n#: lib/solaar/ui/rule_actions.py:203\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Fare tıklaması öykün.\\n\"\n\"Wayland'da /dev/uinput'a yazma yetkisi gerektirir.\"\n\n#: lib/solaar/ui/rule_actions.py:206\nmsgid \"Button\"\nmsgstr \"Düğme\"\n\n#: lib/solaar/ui/rule_actions.py:207\nmsgid \"Count and Action\"\nmsgstr \"Say ve İşle\"\n\n#: lib/solaar/ui/rule_actions.py:256\nmsgid \"Execute a command with arguments.\"\nmsgstr \"Argümanlarla bir komut çalıştır.\"\n\n#: lib/solaar/ui/rule_actions.py:259\nmsgid \"Add argument\"\nmsgstr \"Argüman ekle\"\n\n#: lib/solaar/ui/rule_conditions.py:43\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"X11 etkin işlem. Sadece X11'de kullanım için.\"\n\n#: lib/solaar/ui/rule_conditions.py:73\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"X11 fare işlemi. Sadece X11'de kullanım için.\"\n\n#: lib/solaar/ui/rule_conditions.py:90\nmsgid \"MouseProcess\"\nmsgstr \"Fareİşlemi\"\n\n#: lib/solaar/ui/rule_conditions.py:114\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"Bildirim tetikleme işlemi özelliği adı.\"\n\n#: lib/solaar/ui/rule_conditions.py:161\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"Bildirim tetikleme işlemi rapor numarası.\"\n\n#: lib/solaar/ui/rule_conditions.py:194\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"Etkin klavye değiştiriciler. Wayland'da her zaman çalışmaz.\"\n\n#: lib/solaar/ui/rule_conditions.py:234\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Yönlendirilmiş tuş veya düğme basıldı veya bırakıldı.\\n\"\n\"Tuşları ve düğmeleri yönlendirmek için Tuş/Düğme Yönlendirme ve \"\n\"Yönlendirilen G Tuşları ayarlarını kullanın.\"\n\n#: lib/solaar/ui/rule_conditions.py:243\nmsgid \"Key down\"\nmsgstr \"Tuş basılı\"\n\n#: lib/solaar/ui/rule_conditions.py:246\nmsgid \"Key up\"\nmsgstr \"Tuş serbest\"\n\n#: lib/solaar/ui/rule_conditions.py:286\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Yönlendirilmiş tuş veya düğme şu anda basılı.\\n\"\n\"Tuşları ve düğmeleri yönlendirmek için Tuş/Düğme Yönlendirme ve \"\n\"Yönlendirilen G Tuşları ayarlarını kullanın.\"\n\n#: lib/solaar/ui/rule_conditions.py:324\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"Bildirim tetikleme işlemi test durumu.\"\n\n#: lib/solaar/ui/rule_conditions.py:328\nmsgid \"Parameter\"\nmsgstr \"Parametre\"\n\n#: lib/solaar/ui/rule_conditions.py:401\nmsgid \"begin (inclusive)\"\nmsgstr \"baş (dahil edilen)\"\n\n#: lib/solaar/ui/rule_conditions.py:402\nmsgid \"end (exclusive)\"\nmsgstr \"son (hariç tutulan)\"\n\n#: lib/solaar/ui/rule_conditions.py:410\nmsgid \"range\"\nmsgstr \"aralık\"\n\n#: lib/solaar/ui/rule_conditions.py:413\nmsgid \"minimum\"\nmsgstr \"en az\"\n\n#: lib/solaar/ui/rule_conditions.py:414\nmsgid \"maximum\"\nmsgstr \"en çok\"\n\n#: lib/solaar/ui/rule_conditions.py:416\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"%(0)d bayttan %(1)d bayta, %(2)d ile %(3)d arasında\"\n\n#: lib/solaar/ui/rule_conditions.py:419 lib/solaar/ui/rule_conditions.py:420\nmsgid \"mask\"\nmsgstr \"maske\"\n\n#: lib/solaar/ui/rule_conditions.py:421\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"%(0)d bayttan %(1)d bayta, %(2)d maskeleme\"\n\n#: lib/solaar/ui/rule_conditions.py:430\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\"Bildirim mesajı tetikleyici kural işlemesinde baytlarda bit veya aralık \"\n\"testi.\"\n\n#: lib/solaar/ui/rule_conditions.py:440\nmsgid \"type\"\nmsgstr \"tür\"\n\n#: lib/solaar/ui/rule_conditions.py:528\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"\"\n\"Sıfır veya daha fazla fare hareketinin ardından isteğe bağlı başlatma \"\n\"düğmesi ile fare hareketi.\"\n\n#: lib/solaar/ui/rule_conditions.py:533\nmsgid \"Add movement\"\nmsgstr \"Hareket ekle\"\n\n#: lib/solaar/ui/tray.py:50\nmsgid \"No supported device found\"\nmsgstr \"Desteklenen aygıt bulunamadı\"\n\n#: lib/solaar/ui/tray.py:55 lib/solaar/ui/window.py:310\n#, python-format\nmsgid \"About %s\"\nmsgstr \"%s Hakkında\"\n\n#: lib/solaar/ui/tray.py:56 lib/solaar/ui/window.py:308\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"%s Çıkış\"\n\n#: lib/solaar/ui/tray.py:267 lib/solaar/ui/tray.py:275\nmsgid \"no receiver\"\nmsgstr \"alıcı yok\"\n\n#: lib/solaar/ui/tray.py:288 lib/solaar/ui/tray.py:293\nmsgid \"offline\"\nmsgstr \"çevrimdışı\"\n\n#: lib/solaar/ui/tray.py:291\nmsgid \"no status\"\nmsgstr \"durum yok\"\n\n#: lib/solaar/ui/window.py:91\nmsgid \"Scanning\"\nmsgstr \"Taranıyor\"\n\n#: lib/solaar/ui/window.py:122\nmsgid \"Battery\"\nmsgstr \"Pil\"\n\n#: lib/solaar/ui/window.py:125\nmsgid \"Wireless Link\"\nmsgstr \"Kablosuz Bağlantı\"\n\n#: lib/solaar/ui/window.py:129\nmsgid \"Lighting\"\nmsgstr \"Aydınlatma\"\n\n#: lib/solaar/ui/window.py:163\nmsgid \"Show Technical Details\"\nmsgstr \"Teknik Ayrıntıları Göster\"\n\n#: lib/solaar/ui/window.py:179\nmsgid \"Pair new device\"\nmsgstr \"Yeni aygıt eşle\"\n\n#: lib/solaar/ui/window.py:197\nmsgid \"Select a device\"\nmsgstr \"Aygıtı seç\"\n\n#: lib/solaar/ui/window.py:313\nmsgid \"Rule Editor\"\nmsgstr \"Kural Düzenleyici\"\n\n#: lib/solaar/ui/window.py:517\nmsgid \"Path\"\nmsgstr \"Yol\"\n\n#: lib/solaar/ui/window.py:520\nmsgid \"USB ID\"\nmsgstr \"USB Kimliği\"\n\n#: lib/solaar/ui/window.py:523 lib/solaar/ui/window.py:525\n#: lib/solaar/ui/window.py:540 lib/solaar/ui/window.py:542\nmsgid \"Serial\"\nmsgstr \"Seri\"\n\n#: lib/solaar/ui/window.py:529\nmsgid \"Index\"\nmsgstr \"Dizin\"\n\n#: lib/solaar/ui/window.py:531\nmsgid \"Wireless PID\"\nmsgstr \"Kablosuz bağlantı kimliği\"\n\n#: lib/solaar/ui/window.py:533\nmsgid \"Product ID\"\nmsgstr \"Ürün Kimliği\"\n\n#: lib/solaar/ui/window.py:535\nmsgid \"Protocol\"\nmsgstr \"İletişim kuralı\"\n\n#: lib/solaar/ui/window.py:535\nmsgid \"Unknown\"\nmsgstr \"Bilinmeyen\"\n\n#: lib/solaar/ui/window.py:537\nmsgid \"Polling rate\"\nmsgstr \"Bağlantı sıklığı\"\n\n#: lib/solaar/ui/window.py:544\nmsgid \"Unit ID\"\nmsgstr \"Birim Kimliği\"\n\n#: lib/solaar/ui/window.py:558\nmsgid \"Notifications\"\nmsgstr \"Bildirimler\"\n\n#: lib/solaar/ui/window.py:602\nmsgid \"No device paired.\"\nmsgstr \"Eşleştirilmiş aygıt yok.\"\n\n#: lib/solaar/ui/window.py:611\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"En fazla %(max_count)s aygıt bu alıcıyla eşleşebilir.\"\nmsgstr[1] \"En fazla %(max_count)s aygıt bu alıcıyla eşleşebilir.\"\n\n#: lib/solaar/ui/window.py:622\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"Bu alıcı %d aygıtla daha eşleşebilir.\"\nmsgstr[1] \"Bu alıcı %d aygıtla daha eşleşebilir.\"\n\n#: lib/solaar/ui/window.py:679\nmsgid \"Battery Voltage\"\nmsgstr \"Pil Gerilimi\"\n\n#: lib/solaar/ui/window.py:681\nmsgid \"Voltage reported by battery\"\nmsgstr \"Pil tarafından bildirilen gerilim\"\n\n#: lib/solaar/ui/window.py:683\nmsgid \"Battery Level\"\nmsgstr \"Pil Düzeyi\"\n\n#: lib/solaar/ui/window.py:685\nmsgid \"Approximate level reported by battery\"\nmsgstr \"Pil tarafından bildirilen yaklaşık düzeyi\"\n\n#: lib/solaar/ui/window.py:692 lib/solaar/ui/window.py:694\nmsgid \"next reported \"\nmsgstr \"sonraki rapor \"\n\n#: lib/solaar/ui/window.py:695\nmsgid \" and next level to be reported.\"\nmsgstr \" ve sonraki seviye raporlanması.\"\n\n#: lib/solaar/ui/window.py:711\nmsgid \"encrypted\"\nmsgstr \"şifreli\"\n\n#: lib/solaar/ui/window.py:713\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"Bu aygıt ile alıcı arasındaki kablosuz bağlantı şirelenmiştir.\"\n\n#: lib/solaar/ui/window.py:715\nmsgid \"not encrypted\"\nmsgstr \"şifresiz\"\n\n#: lib/solaar/ui/window.py:719\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"Bu aygıt ile alıcı arasındaki kablosuz bağlantı şirelenmemiştir.\\n\"\n\"Bu işaretçi cihazlar için güvenlik açığı ve metin-giriş aygıtları için büyük \"\n\"bir güvenlik açığı.\"\n\n#: lib/solaar/ui/window.py:735\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d lüks\"\n"
  },
  {
    "path": "po/uk.po",
    "content": "# Ukrainian translation for solaar\n# This file is distributed under the same license as the solaar package.\n# Kira, 2025.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 1.1.14\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-10-16 18:53+0300\\n\"\n\"PO-Revision-Date: 2025-10-16 20:11+0300\\n\"\n\"Last-Translator: Олександр Афанасьєв <retaskclub@gmail.com>\\n\"\n\"Language-Team: Ukrainian <uk@li.org>\\n\"\n\"Language: uk\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && \"\n\"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\\n\"\n\n#: lib/logitech_receiver/base_usb.py:52\nmsgid \"Bolt Receiver\"\nmsgstr \"Приймач Bolt\"\n\n#: lib/logitech_receiver/base_usb.py:64\nmsgid \"Unifying Receiver\"\nmsgstr \"Приймач Unifying\"\n\n#: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87\n#: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113\nmsgid \"Nano Receiver\"\nmsgstr \"Наноприймач\"\n\n#: lib/logitech_receiver/base_usb.py:125\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Приймач Lightspeed\"\n\n#: lib/logitech_receiver/base_usb.py:135\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"Приймач EX100 27 МГц\"\n\n#: lib/logitech_receiver/common.py:649\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"Батарея: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:652\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"Батарея: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:1023\n#: lib/logitech_receiver/settings_templates.py:295\nmsgid \"Disabled\"\nmsgstr \"Вимкнено\"\n\n#: lib/logitech_receiver/hidpp20.py:1024\nmsgid \"Static\"\nmsgstr \"Статичний\"\n\n#: lib/logitech_receiver/hidpp20.py:1025\nmsgid \"Pulse\"\nmsgstr \"Пульсація\"\n\n#: lib/logitech_receiver/hidpp20.py:1026\nmsgid \"Cycle\"\nmsgstr \"Цикл\"\n\n#: lib/logitech_receiver/hidpp20.py:1027\nmsgid \"Boot\"\nmsgstr \"Завантаження\"\n\n#: lib/logitech_receiver/hidpp20.py:1028\nmsgid \"Demo\"\nmsgstr \"Демо\"\n\n#: lib/logitech_receiver/hidpp20.py:1030\nmsgid \"Breathe\"\nmsgstr \"Дихання\"\n\n#: lib/logitech_receiver/hidpp20.py:1033\nmsgid \"Ripple\"\nmsgstr \"Брижі\"\n\n#: lib/logitech_receiver/hidpp20.py:1034\nmsgid \"Decomposition\"\nmsgstr \"Розкладання\"\n\n#: lib/logitech_receiver/hidpp20.py:1035\nmsgid \"Signature1\"\nmsgstr \"Підпис1\"\n\n#: lib/logitech_receiver/hidpp20.py:1036\nmsgid \"Signature2\"\nmsgstr \"Підпис2\"\n\n#: lib/logitech_receiver/hidpp20.py:1037\nmsgid \"CycleS\"\nmsgstr \"ЦиклS\"\n\n#: lib/logitech_receiver/hidpp20.py:1101\nmsgid \"Unknown Location\"\nmsgstr \"Невідоме місце\"\n\n#: lib/logitech_receiver/hidpp20.py:1102\nmsgid \"Primary\"\nmsgstr \"Основний\"\n\n#: lib/logitech_receiver/hidpp20.py:1103\nmsgid \"Logo\"\nmsgstr \"Логотип\"\n\n#: lib/logitech_receiver/hidpp20.py:1104\nmsgid \"Left Side\"\nmsgstr \"Ліва сторона\"\n\n#: lib/logitech_receiver/hidpp20.py:1105\nmsgid \"Right Side\"\nmsgstr \"Права сторона\"\n\n#: lib/logitech_receiver/hidpp20.py:1106\nmsgid \"Combined\"\nmsgstr \"Комбінований\"\n\n#: lib/logitech_receiver/hidpp20.py:1107\nmsgid \"Primary 1\"\nmsgstr \"Основний 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1108\nmsgid \"Primary 2\"\nmsgstr \"Основний 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1109\nmsgid \"Primary 3\"\nmsgstr \"Основний 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1110\nmsgid \"Primary 4\"\nmsgstr \"Основний 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1111\nmsgid \"Primary 5\"\nmsgstr \"Основний 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1112\nmsgid \"Primary 6\"\nmsgstr \"Основний 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"порожній\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"критичний\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"низький\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"середній\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"добрий\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"повний\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"розряджається\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"заряджається\"\n\n#: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700\nmsgid \"charging\"\nmsgstr \"заряджається\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"не заряджається\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"майже повний\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"заряджено\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"повільне заряджання\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"invalid battery\"\nmsgstr \"несправна батарея\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"термічна помилка\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"помилка\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"стандартний\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"швидкий\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"повільний\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"тайм-аут пристрою\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"пристрій не підтримується\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"забагато пристроїв\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"тайм-аут послідовності\"\n\n#: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555\nmsgid \"Firmware\"\nmsgstr \"Мікропрограма\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"Завантажувач\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"Обладнання\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"Інше\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"Ліва кнопка\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"Права кнопка\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"Середня кнопка\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"Кнопка 'Назад'\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"Кнопка 'Вперед'\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"Кнопка жестів миші\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"Розумне перемикання\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"Перемикач DPI\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"Нахил вліво\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"Нахил вправо\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"Лівий клік\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"Правий клік\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"Середня кнопка миші\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"Кнопка миші 'Назад'\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"Кнопка миші 'Вперед'\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"Навігація кнопкою жестів\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"Кнопка прокрутки миші вліво\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"Кнопка прокрутки миші вправо\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"натиснуто\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"відпущено\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"connected\"\nmsgstr \"під'єднано\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"disconnected\"\nmsgstr \"від'єднано\"\n\n#: lib/logitech_receiver/notifications.py:182\nmsgid \"unpaired\"\nmsgstr \"пару розірвано\"\n\n#: lib/logitech_receiver/notifications.py:231\nmsgid \"powered on\"\nmsgstr \"увімкнено\"\n\n#: lib/logitech_receiver/notifications.py:283\nmsgid \"ADC measurement notification\"\nmsgstr \"сповіщення про вимірювання АЦП\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:483\nmsgid \"pairing lock is closed\"\nmsgstr \"блокування створення пари закрито\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:483\nmsgid \"pairing lock is open\"\nmsgstr \"блокування створення пари відкрито\"\n\n#: lib/logitech_receiver/notifications.py:446\nmsgid \"discovery lock is closed\"\nmsgstr \"блокування виявлення закрито\"\n\n#: lib/logitech_receiver/notifications.py:446\nmsgid \"discovery lock is open\"\nmsgstr \"блокування виявлення відкрито\"\n\n#: lib/logitech_receiver/receiver.py:437\nmsgid \"No paired devices.\"\nmsgstr \"Немає під'єднаних пристроїв.\"\n\n#: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s під'єднаний пристрій.\"\nmsgstr[1] \"%(count)s під'єднаних пристроїв.\"\nmsgstr[2] \"%(count)s під'єднаних пристроїв.\"\n\n#: lib/logitech_receiver/settings.py:598\nmsgid \"register\"\nmsgstr \"реєстр\"\n\n#: lib/logitech_receiver/settings.py:612 lib/logitech_receiver/settings.py:650\nmsgid \"feature\"\nmsgstr \"функція\"\n\n#: lib/logitech_receiver/settings_templates.py:134\nmsgid \"Swap Fx function\"\nmsgstr \"Поміняти функцію Fx\"\n\n#: lib/logitech_receiver/settings_templates.py:137\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"Якщо встановлено, клавіші F1-F12 активуватимуть свою спеціальну функцію,\\n\"\n\"і вам потрібно буде утримувати клавішу FN для активації стандартної функції.\"\n\n#: lib/logitech_receiver/settings_templates.py:142\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"Якщо не встановлено, клавіші F1-F12 активуватимуть свою стандартну функцію,\\n\"\n\"і вам потрібно буде утримувати клавішу FN для активації спеціальної функції.\"\n\n#: lib/logitech_receiver/settings_templates.py:150\nmsgid \"Hand Detection\"\nmsgstr \"Виявлення рук\"\n\n#: lib/logitech_receiver/settings_templates.py:151\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"Вмикати підсвічування, коли руки знаходяться над клавіатурою.\"\n\n#: lib/logitech_receiver/settings_templates.py:158\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"Плавне прокручування коліщатка\"\n\n#: lib/logitech_receiver/settings_templates.py:159\n#: lib/logitech_receiver/settings_templates.py:406\n#: lib/logitech_receiver/settings_templates.py:435\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"Режим високої чутливості для вертикального прокручування коліщатком.\"\n\n#: lib/logitech_receiver/settings_templates.py:166\nmsgid \"Side Scrolling\"\nmsgstr \"Бічне прокручування\"\n\n#: lib/logitech_receiver/settings_templates.py:168\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"Якщо вимкнено, натискання коліщатка вбік надсилає спеціальні події кнопок\\n\"\n\"замість стандартних подій бічного прокручування.\"\n\n#: lib/logitech_receiver/settings_templates.py:178\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"Чутливість (DPI - для старих мишей)\"\n\n#: lib/logitech_receiver/settings_templates.py:179\n#: lib/logitech_receiver/settings_templates.py:983\n#: lib/logitech_receiver/settings_templates.py:1011\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"Чутливість руху миші\"\n\n#: lib/logitech_receiver/settings_templates.py:252\nmsgid \"Backlight Timed\"\nmsgstr \"Підсвічування за таймером\"\n\n#: lib/logitech_receiver/settings_templates.py:253\n#: lib/logitech_receiver/settings_templates.py:393\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"Встановити час підсвічування клавіатури.\"\n\n#: lib/logitech_receiver/settings_templates.py:264\nmsgid \"Backlight\"\nmsgstr \"Підсвічування\"\n\n#: lib/logitech_receiver/settings_templates.py:265\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"\"\n\"Рівень підсвічування клавіатури. Зміни застосовуються лише в ручному режимі.\"\n\n#: lib/logitech_receiver/settings_templates.py:297\nmsgid \"Automatic\"\nmsgstr \"Автоматично\"\n\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid \"Manual\"\nmsgstr \"Вручну\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid \"Enabled\"\nmsgstr \"Увімкнено\"\n\n#: lib/logitech_receiver/settings_templates.py:307\nmsgid \"Backlight Level\"\nmsgstr \"Рівень підсвічування\"\n\n#: lib/logitech_receiver/settings_templates.py:308\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"Рівень підсвічування клавіатури в ручному режимі.\"\n\n#: lib/logitech_receiver/settings_templates.py:365\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"Затримка підсвічування (руки прибрано)\"\n\n#: lib/logitech_receiver/settings_templates.py:366\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"\"\n\"Затримка в секундах до згасання підсвічування, коли руки прибрані з \"\n\"клавіатури.\"\n\n#: lib/logitech_receiver/settings_templates.py:374\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"Затримка підсвічування (руки на клавіатурі)\"\n\n#: lib/logitech_receiver/settings_templates.py:375\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"\"\n\"Затримка в секундах до згасання підсвічування, коли руки біля клавіатури.\"\n\n#: lib/logitech_receiver/settings_templates.py:383\nmsgid \"Backlight Delay Powered\"\nmsgstr \"Затримка підсвічування (від живлення)\"\n\n#: lib/logitech_receiver/settings_templates.py:384\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"\"\n\"Затримка в секундах до згасання підсвічування при зовнішньому живленні.\"\n\n#: lib/logitech_receiver/settings_templates.py:392\nmsgid \"Backlight (Seconds)\"\nmsgstr \"Підсвічування (секунди)\"\n\n#: lib/logitech_receiver/settings_templates.py:404\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"Висока роздільна здатність коліщатка\"\n\n#: lib/logitech_receiver/settings_templates.py:408\n#: lib/logitech_receiver/settings_templates.py:437\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"Ігнорувати, якщо прокручування ненормально швидке або повільне\"\n\n#: lib/logitech_receiver/settings_templates.py:415\n#: lib/logitech_receiver/settings_templates.py:446\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"Перенаправлення коліщатка прокрутки\"\n\n#: lib/logitech_receiver/settings_templates.py:417\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Примусити коліщатко прокрутки надсилати сповіщення LOWRES_WHEEL HID++ (які \"\n\"запускають правила Solaar, але в іншому випадку ігноруються).\"\n\n#: lib/logitech_receiver/settings_templates.py:424\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"Напрямок прокручування коліщатка\"\n\n#: lib/logitech_receiver/settings_templates.py:425\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"Інвертувати напрямок вертикального прокручування коліщатком.\"\n\n#: lib/logitech_receiver/settings_templates.py:433\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"Роздільна здатність коліщатка прокрутки\"\n\n#: lib/logitech_receiver/settings_templates.py:448\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Примусити коліщатко прокрутки надсилати сповіщення HIRES_WHEEL HID++ (які \"\n\"запускають правила Solaar, але в іншому випадку ігноруються).\"\n\n#: lib/logitech_receiver/settings_templates.py:457\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"Чутливість (швидкість вказівника)\"\n\n#: lib/logitech_receiver/settings_templates.py:458\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"Множник швидкості для миші (256 — звичайний множник).\"\n\n#: lib/logitech_receiver/settings_templates.py:468\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"Перенаправлення коліщатка для великого пальця\"\n\n#: lib/logitech_receiver/settings_templates.py:470\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"Примусити коліщатко для великого пальця надсилати сповіщення THUMB_WHEEL HID+\"\n\"+ (які запускають правила Solaar, але в іншому випадку ігноруються).\"\n\n#: lib/logitech_receiver/settings_templates.py:479\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"Напрямок коліщатка для великого пальця\"\n\n#: lib/logitech_receiver/settings_templates.py:480\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"Інвертувати напрямок прокручування коліщатка для великого пальця.\"\n\n#: lib/logitech_receiver/settings_templates.py:500\nmsgid \"Onboard Profiles\"\nmsgstr \"Вбудовані профілі\"\n\n#: lib/logitech_receiver/settings_templates.py:501\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"\"\n\"Увімкнути вбудований профіль, який контролює частоту опитування, чутливість \"\n\"та дії кнопок\"\n\n#: lib/logitech_receiver/settings_templates.py:545\n#: lib/logitech_receiver/settings_templates.py:578\nmsgid \"Report Rate\"\nmsgstr \"Частота опитування\"\n\n#: lib/logitech_receiver/settings_templates.py:547\n#: lib/logitech_receiver/settings_templates.py:580\nmsgid \"Frequency of device movement reports\"\nmsgstr \"Частота звітів про рух пристрою\"\n\n#: lib/logitech_receiver/settings_templates.py:547\n#: lib/logitech_receiver/settings_templates.py:580\n#: lib/logitech_receiver/settings_templates.py:1011\n#: lib/logitech_receiver/settings_templates.py:1385\n#: lib/logitech_receiver/settings_templates.py:1416\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"Для ефективності може знадобитися вимкнути вбудовані профілі.\"\n\n#: lib/logitech_receiver/settings_templates.py:608\nmsgid \"Divert crown events\"\nmsgstr \"Перенаправляти події коронки\"\n\n#: lib/logitech_receiver/settings_templates.py:609\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Примусити коронку надсилати сповіщення CROWN HID++ (які запускають правила \"\n\"Solaar, але в іншому випадку ігноруються).\"\n\n#: lib/logitech_receiver/settings_templates.py:617\nmsgid \"Crown smooth scroll\"\nmsgstr \"Плавне прокручування коронкою\"\n\n#: lib/logitech_receiver/settings_templates.py:618\nmsgid \"Set crown smooth scroll\"\nmsgstr \"Встановити плавне прокручування коронкою\"\n\n#: lib/logitech_receiver/settings_templates.py:626\nmsgid \"Divert G and M Keys\"\nmsgstr \"Перенаправити клавіші G та M\"\n\n#: lib/logitech_receiver/settings_templates.py:627\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"Примусити клавіші G та M надсилати сповіщення HID++ (які запускають правила \"\n\"Solaar, але в іншому випадку ігноруються).\"\n\n#: lib/logitech_receiver/settings_templates.py:641\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"Тріскачка коліщатка прокрутки\"\n\n#: lib/logitech_receiver/settings_templates.py:642\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"\"\n\"Перемикання коліщатка миші між тріскачкою з контролем швидкості та вільним \"\n\"обертанням.\"\n\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid \"Freespinning\"\nmsgstr \"Вільне обертання\"\n\n#: lib/logitech_receiver/settings_templates.py:644\nmsgid \"Ratcheted\"\nmsgstr \"Тріскачка\"\n\n#: lib/logitech_receiver/settings_templates.py:651\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"Швидкість тріскачки коліщатка прокрутки\"\n\n#: lib/logitech_receiver/settings_templates.py:653\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"Використовуйте швидкість коліщатка миші для перемикання між тріскачкою та \"\n\"вільним обертанням.\\n\"\n\"Коліщатко миші завжди має тріскачку на 50.\"\n\n#: lib/logitech_receiver/settings_templates.py:707\nmsgid \"Key/Button Actions\"\nmsgstr \"Дії клавіш/кнопок\"\n\n#: lib/logitech_receiver/settings_templates.py:709\nmsgid \"Change the action for the key or button.\"\nmsgstr \"Змінити дію для клавіші або кнопки.\"\n\n#: lib/logitech_receiver/settings_templates.py:711\nmsgid \"Overridden by diversion.\"\nmsgstr \"Перевизначено перенаправленням.\"\n\n#: lib/logitech_receiver/settings_templates.py:713\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"\"\n\"Зміна важливих дій (наприклад, для лівої кнопки миші) може призвести до \"\n\"непрацездатності системи.\"\n\n#: lib/solaar/ui/__init__.py:120\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"Інший процес Solaar вже запущено, тому просто показуємо його вікно\"\n\n#: lib/solaar/ui/about/model.py:36\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"Керує приймачами, клавіатурами,\\n\"\n\"мишами та планшетами Logitech.\"\n\n#: lib/solaar/ui/about/model.py:63\nmsgid \"Additional Programming\"\nmsgstr \"Додаткове програмування\"\n\n#: lib/solaar/ui/about/model.py:64\nmsgid \"GUI design\"\nmsgstr \"Дизайн GUI\"\n\n#: lib/solaar/ui/about/model.py:66\nmsgid \"Testing\"\nmsgstr \"Тестування\"\n\n#: lib/solaar/ui/about/model.py:74\nmsgid \"Logitech documentation\"\nmsgstr \"Документація Logitech\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92\n#: lib/solaar/ui/window.py:208\nmsgid \"Unpair\"\nmsgstr \"Розірвати пару\"\n\n#: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141\nmsgid \"Cancel\"\nmsgstr \"Скасувати\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Permissions error\"\nmsgstr \"Помилка дозволів\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"\"\n\"Знайдено приймач або пристрій Logitech (%s), але немає дозволу на його \"\n\"відкриття.\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"\"\n\"Якщо ви щойно встановили Solaar, спробуйте від'єднати та знову під'єднати \"\n\"приймач або пристрій.\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Cannot connect to device error\"\nmsgstr \"Помилка підключення до пристрою\"\n\n#: lib/solaar/ui/common.py:51\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"\"\n\"Знайдено приймач або пристрій Logitech за адресою %s, але виникла помилка \"\n\"при підключенні до нього.\"\n\n#: lib/solaar/ui/common.py:53\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"\"\n\"Спробуйте від'єднати та знову під'єднати пристрій або вимкнути та увімкнути \"\n\"його.\"\n\n#: lib/solaar/ui/common.py:56\nmsgid \"Unpairing failed\"\nmsgstr \"Не вдалося розірвати пару\"\n\n#: lib/solaar/ui/common.py:58\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"Не вдалося розірвати пару між %{device} та %{receiver}.\"\n\n#: lib/solaar/ui/common.py:63\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"Приймач повернув помилку без додаткових деталей.\"\n\n#: lib/solaar/ui/config_panel.py:241\nmsgid \"Complete - ENTER to change\"\nmsgstr \"Завершено - ENTER для зміни\"\n\n#: lib/solaar/ui/config_panel.py:241\nmsgid \"Incomplete\"\nmsgstr \"Не завершено\"\n\n#: lib/solaar/ui/config_panel.py:487 lib/solaar/ui/config_panel.py:539\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d значення\"\nmsgstr[1] \"%d значення\"\nmsgstr[2] \"%d значень\"\n\n#: lib/solaar/ui/config_panel.py:621\nmsgid \"Changes allowed\"\nmsgstr \"Зміни дозволено\"\n\n#: lib/solaar/ui/config_panel.py:622\nmsgid \"No changes allowed\"\nmsgstr \"Зміни не дозволено\"\n\n#: lib/solaar/ui/config_panel.py:623\nmsgid \"Ignore this setting\"\nmsgstr \"Ігнорувати це налаштування\"\n\n#: lib/solaar/ui/config_panel.py:667\nmsgid \"Working\"\nmsgstr \"Працюю\"\n\n#: lib/solaar/ui/config_panel.py:670\nmsgid \"Read/write operation failed.\"\nmsgstr \"Операція читання/запису не вдалася.\"\n\n#: lib/solaar/ui/desktop_notifications.py:112\nmsgid \"unspecified reason\"\nmsgstr \"невідома причина\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"Built-in rules\"\nmsgstr \"Вбудовані правила\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"User-defined rules\"\nmsgstr \"Правила користувача\"\n\n#: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126\nmsgid \"Rule\"\nmsgstr \"Правило\"\n\n#: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382\n#: lib/solaar/ui/diversion_rules.py:509\nmsgid \"Sub-rule\"\nmsgstr \"Підправило\"\n\n#: lib/solaar/ui/diversion_rules.py:108\nmsgid \"[empty]\"\nmsgstr \"[порожньо]\"\n\n#: lib/solaar/ui/diversion_rules.py:132\nmsgid \"Make changes permanent?\"\nmsgstr \"Зробити зміни постійними?\"\n\n#: lib/solaar/ui/diversion_rules.py:137\nmsgid \"Yes\"\nmsgstr \"Так\"\n\n#: lib/solaar/ui/diversion_rules.py:139\nmsgid \"No\"\nmsgstr \"Ні\"\n\n#: lib/solaar/ui/diversion_rules.py:144\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"Якщо ви оберете 'Ні', зміни буде втрачено при закритті Solaar.\"\n\n#: lib/solaar/ui/diversion_rules.py:273\nmsgid \"Paste here\"\nmsgstr \"Вставити сюди\"\n\n#: lib/solaar/ui/diversion_rules.py:275\nmsgid \"Paste above\"\nmsgstr \"Вставити вище\"\n\n#: lib/solaar/ui/diversion_rules.py:277\nmsgid \"Paste below\"\nmsgstr \"Вставити нижче\"\n\n#: lib/solaar/ui/diversion_rules.py:283\nmsgid \"Paste rule here\"\nmsgstr \"Вставити правило сюди\"\n\n#: lib/solaar/ui/diversion_rules.py:285\nmsgid \"Paste rule above\"\nmsgstr \"Вставити правило вище\"\n\n#: lib/solaar/ui/diversion_rules.py:287\nmsgid \"Paste rule below\"\nmsgstr \"Вставити правило нижче\"\n\n#: lib/solaar/ui/diversion_rules.py:291\nmsgid \"Paste rule\"\nmsgstr \"Вставити правило\"\n\n#: lib/solaar/ui/diversion_rules.py:306\nmsgid \"Insert here\"\nmsgstr \"Вставити сюди\"\n\n#: lib/solaar/ui/diversion_rules.py:308\nmsgid \"Insert above\"\nmsgstr \"Вставити вище\"\n\n#: lib/solaar/ui/diversion_rules.py:310\nmsgid \"Insert below\"\nmsgstr \"Вставити нижче\"\n\n#: lib/solaar/ui/diversion_rules.py:316\nmsgid \"Insert new rule here\"\nmsgstr \"Вставити нове правило сюди\"\n\n#: lib/solaar/ui/diversion_rules.py:318\nmsgid \"Insert new rule above\"\nmsgstr \"Вставити нове правило вище\"\n\n#: lib/solaar/ui/diversion_rules.py:320\nmsgid \"Insert new rule below\"\nmsgstr \"Вставити нове правило нижче\"\n\n#: lib/solaar/ui/diversion_rules.py:347\nmsgid \"Flatten\"\nmsgstr \"Сплощити\"\n\n#: lib/solaar/ui/diversion_rules.py:380\nmsgid \"Insert\"\nmsgstr \"Вставити\"\n\n#: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511\n#: lib/solaar/ui/diversion_rules.py:1158\nmsgid \"Or\"\nmsgstr \"Або\"\n\n#: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510\n#: lib/solaar/ui/diversion_rules.py:1144\nmsgid \"And\"\nmsgstr \"І\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid \"Condition\"\nmsgstr \"Умова\"\n\n#: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154\nmsgid \"Feature\"\nmsgstr \"Функція\"\n\n#: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188\nmsgid \"Report\"\nmsgstr \"Звіт\"\n\n#: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69\nmsgid \"Process\"\nmsgstr \"Процес\"\n\n#: lib/solaar/ui/diversion_rules.py:391\nmsgid \"Mouse process\"\nmsgstr \"Процес миші\"\n\n#: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225\nmsgid \"Modifiers\"\nmsgstr \"Модифікатори\"\n\n#: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277\nmsgid \"Key\"\nmsgstr \"Клавіша\"\n\n#: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318\nmsgid \"KeyIsDown\"\nmsgstr \"КлавішаНатиснута\"\n\n#: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432\nmsgid \"Active\"\nmsgstr \"Активний\"\n\n#: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390\n#: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487\nmsgid \"Device\"\nmsgstr \"Пристрій\"\n\n#: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467\nmsgid \"Host\"\nmsgstr \"Хост\"\n\n#: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506\nmsgid \"Setting\"\nmsgstr \"Налаштування\"\n\n#: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333\n#: lib/solaar/ui/rule_conditions.py:382\nmsgid \"Test\"\nmsgstr \"Тест\"\n\n#: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507\nmsgid \"Test bytes\"\nmsgstr \"Тестові байти\"\n\n#: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608\nmsgid \"Mouse Gesture\"\nmsgstr \"Жест миші\"\n\n#: lib/solaar/ui/diversion_rules.py:405\nmsgid \"Action\"\nmsgstr \"Дія\"\n\n#: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138\nmsgid \"Key press\"\nmsgstr \"Натискання клавіші\"\n\n#: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191\nmsgid \"Mouse scroll\"\nmsgstr \"Прокручування миші\"\n\n#: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:254\nmsgid \"Mouse click\"\nmsgstr \"Клік миші\"\n\n#: lib/solaar/ui/diversion_rules.py:410\nmsgid \"Set\"\nmsgstr \"Встановити\"\n\n#: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:326\nmsgid \"Execute\"\nmsgstr \"Виконати\"\n\n#: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189\nmsgid \"Later\"\nmsgstr \"Пізніше\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid \"Insert new rule\"\nmsgstr \"Вставити нове правило\"\n\n#: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82\n#: lib/solaar/ui/rule_actions.py:285 lib/solaar/ui/rule_conditions.py:556\nmsgid \"Delete\"\nmsgstr \"Видалити\"\n\n#: lib/solaar/ui/diversion_rules.py:483\nmsgid \"Negate\"\nmsgstr \"Заперечити\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid \"Wrap with\"\nmsgstr \"Огорнути в\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid \"Cut\"\nmsgstr \"Вирізати\"\n\n#: lib/solaar/ui/diversion_rules.py:553\nmsgid \"Paste\"\nmsgstr \"Вставити\"\n\n#: lib/solaar/ui/diversion_rules.py:559\nmsgid \"Copy\"\nmsgstr \"Копіювати\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Редактор правил Solaar\"\n\n#: lib/solaar/ui/diversion_rules.py:668\nmsgid \"Save changes\"\nmsgstr \"Зберегти зміни\"\n\n#: lib/solaar/ui/diversion_rules.py:673\nmsgid \"Discard changes\"\nmsgstr \"Скасувати зміни\"\n\n#: lib/solaar/ui/diversion_rules.py:1104\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"Цей редактор ще не підтримує вибраний компонент правила.\"\n\n#: lib/solaar/ui/diversion_rules.py:1169\nmsgid \"\"\n\"Number of seconds to delay.\\n\"\n\"Delay between 0 and 1 is done with higher precision.\"\nmsgstr \"\"\n\"Кількість секунд для затримки.\\n\"\n\"Затримка від 0 до 1 виконується з вищою точністю.\"\n\n#: lib/solaar/ui/diversion_rules.py:1207\nmsgid \"Not\"\nmsgstr \"Не\"\n\n#: lib/solaar/ui/diversion_rules.py:1238\nmsgid \"Toggle\"\nmsgstr \"Перемкнути\"\n\n#: lib/solaar/ui/diversion_rules.py:1239\nmsgid \"True\"\nmsgstr \"Істина\"\n\n#: lib/solaar/ui/diversion_rules.py:1240\nmsgid \"False\"\nmsgstr \"Хиба\"\n\n#: lib/solaar/ui/diversion_rules.py:1253\nmsgid \"Unsupported setting\"\nmsgstr \"Налаштування не підтримується\"\n\n#: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415\n#: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748\n#: lib/solaar/ui/diversion_rules.py:1766\nmsgid \"Originating device\"\nmsgstr \"Пристрій-джерело\"\n\n#: lib/solaar/ui/diversion_rules.py:1428\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"Пристрій активний, і його налаштування можна змінювати.\"\n\n#: lib/solaar/ui/diversion_rules.py:1437\nmsgid \"Device that originated the current notification.\"\nmsgstr \"Пристрій, який надіслав поточне сповіщення.\"\n\n#: lib/solaar/ui/diversion_rules.py:1450\nmsgid \"Name of host computer.\"\nmsgstr \"Ім'я комп'ютера-хоста.\"\n\n#: lib/solaar/ui/diversion_rules.py:1520\nmsgid \"Value\"\nmsgstr \"Значення\"\n\n#: lib/solaar/ui/diversion_rules.py:1529\nmsgid \"Item\"\nmsgstr \"Елемент\"\n\n#: lib/solaar/ui/diversion_rules.py:1808\nmsgid \"Change setting on device\"\nmsgstr \"Змінити налаштування на пристрої\"\n\n#: lib/solaar/ui/diversion_rules.py:1824\nmsgid \"Setting on device\"\nmsgstr \"Налаштування на пристрої\"\n\n#: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: створити пару з новим пристроєм\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Приймачі Bolt сумісні лише з пристроями Bolt.\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"\"\n\"Натисніть кнопку або клавішу створення пари, доки індикатор не почне швидко \"\n\"блимати.\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"Приймачі Unifying сумісні лише з пристроями Unifying.\"\n\n#: lib/solaar/ui/pair_window.py:53\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"Інші приймачі сумісні лише з кількома пристроями.\"\n\n#: lib/solaar/ui/pair_window.py:55\nmsgid \"For most devices, turn on the device you want to pair.\"\nmsgstr \"\"\n\"Для більшості пристроїв увімкніть пристрій, з яким хочете створити пару.\"\n\n#: lib/solaar/ui/pair_window.py:56\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"Якщо пристрій уже увімкнено, вимкніть його та увімкніть знову.\"\n\n#: lib/solaar/ui/pair_window.py:58\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"\"\n\"Пристрій не повинен бути з'єднаний з іншим увімкненим приймачем поблизу.\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid \"\"\n\"For devices with multiple channels, press, hold, and release the button for \"\n\"the channel you wish to pair\\n\"\n\"or use the channel switch button to select a channel and then press, hold, \"\n\"and release the channel switch button.\"\nmsgstr \"\"\n\"Для пристроїв з кількома каналами натисніть, утримуйте та відпустіть кнопку \"\n\"потрібного каналу\\n\"\n\"або скористайтеся кнопкою перемикання каналів, щоб вибрати канал, а потім \"\n\"натисніть, утримуйте та відпустіть її.\"\n\n#: lib/solaar/ui/pair_window.py:68\nmsgid \"The channel indicator light should be blinking rapidly.\"\nmsgstr \"Індикатор каналу повинен швидко блимати.\"\n\n#: lib/solaar/ui/pair_window.py:72\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"Цей приймач має ще %d спробу створення пари.\"\nmsgstr[1] \"\"\n\"\\n\"\n\"\\n\"\n\"Цей приймач має ще %d спроби створення пари.\"\nmsgstr[2] \"\"\n\"\\n\"\n\"\\n\"\n\"Цей приймач має ще %d спроб створення пари.\"\n\n#: lib/solaar/ui/pair_window.py:78\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"Скасування на цьому етапі не використає спробу створення пари.\"\n\n#: lib/solaar/ui/pair_window.py:168\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"Введіть пароль на %(name)s.\"\n\n#: lib/solaar/ui/pair_window.py:171\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"Введіть %(passcode)s, а потім натисніть клавішу Enter.\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"left\"\nmsgstr \"ліва\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"right\"\nmsgstr \"права\"\n\n#: lib/solaar/ui/pair_window.py:178\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"Натисніть %(code)s\\n\"\n\", а потім одночасно натисніть ліву та праву кнопки.\"\n\n#: lib/solaar/ui/pair_window.py:221\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"Бездротове з'єднання не зашифроване\"\n\n#: lib/solaar/ui/pair_window.py:226\nmsgid \"Found a new device:\"\nmsgstr \"Знайдено новий пристрій:\"\n\n#: lib/solaar/ui/pair_window.py:247\nmsgid \"Pairing failed\"\nmsgstr \"Не вдалося створити пару\"\n\n#: lib/solaar/ui/pair_window.py:249\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"\"\n\"Переконайтеся, що ваш пристрій знаходиться в зоні досяжності та має \"\n\"достатній заряд батареї.\"\n\n#: lib/solaar/ui/pair_window.py:251\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"Було виявлено новий пристрій, але він не сумісний з цим приймачем.\"\n\n#: lib/solaar/ui/pair_window.py:253\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"Більше під'єднаних пристроїв, ніж може підтримувати приймач.\"\n\n#: lib/solaar/ui/pair_window.py:255\nmsgid \"No further details are available about the error.\"\nmsgstr \"Додаткові відомості про помилку відсутні.\"\n\n#: lib/solaar/ui/rule_actions.py:54\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Імітувати натискання, утримання або відпускання комбінації клавіш.\\n\"\n\"У Wayland потрібен дозвіл на запис до /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:60\nmsgid \"Add key\"\nmsgstr \"Додати клавішу\"\n\n#: lib/solaar/ui/rule_actions.py:63\nmsgid \"Click\"\nmsgstr \"Клік\"\n\n#: lib/solaar/ui/rule_actions.py:66\nmsgid \"Depress\"\nmsgstr \"Натиснути\"\n\n#: lib/solaar/ui/rule_actions.py:69\nmsgid \"Release\"\nmsgstr \"Відпустити\"\n\n#: lib/solaar/ui/rule_actions.py:153\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Імітувати прокручування миші.\\n\"\n\"У Wayland потрібен дозвіл на запис до /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:211\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"Імітувати клік миші.\\n\"\n\"У Wayland потрібен дозвіл на запис до /dev/uinput.\"\n\n#: lib/solaar/ui/rule_actions.py:216\nmsgid \"Button\"\nmsgstr \"Кнопка\"\n\n#: lib/solaar/ui/rule_actions.py:217\nmsgid \"Count and Action\"\nmsgstr \"Кількість та дія\"\n\n#: lib/solaar/ui/rule_actions.py:267\nmsgid \"Execute a command with arguments.\"\nmsgstr \"Виконати команду з аргументами.\"\n\n#: lib/solaar/ui/rule_actions.py:271\nmsgid \"Add argument\"\nmsgstr \"Додати аргумент\"\n\n#: lib/solaar/ui/rule_conditions.py:52\nmsgid \"\"\n\"X11 active process.\\n\"\n\"For use in X11 only.\"\nmsgstr \"\"\n\"Активний процес X11.\\n\"\n\"Використовувати лише в X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:82\nmsgid \"\"\n\"X11 mouse process.\\n\"\n\"For use in X11 only.\"\nmsgstr \"\"\n\"Процес миші X11.\\n\"\n\"Використовувати лише в X11.\"\n\n#: lib/solaar/ui/rule_conditions.py:99\nmsgid \"MouseProcess\"\nmsgstr \"ПроцесМиші\"\n\n#: lib/solaar/ui/rule_conditions.py:123\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"Назва функції сповіщення, що запускає обробку правила.\"\n\n#: lib/solaar/ui/rule_conditions.py:169\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"Номер звіту сповіщення, що запускає обробку правила.\"\n\n#: lib/solaar/ui/rule_conditions.py:201\nmsgid \"\"\n\"Active keyboard modifiers.\\n\"\n\"Not always available in Wayland.\"\nmsgstr \"\"\n\"Активні модифікатори клавіатури.\\n\"\n\"Не завжди доступні у Wayland.\"\n\n#: lib/solaar/ui/rule_conditions.py:241\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Перенаправлена клавіша або кнопка натиснута чи відпущена.\\n\"\n\"Використовуйте налаштування 'Перенаправлення клавіш/кнопок' та \"\n\"'Перенаправити G-клавіші' для перенаправлення.\"\n\n#: lib/solaar/ui/rule_conditions.py:250\nmsgid \"Key down\"\nmsgstr \"Клавішу натиснуто\"\n\n#: lib/solaar/ui/rule_conditions.py:253\nmsgid \"Key up\"\nmsgstr \"Клавішу відпущено\"\n\n#: lib/solaar/ui/rule_conditions.py:293\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"Перенаправлена клавіша або кнопка зараз натиснута.\\n\"\n\"Використовуйте налаштування 'Перенаправлення клавіш/кнопок' та \"\n\"'Перенаправити G-клавіші' для перенаправлення.\"\n\n#: lib/solaar/ui/rule_conditions.py:331\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"Перевірка умови для сповіщення, що запускає обробку правила.\"\n\n#: lib/solaar/ui/rule_conditions.py:335\nmsgid \"Parameter\"\nmsgstr \"Параметр\"\n\n#: lib/solaar/ui/rule_conditions.py:408\nmsgid \"begin (inclusive)\"\nmsgstr \"початок (включно)\"\n\n#: lib/solaar/ui/rule_conditions.py:409\nmsgid \"end (exclusive)\"\nmsgstr \"кінець (виключно)\"\n\n#: lib/solaar/ui/rule_conditions.py:417\nmsgid \"range\"\nmsgstr \"діапазон\"\n\n#: lib/solaar/ui/rule_conditions.py:420\nmsgid \"minimum\"\nmsgstr \"мінімум\"\n\n#: lib/solaar/ui/rule_conditions.py:421\nmsgid \"maximum\"\nmsgstr \"максимум\"\n\n#: lib/solaar/ui/rule_conditions.py:423\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"байти від %(0)d до %(1)d, в діапазоні від %(2)d до %(3)d\"\n\n#: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427\nmsgid \"mask\"\nmsgstr \"маска\"\n\n#: lib/solaar/ui/rule_conditions.py:428\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"байти від %(0)d до %(1)d, маска %(2)d\"\n\n#: lib/solaar/ui/rule_conditions.py:437\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"\"\n\"Бітовий або діапазонний тест байтів у повідомленні-сповіщенні, що запускає \"\n\"обробку правила.\"\n\n#: lib/solaar/ui/rule_conditions.py:447\nmsgid \"type\"\nmsgstr \"тип\"\n\n#: lib/solaar/ui/rule_conditions.py:535\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"\"\n\"Жест миші з необов'язковою кнопкою-ініціатором, за якою слідують нуль або \"\n\"більше рухів миші.\"\n\n#: lib/solaar/ui/rule_conditions.py:541\nmsgid \"Add movement\"\nmsgstr \"Додати рух\"\n\n#: lib/solaar/ui/tray.py:55\nmsgid \"No supported device found\"\nmsgstr \"Не знайдено підтримуваних пристроїв\"\n\n#: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328\n#, python-format\nmsgid \"About %s\"\nmsgstr \"Про %s\"\n\n#: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"Вийти з %s\"\n\n#: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281\nmsgid \"no receiver\"\nmsgstr \"немає приймача\"\n\n#: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299\n#: lib/solaar/ui/window.py:728\nmsgid \"offline\"\nmsgstr \"офлайн\"\n\n#: lib/solaar/ui/tray.py:297\nmsgid \"no status\"\nmsgstr \"немає статусу\"\n\n#: lib/solaar/ui/window.py:110\nmsgid \"Scanning\"\nmsgstr \"Сканування\"\n\n#: lib/solaar/ui/window.py:141\nmsgid \"Battery\"\nmsgstr \"Батарея\"\n\n#: lib/solaar/ui/window.py:144\nmsgid \"Wireless Link\"\nmsgstr \"Бездротове з'єднання\"\n\n#: lib/solaar/ui/window.py:148\nmsgid \"Lighting\"\nmsgstr \"Підсвічування\"\n\n#: lib/solaar/ui/window.py:182\nmsgid \"Show Technical Details\"\nmsgstr \"Показати технічні деталі\"\n\n#: lib/solaar/ui/window.py:198\nmsgid \"Pair new device\"\nmsgstr \"Створити пару з новим пристроєм\"\n\n#: lib/solaar/ui/window.py:216\nmsgid \"Select a device\"\nmsgstr \"Виберіть пристрій\"\n\n#: lib/solaar/ui/window.py:331\nmsgid \"Rule Editor\"\nmsgstr \"Редактор правил\"\n\n#: lib/solaar/ui/window.py:522\nmsgid \"Path\"\nmsgstr \"Шлях\"\n\n#: lib/solaar/ui/window.py:524\nmsgid \"USB ID\"\nmsgstr \"USB ID\"\n\n#: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529\n#: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546\nmsgid \"Serial\"\nmsgstr \"Серійний номер\"\n\n#: lib/solaar/ui/window.py:533\nmsgid \"Index\"\nmsgstr \"Індекс\"\n\n#: lib/solaar/ui/window.py:535\nmsgid \"Wireless PID\"\nmsgstr \"Бездротовий PID\"\n\n#: lib/solaar/ui/window.py:537\nmsgid \"Product ID\"\nmsgstr \"ID продукту\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Protocol\"\nmsgstr \"Протокол\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Unknown\"\nmsgstr \"Невідомо\"\n\n#: lib/solaar/ui/window.py:541\nmsgid \"Polling rate\"\nmsgstr \"Частота опитування\"\n\n#: lib/solaar/ui/window.py:548\nmsgid \"Unit ID\"\nmsgstr \"ID одиниці\"\n\n#: lib/solaar/ui/window.py:559\nmsgid \"none\"\nmsgstr \"немає\"\n\n#: lib/solaar/ui/window.py:560\nmsgid \"Notifications\"\nmsgstr \"Сповіщення\"\n\n#: lib/solaar/ui/window.py:604\nmsgid \"No device paired.\"\nmsgstr \"Немає під'єднаних пристроїв.\"\n\n#: lib/solaar/ui/window.py:613\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"До цього приймача можна під'єднати до %(max_count)s пристрою.\"\nmsgstr[1] \"До цього приймача можна під'єднати до %(max_count)s пристроїв.\"\nmsgstr[2] \"До цього приймача можна під'єднати до %(max_count)s пристроїв.\"\n\n#: lib/solaar/ui/window.py:620\nmsgid \"Only one device can be paired to this receiver.\"\nmsgstr \"До цього приймача можна під'єднати лише один пристрій.\"\n\n#: lib/solaar/ui/window.py:624\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"Цей приймач має ще %d спробу створення пари.\"\nmsgstr[1] \"Цей приймач має ще %d спроби створення пари.\"\nmsgstr[2] \"Цей приймач має ще %d спроб створення пари.\"\n\n#: lib/solaar/ui/window.py:681\nmsgid \"Battery Voltage\"\nmsgstr \"Напруга батареї\"\n\n#: lib/solaar/ui/window.py:683\nmsgid \"Voltage reported by battery\"\nmsgstr \"Напруга, що повідомляється батареєю\"\n\n#: lib/solaar/ui/window.py:685\nmsgid \"Battery Level\"\nmsgstr \"Рівень заряду батареї\"\n\n#: lib/solaar/ui/window.py:687\nmsgid \"Approximate level reported by battery\"\nmsgstr \"Приблизний рівень, що повідомляється батареєю\"\n\n#: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696\nmsgid \"next reported \"\nmsgstr \"наступний повідомлений \"\n\n#: lib/solaar/ui/window.py:697\nmsgid \" and next level to be reported.\"\nmsgstr \" та наступний рівень, що буде повідомлено.\"\n\n#: lib/solaar/ui/window.py:702\nmsgid \"last known\"\nmsgstr \"останній відомий\"\n\n#: lib/solaar/ui/window.py:713\nmsgid \"encrypted\"\nmsgstr \"зашифровано\"\n\n#: lib/solaar/ui/window.py:715\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"Бездротове з'єднання між цим пристроєм та його приймачем зашифроване.\"\n\n#: lib/solaar/ui/window.py:717\nmsgid \"not encrypted\"\nmsgstr \"не зашифровано\"\n\n#: lib/solaar/ui/window.py:721\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"Бездротове з'єднання між цим пристроєм та його приймачем не зашифроване.\\n\"\n\"Це проблема безпеки для вказівних пристроїв та серйозна проблема безпеки для \"\n\"пристроїв введення тексту.\"\n\n#: lib/solaar/ui/window.py:737\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d люкс\"\n"
  },
  {
    "path": "po/zh_CN.po",
    "content": "# Chinese translations for solaar package\n# Copyright (C) 2014 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2014.\n# ZH <zhanghan@gmx.cn>, 2014.\n# Rongrong <i@rong.moe>, 2022.\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 1.1.13\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-07-01 13:49+0800\\n\"\n\"PO-Revision-Date: 2024-07-01 16:23+0800\\n\"\n\"Last-Translator: iskandarma <iskandarma@gmail.com>\\n\"\n\"Language-Team: none\\n\"\n\"Language: zh_CN\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"X-Language: zh_CN\\n\"\n\"X-Source-Language: C\\n\"\n\"X-Generator: Poedit 3.4.3\\n\"\n\n#: lib/logitech_receiver/base_usb.py:45\nmsgid \"Bolt Receiver\"\nmsgstr \"Bolt 接收器\"\n\n#: lib/logitech_receiver/base_usb.py:57\nmsgid \"Unifying Receiver\"\nmsgstr \"优联接收器\"\n\n#: lib/logitech_receiver/base_usb.py:68 lib/logitech_receiver/base_usb.py:80\n#: lib/logitech_receiver/base_usb.py:93 lib/logitech_receiver/base_usb.py:106\n#: lib/logitech_receiver/base_usb.py:119\nmsgid \"Nano Receiver\"\nmsgstr \"微型接收器\"\n\n#: lib/logitech_receiver/base_usb.py:131\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Lightspeed 接收器\"\n\n#: lib/logitech_receiver/base_usb.py:141\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"EX100 接收器 (27MHz)\"\n\n#: lib/logitech_receiver/common.py:610\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"电池: %(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:613\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"电池: %(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:921\n#: lib/logitech_receiver/settings_templates.py:283\nmsgid \"Disabled\"\nmsgstr \"禁用\"\n\n#: lib/logitech_receiver/hidpp20.py:922\nmsgid \"Static\"\nmsgstr \"静态\"\n\n#: lib/logitech_receiver/hidpp20.py:923\nmsgid \"Pulse\"\nmsgstr \"脉冲\"\n\n#: lib/logitech_receiver/hidpp20.py:924\nmsgid \"Cycle\"\nmsgstr \"循环\"\n\n#: lib/logitech_receiver/hidpp20.py:925\nmsgid \"Boot\"\nmsgstr \"启动\"\n\n#: lib/logitech_receiver/hidpp20.py:926\nmsgid \"Demo\"\nmsgstr \"演示\"\n\n#: lib/logitech_receiver/hidpp20.py:927\nmsgid \"Breathe\"\nmsgstr \"呼吸\"\n\n#: lib/logitech_receiver/hidpp20.py:928\nmsgid \"Ripple\"\nmsgstr \"涟漪\"\n\n#: lib/logitech_receiver/hidpp20.py:929\nmsgid \"Decomposition\"\nmsgstr \"分解\"\n\n#: lib/logitech_receiver/hidpp20.py:930\nmsgid \"Signature1\"\nmsgstr \"签名1\"\n\n#: lib/logitech_receiver/hidpp20.py:931\nmsgid \"Signature2\"\nmsgstr \"签名2\"\n\n#: lib/logitech_receiver/hidpp20.py:932\nmsgid \"CycleS\"\nmsgstr \"饱和度循环\"\n\n#: lib/logitech_receiver/hidpp20.py:996\nmsgid \"Unknown Location\"\nmsgstr \"未知位置\"\n\n#: lib/logitech_receiver/hidpp20.py:997\nmsgid \"Primary\"\nmsgstr \"主要\"\n\n#: lib/logitech_receiver/hidpp20.py:998\nmsgid \"Logo\"\nmsgstr \"标志\"\n\n#: lib/logitech_receiver/hidpp20.py:999\nmsgid \"Left Side\"\nmsgstr \"左侧\"\n\n#: lib/logitech_receiver/hidpp20.py:1000\nmsgid \"Right Side\"\nmsgstr \"右侧\"\n\n#: lib/logitech_receiver/hidpp20.py:1001\nmsgid \"Combined\"\nmsgstr \"合并\"\n\n#: lib/logitech_receiver/hidpp20.py:1002\nmsgid \"Primary 1\"\nmsgstr \"主要 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1003\nmsgid \"Primary 2\"\nmsgstr \"主要 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1004\nmsgid \"Primary 3\"\nmsgstr \"主要 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1005\nmsgid \"Primary 4\"\nmsgstr \"主要 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1006\nmsgid \"Primary 5\"\nmsgstr \"主要 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1007\nmsgid \"Primary 6\"\nmsgstr \"主要6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"空\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"极低\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"低\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"平均\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"良好\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"全满\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"放电中\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"充电中\"\n\n#: lib/logitech_receiver/i18n.py:37\nmsgid \"charging\"\nmsgstr \"正充电\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"未在充电\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"接近全满\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"已充满\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"慢速充电\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"invalid battery\"\nmsgstr \"电池无效\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"温度异常\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"异常\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"标准\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"快速\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"慢速\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"设备超时\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"不支持的设备\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"设备数量太多\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"序列超时\"\n\n#: lib/logitech_receiver/i18n.py:54\nmsgid \"Firmware\"\nmsgstr \"固件\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"启动器\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"硬件\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"其他\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"左键\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"右键\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"中键\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"返回键\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"前进键\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"鼠标手势按钮\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"SmartShift\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"DPI 切换\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"滚轮向左倾斜\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"滚轮向右倾斜\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"左击\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"右击\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"鼠标中键\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"鼠标返回键\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"鼠标前进键\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"手势按钮导航\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"鼠标向左滚动键\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"鼠标向右滚动键\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"按下\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"释放\"\n\n#: lib/logitech_receiver/notifications.py:64\n#: lib/logitech_receiver/notifications.py:116\nmsgid \"pairing lock is closed\"\nmsgstr \"配对锁已关闭\"\n\n#: lib/logitech_receiver/notifications.py:64\n#: lib/logitech_receiver/notifications.py:116\nmsgid \"pairing lock is open\"\nmsgstr \"配对锁已打开\"\n\n#: lib/logitech_receiver/notifications.py:81\nmsgid \"discovery lock is closed\"\nmsgstr \"发现锁已关闭\"\n\n#: lib/logitech_receiver/notifications.py:81\nmsgid \"discovery lock is open\"\nmsgstr \"发现锁已打开\"\n\n#: lib/logitech_receiver/notifications.py:210 lib/solaar/listener.py:238\nmsgid \"connected\"\nmsgstr \"已连接\"\n\n#: lib/logitech_receiver/notifications.py:210 lib/solaar/listener.py:238\nmsgid \"disconnected\"\nmsgstr \"已断开\"\n\n#: lib/logitech_receiver/notifications.py:236\nmsgid \"unpaired\"\nmsgstr \"未配对\"\n\n#: lib/logitech_receiver/notifications.py:283\nmsgid \"powered on\"\nmsgstr \"已上电\"\n\n#: lib/logitech_receiver/receiver.py:371\nmsgid \"No paired devices.\"\nmsgstr \"无已配对设备。\"\n\n#: lib/logitech_receiver/receiver.py:373 lib/solaar/ui/window.py:604\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s 个已配对设备。\"\n\n#: lib/logitech_receiver/settings.py:611\nmsgid \"register\"\nmsgstr \"注册\"\n\n#: lib/logitech_receiver/settings.py:625 lib/logitech_receiver/settings.py:651\nmsgid \"feature\"\nmsgstr \"特性\"\n\n#: lib/logitech_receiver/settings_templates.py:122\nmsgid \"Swap Fx function\"\nmsgstr \"互换 Fx 键功能\"\n\n#: lib/logitech_receiver/settings_templates.py:125\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"若开启，F1 到 F12 键会激活特殊功能，\\n\"\n\"使用标准功能请同时按住 FN 键。\"\n\n#: lib/logitech_receiver/settings_templates.py:130\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"若关闭，F1 到 F12 键会激活标准功能，\\n\"\n\"使用特殊功能请同时按住 FN 键。\"\n\n#: lib/logitech_receiver/settings_templates.py:138\nmsgid \"Hand Detection\"\nmsgstr \"手掌识别\"\n\n#: lib/logitech_receiver/settings_templates.py:139\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"手掌置于键盘上方时开启照明。\"\n\n#: lib/logitech_receiver/settings_templates.py:146\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"滚轮平滑滚动\"\n\n#: lib/logitech_receiver/settings_templates.py:147\n#: lib/logitech_receiver/settings_templates.py:394\n#: lib/logitech_receiver/settings_templates.py:423\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"滚轮高分辨率滚动模式。\"\n\n#: lib/logitech_receiver/settings_templates.py:154\nmsgid \"Side Scrolling\"\nmsgstr \"侧向滚轮\"\n\n#: lib/logitech_receiver/settings_templates.py:156\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"若禁用，按下滚轮侧边将发送自定义按钮事件\\n\"\n\"而不是标准侧向滚动事件。\"\n\n#: lib/logitech_receiver/settings_templates.py:166\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"灵敏度 (DPI - 旧款鼠标)\"\n\n#: lib/logitech_receiver/settings_templates.py:167\n#: lib/logitech_receiver/settings_templates.py:955\n#: lib/logitech_receiver/settings_templates.py:983\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"鼠标移动灵敏度\"\n\n#: lib/logitech_receiver/settings_templates.py:240\nmsgid \"Backlight Timed\"\nmsgstr \"定时背光\"\n\n#: lib/logitech_receiver/settings_templates.py:241\n#: lib/logitech_receiver/settings_templates.py:381\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"为键盘设置背光时间。\"\n\n#: lib/logitech_receiver/settings_templates.py:252\nmsgid \"Backlight\"\nmsgstr \"背光\"\n\n#: lib/logitech_receiver/settings_templates.py:253\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"键盘亮度等级。仅在手动模式下可用\"\n\n#: lib/logitech_receiver/settings_templates.py:285\nmsgid \"Automatic\"\nmsgstr \"自动\"\n\n#: lib/logitech_receiver/settings_templates.py:287\nmsgid \"Manual\"\nmsgstr \"手动\"\n\n#: lib/logitech_receiver/settings_templates.py:289\nmsgid \"Enabled\"\nmsgstr \"已启用\"\n\n#: lib/logitech_receiver/settings_templates.py:295\nmsgid \"Backlight Level\"\nmsgstr \"背光等级\"\n\n#: lib/logitech_receiver/settings_templates.py:296\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"手动模式下的键盘亮度等级\"\n\n#: lib/logitech_receiver/settings_templates.py:353\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"手离开键盘后背光关闭的延迟\"\n\n#: lib/logitech_receiver/settings_templates.py:354\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"手离开键盘后，背光渐灭的延迟秒数\"\n\n#: lib/logitech_receiver/settings_templates.py:362\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"手靠近键盘后背光亮起的延迟\"\n\n#: lib/logitech_receiver/settings_templates.py:363\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"手靠近键盘后，背光亮起的延迟秒数\"\n\n#: lib/logitech_receiver/settings_templates.py:371\nmsgid \"Backlight Delay Powered\"\nmsgstr \"外接电源时的背光延迟\"\n\n#: lib/logitech_receiver/settings_templates.py:372\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"外接电源时背光渐灭的延迟秒数\"\n\n#: lib/logitech_receiver/settings_templates.py:380\nmsgid \"Backlight (Seconds)\"\nmsgstr \"背光（秒）\"\n\n#: lib/logitech_receiver/settings_templates.py:392\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"滚轮高分辨率\"\n\n#: lib/logitech_receiver/settings_templates.py:396\n#: lib/logitech_receiver/settings_templates.py:425\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"如果滚动异常地快或慢，请设置为忽略\"\n\n#: lib/logitech_receiver/settings_templates.py:403\n#: lib/logitech_receiver/settings_templates.py:434\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"滚轮重定义\"\n\n#: lib/logitech_receiver/settings_templates.py:405\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"使滚轮发送 LOWRES_WHEEL (低精度滚轮) HID++ 报告（如有Solaar规则，则被触发）\"\n\n#: lib/logitech_receiver/settings_templates.py:412\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"滚轮方向\"\n\n#: lib/logitech_receiver/settings_templates.py:413\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"反转滚轮的垂直滚动方向。\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"滚轮分辨率\"\n\n#: lib/logitech_receiver/settings_templates.py:436\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"使滚轮发送 HIRES_WHEEL (高精度滚轮) HID++ 报告（如有Solaar规则，则被触发）\"\n\n#: lib/logitech_receiver/settings_templates.py:445\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"灵敏度 (指针速度)\"\n\n#: lib/logitech_receiver/settings_templates.py:446\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"鼠标速度倍率 (256 为常规倍率)。\"\n\n#: lib/logitech_receiver/settings_templates.py:456\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"拇指滚轮重定义\"\n\n#: lib/logitech_receiver/settings_templates.py:458\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"使拇指滚轮发送 THUMB_WHEEL (拇指滚轮) HID++ 报告（如有Solaar规则，则被触发）\"\n\n#: lib/logitech_receiver/settings_templates.py:467\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"拇指滚轮方向\"\n\n#: lib/logitech_receiver/settings_templates.py:468\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"反转拇指滚轮的滚动方向。\"\n\n#: lib/logitech_receiver/settings_templates.py:488\nmsgid \"Onboard Profiles\"\nmsgstr \"板载预设\"\n\n#: lib/logitech_receiver/settings_templates.py:489\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"启用板载预设，用于控制回报率、灵敏度及按键功能\"\n\n#: lib/logitech_receiver/settings_templates.py:533\n#: lib/logitech_receiver/settings_templates.py:566\nmsgid \"Report Rate\"\nmsgstr \"回报率\"\n\n#: lib/logitech_receiver/settings_templates.py:535\n#: lib/logitech_receiver/settings_templates.py:568\nmsgid \"Frequency of device movement reports\"\nmsgstr \"设备移动事件的回报频率\"\n\n#: lib/logitech_receiver/settings_templates.py:535\n#: lib/logitech_receiver/settings_templates.py:568\n#: lib/logitech_receiver/settings_templates.py:983\n#: lib/logitech_receiver/settings_templates.py:1357\n#: lib/logitech_receiver/settings_templates.py:1388\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"可能需要禁用板载预设才能生效。\"\n\n#: lib/logitech_receiver/settings_templates.py:596\nmsgid \"Divert crown events\"\nmsgstr \"重定义旋钮事件\"\n\n#: lib/logitech_receiver/settings_templates.py:597\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"使旋钮发送 CROWN (旋钮) HID++ 报告（如有Solaar规则，则被触发）\"\n\n#: lib/logitech_receiver/settings_templates.py:605\nmsgid \"Crown smooth scroll\"\nmsgstr \"旋钮平滑旋动\"\n\n#: lib/logitech_receiver/settings_templates.py:606\nmsgid \"Set crown smooth scroll\"\nmsgstr \"设置旋钮的平滑旋动\"\n\n#: lib/logitech_receiver/settings_templates.py:614\nmsgid \"Divert G and M Keys\"\nmsgstr \"转换G键及M键\"\n\n#: lib/logitech_receiver/settings_templates.py:615\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"G键及M键将发送 HID++ 报告（如有Solaar规则，则被触发）\"\n\n#: lib/logitech_receiver/settings_templates.py:629\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"滚轮棘轮\"\n\n#: lib/logitech_receiver/settings_templates.py:630\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"在滚速响应式棘轮及平滑滚动模式间切换\"\n\n#: lib/logitech_receiver/settings_templates.py:632\nmsgid \"Freespinning\"\nmsgstr \"平滑滚动\"\n\n#: lib/logitech_receiver/settings_templates.py:632\nmsgid \"Ratcheted\"\nmsgstr \"棘轮式\"\n\n#: lib/logitech_receiver/settings_templates.py:639\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"滚轮棘轮速度\"\n\n#: lib/logitech_receiver/settings_templates.py:641\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"根据鼠标滚轮速度，在棘轮模式和平滑滚动模式间切换。\\n\"\n\"50时将始终处于棘轮模式。\"\n\n#: lib/logitech_receiver/settings_templates.py:690\nmsgid \"Key/Button Actions\"\nmsgstr \"按键/按钮行为\"\n\n#: lib/logitech_receiver/settings_templates.py:692\nmsgid \"Change the action for the key or button.\"\nmsgstr \"更改按键或按钮的行为。\"\n\n#: lib/logitech_receiver/settings_templates.py:694\nmsgid \"Overridden by diversion.\"\nmsgstr \"会被重定义配置覆盖。\"\n\n#: lib/logitech_receiver/settings_templates.py:696\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"更改关键行为 (如鼠标左键) 可能会导致无法操作。\"\n\n#: lib/logitech_receiver/settings_templates.py:862\nmsgid \"Key/Button Diversion\"\nmsgstr \"按键/按钮重定义\"\n\n#: lib/logitech_receiver/settings_templates.py:863\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse \"\n\"Gestures or Sliding DPI\"\nmsgstr \"使按键或按钮发送 HID++  (重定义)报告 、触发鼠标手势或滑动调节 DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:866\n#: lib/logitech_receiver/settings_templates.py:867\n#: lib/logitech_receiver/settings_templates.py:868\nmsgid \"Diverted\"\nmsgstr \"重定义\"\n\n#: lib/logitech_receiver/settings_templates.py:866\n#: lib/logitech_receiver/settings_templates.py:867\nmsgid \"Mouse Gestures\"\nmsgstr \"鼠标手势\"\n\n#: lib/logitech_receiver/settings_templates.py:866\n#: lib/logitech_receiver/settings_templates.py:867\n#: lib/logitech_receiver/settings_templates.py:868\nmsgid \"Regular\"\nmsgstr \"常规\"\n\n#: lib/logitech_receiver/settings_templates.py:866\nmsgid \"Sliding DPI\"\nmsgstr \"滑动调节 DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:954\n#: lib/logitech_receiver/settings_templates.py:982\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"灵敏度 (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:1059\nmsgid \"Sensitivity Switching\"\nmsgstr \"灵敏度切换\"\n\n#: lib/logitech_receiver/settings_templates.py:1061\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key \"\n\"or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\"切换当前灵敏度，并记忆按键或按钮按下时的灵敏度。\\n\"\n\"如果没有已记忆的灵敏度，就只会记忆当前灵敏度\"\n\n#: lib/logitech_receiver/settings_templates.py:1065\nmsgid \"Off\"\nmsgstr \"关\"\n\n#: lib/logitech_receiver/settings_templates.py:1096\nmsgid \"Disable keys\"\nmsgstr \"禁用按键\"\n\n#: lib/logitech_receiver/settings_templates.py:1097\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"禁用特定的键盘按键。\"\n\n#: lib/logitech_receiver/settings_templates.py:1100\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"禁用 %s 按键。\"\n\n#: lib/logitech_receiver/settings_templates.py:1113\n#: lib/logitech_receiver/settings_templates.py:1170\nmsgid \"Set OS\"\nmsgstr \"设置操作系统\"\n\n#: lib/logitech_receiver/settings_templates.py:1114\n#: lib/logitech_receiver/settings_templates.py:1171\nmsgid \"Change keys to match OS.\"\nmsgstr \"改变键位以匹配操作系统。\"\n\n#: lib/logitech_receiver/settings_templates.py:1183\nmsgid \"Change Host\"\nmsgstr \"切换主机\"\n\n#: lib/logitech_receiver/settings_templates.py:1184\nmsgid \"Switch connection to a different host\"\nmsgstr \"切换连接的主机\"\n\n#: lib/logitech_receiver/settings_templates.py:1208\nmsgid \"Performs a left click.\"\nmsgstr \"单击鼠标左键。\"\n\n#: lib/logitech_receiver/settings_templates.py:1208\nmsgid \"Single tap\"\nmsgstr \"单指点击\"\n\n#: lib/logitech_receiver/settings_templates.py:1209\nmsgid \"Performs a right click.\"\nmsgstr \"单击鼠标右键。\"\n\n#: lib/logitech_receiver/settings_templates.py:1209\nmsgid \"Single tap with two fingers\"\nmsgstr \"双指点击\"\n\n#: lib/logitech_receiver/settings_templates.py:1210\nmsgid \"Single tap with three fingers\"\nmsgstr \"三指点击\"\n\n#: lib/logitech_receiver/settings_templates.py:1214\nmsgid \"Double tap\"\nmsgstr \"单指双击\"\n\n#: lib/logitech_receiver/settings_templates.py:1214\nmsgid \"Performs a double click.\"\nmsgstr \"双击。\"\n\n#: lib/logitech_receiver/settings_templates.py:1215\nmsgid \"Double tap with two fingers\"\nmsgstr \"双指双击\"\n\n#: lib/logitech_receiver/settings_templates.py:1216\nmsgid \"Double tap with three fingers\"\nmsgstr \"三指双击\"\n\n#: lib/logitech_receiver/settings_templates.py:1219\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"单指双击后移动手指来拖动项目。\"\n\n#: lib/logitech_receiver/settings_templates.py:1219\nmsgid \"Tap and drag\"\nmsgstr \"触摸并拖动\"\n\n#: lib/logitech_receiver/settings_templates.py:1221\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"双指触摸并拖动\"\n\n#: lib/logitech_receiver/settings_templates.py:1222\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"多指双击后移动手指来拖动项目。\"\n\n#: lib/logitech_receiver/settings_templates.py:1224\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"三指触摸并拖动\"\n\n#: lib/logitech_receiver/settings_templates.py:1227\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"禁用触摸和边缘手势\"\n\n#: lib/logitech_receiver/settings_templates.py:1228\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"禁用触摸和边缘手势 (等价于按下 Fn+左键单击)。\"\n\n#: lib/logitech_receiver/settings_templates.py:1230\nmsgid \"Scroll with one finger\"\nmsgstr \"单指滚动\"\n\n#: lib/logitech_receiver/settings_templates.py:1230\n#: lib/logitech_receiver/settings_templates.py:1231\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid \"Scrolls.\"\nmsgstr \"滚动。\"\n\n#: lib/logitech_receiver/settings_templates.py:1231\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid \"Scroll with two fingers\"\nmsgstr \"双指滚动\"\n\n#: lib/logitech_receiver/settings_templates.py:1232\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"双指水平滚动\"\n\n#: lib/logitech_receiver/settings_templates.py:1232\nmsgid \"Scrolls horizontally.\"\nmsgstr \"水平滚动。\"\n\n#: lib/logitech_receiver/settings_templates.py:1233\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"双指垂直滚动\"\n\n#: lib/logitech_receiver/settings_templates.py:1233\nmsgid \"Scrolls vertically.\"\nmsgstr \"垂直滚动。\"\n\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"反转滚动方向。\"\n\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid \"Natural scrolling\"\nmsgstr \"自然滚动\"\n\n#: lib/logitech_receiver/settings_templates.py:1236\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"启用拇指滚轮。\"\n\n#: lib/logitech_receiver/settings_templates.py:1236\nmsgid \"Thumbwheel\"\nmsgstr \"拇指滚轮\"\n\n#: lib/logitech_receiver/settings_templates.py:1247\n#: lib/logitech_receiver/settings_templates.py:1251\nmsgid \"Swipe from the top edge\"\nmsgstr \"从顶部边缘滑动\"\n\n#: lib/logitech_receiver/settings_templates.py:1248\nmsgid \"Swipe from the left edge\"\nmsgstr \"从左侧边缘滑动\"\n\n#: lib/logitech_receiver/settings_templates.py:1249\nmsgid \"Swipe from the right edge\"\nmsgstr \"从右侧边缘滑动\"\n\n#: lib/logitech_receiver/settings_templates.py:1250\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"从底部边缘滑动\"\n\n#: lib/logitech_receiver/settings_templates.py:1252\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"从左侧边缘双指滑动\"\n\n#: lib/logitech_receiver/settings_templates.py:1253\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"从右侧边缘双指滑动\"\n\n#: lib/logitech_receiver/settings_templates.py:1254\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"从底部边缘双指滑动\"\n\n#: lib/logitech_receiver/settings_templates.py:1255\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"从顶部边缘双指滑动\"\n\n#: lib/logitech_receiver/settings_templates.py:1256\n#: lib/logitech_receiver/settings_templates.py:1260\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"通过捏合手指缩小；伸展手指以放大。\"\n\n#: lib/logitech_receiver/settings_templates.py:1256\nmsgid \"Zoom with two fingers.\"\nmsgstr \"双指缩放。\"\n\n#: lib/logitech_receiver/settings_templates.py:1257\nmsgid \"Pinch to zoom out.\"\nmsgstr \"捏合手指以缩小。\"\n\n#: lib/logitech_receiver/settings_templates.py:1258\nmsgid \"Spread to zoom in.\"\nmsgstr \"伸展手指以放大。\"\n\n#: lib/logitech_receiver/settings_templates.py:1259\nmsgid \"Zoom with three fingers.\"\nmsgstr \"三指缩放。\"\n\n#: lib/logitech_receiver/settings_templates.py:1260\nmsgid \"Zoom with two fingers\"\nmsgstr \"双指缩放\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Pixel zone\"\nmsgstr \"像素区\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid \"Ratio zone\"\nmsgstr \"比例区\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Scale factor\"\nmsgstr \"缩放比例\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Sets the cursor speed.\"\nmsgstr \"设置指针速度。\"\n\n#: lib/logitech_receiver/settings_templates.py:1284\nmsgid \"Left\"\nmsgstr \"左侧\"\n\n#: lib/logitech_receiver/settings_templates.py:1284\nmsgid \"Left-most coordinate.\"\nmsgstr \"最左坐标。\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid \"Bottom\"\nmsgstr \"底部\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid \"Bottom coordinate.\"\nmsgstr \"底部坐标。\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid \"Width\"\nmsgstr \"宽度\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid \"Width.\"\nmsgstr \"宽度。\"\n\n#: lib/logitech_receiver/settings_templates.py:1287\nmsgid \"Height\"\nmsgstr \"高度\"\n\n#: lib/logitech_receiver/settings_templates.py:1287\nmsgid \"Height.\"\nmsgstr \"高度。\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid \"Cursor speed.\"\nmsgstr \"指针速度。\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid \"Scale\"\nmsgstr \"比例\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\nmsgid \"Gestures\"\nmsgstr \"手势\"\n\n#: lib/logitech_receiver/settings_templates.py:1295\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"调整鼠标或触摸板的行为。\"\n\n#: lib/logitech_receiver/settings_templates.py:1311\nmsgid \"Gestures Diversion\"\nmsgstr \"手势重定义\"\n\n#: lib/logitech_receiver/settings_templates.py:1312\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"重定义鼠标或触摸板手势。\"\n\n#: lib/logitech_receiver/settings_templates.py:1328\nmsgid \"Gesture params\"\nmsgstr \"手势参数\"\n\n#: lib/logitech_receiver/settings_templates.py:1329\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"更改鼠标或触摸板的数值参数。\"\n\n#: lib/logitech_receiver/settings_templates.py:1353\nmsgid \"M-Key LEDs\"\nmsgstr \"M 键 LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1355\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"控制 M 键的 LED。\"\n\n#: lib/logitech_receiver/settings_templates.py:1359\n#: lib/logitech_receiver/settings_templates.py:1390\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"可能需要开启 G 键重定义。\"\n\n#: lib/logitech_receiver/settings_templates.py:1365\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"点亮 %s 按键。\"\n\n#: lib/logitech_receiver/settings_templates.py:1384\nmsgid \"MR-Key LED\"\nmsgstr \"MR 键 LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1386\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"控制 MR 键的 LED。\"\n\n#: lib/logitech_receiver/settings_templates.py:1407\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"持久化按键/按钮映射\"\n\n#: lib/logitech_receiver/settings_templates.py:1409\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"永久更改按键或按钮的映射。\"\n\n#: lib/logitech_receiver/settings_templates.py:1411\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"更改重要的按键或按钮 (如鼠标左键) 可以导致系统无法使用。\"\n\n#: lib/logitech_receiver/settings_templates.py:1468\nmsgid \"Sidetone\"\nmsgstr \"侧音 (麦克风回馈)\"\n\n#: lib/logitech_receiver/settings_templates.py:1469\nmsgid \"Set sidetone level.\"\nmsgstr \"设置侧音水平。\"\n\n#: lib/logitech_receiver/settings_templates.py:1478\nmsgid \"Equalizer\"\nmsgstr \"均衡器\"\n\n#: lib/logitech_receiver/settings_templates.py:1479\nmsgid \"Set equalizer levels.\"\nmsgstr \"设置均衡器水平。\"\n\n#: lib/logitech_receiver/settings_templates.py:1501\nmsgid \"Hz\"\nmsgstr \"\"\n\n#: lib/logitech_receiver/settings_templates.py:1507\nmsgid \"Power Management\"\nmsgstr \"电源管理\"\n\n#: lib/logitech_receiver/settings_templates.py:1508\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"分钟后关机（0为不关机）\"\n\n#: lib/logitech_receiver/settings_templates.py:1519\nmsgid \"Brightness Control\"\nmsgstr \"亮度控制\"\n\n#: lib/logitech_receiver/settings_templates.py:1520\nmsgid \"Control overall brightness\"\nmsgstr \"全局亮度控制\"\n\n#: lib/logitech_receiver/settings_templates.py:1563\n#: lib/logitech_receiver/settings_templates.py:1617\nmsgid \"LED Control\"\nmsgstr \"LED控制\"\n\n#: lib/logitech_receiver/settings_templates.py:1564\n#: lib/logitech_receiver/settings_templates.py:1618\nmsgid \"Switch control of LED zones between device and Solaar\"\nmsgstr \"在设备和Solaar间切换LED区域控制\"\n\n#: lib/logitech_receiver/settings_templates.py:1579\n#: lib/logitech_receiver/settings_templates.py:1628\nmsgid \"LED Zone Effects\"\nmsgstr \"LED区域效果\"\n\n#: lib/logitech_receiver/settings_templates.py:1580\n#: lib/logitech_receiver/settings_templates.py:1629\nmsgid \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr \"设置并启用LED控制到Solaar\"\n\n#: lib/logitech_receiver/settings_templates.py:1580\n#: lib/logitech_receiver/settings_templates.py:1629\nmsgid \"Set effect for LED Zone\"\nmsgstr \"设置LED区域效果\"\n\n#: lib/logitech_receiver/settings_templates.py:1583\nmsgid \"Speed\"\nmsgstr \"速度\"\n\n#: lib/logitech_receiver/settings_templates.py:1584\nmsgid \"Period\"\nmsgstr \"周期\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\nmsgid \"Intensity\"\nmsgstr \"强度\"\n\n#: lib/logitech_receiver/settings_templates.py:1586\nmsgid \"Ramp\"\nmsgstr \"渐变\"\n\n#: lib/logitech_receiver/settings_templates.py:1602\nmsgid \"LEDs\"\nmsgstr \"LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1639\nmsgid \"Per-key Lighting\"\nmsgstr \"按键独立灯光\"\n\n#: lib/logitech_receiver/settings_templates.py:1640\nmsgid \"Control per-key lighting.\"\nmsgstr \"设置按键独立灯光\"\n\n#: lib/solaar/ui/__init__.py:103\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"另一个 Solaar 进程正在运行，已唤醒窗口\"\n\n#: lib/solaar/ui/about.py:34\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"管理罗技接收器、\\n\"\n\"键盘、鼠标和平板电脑。\"\n\n#: lib/solaar/ui/about.py:43\nmsgid \"Additional Programming\"\nmsgstr \"协作研发\"\n\n#: lib/solaar/ui/about.py:44\nmsgid \"GUI design\"\nmsgstr \"界面设计\"\n\n#: lib/solaar/ui/about.py:46\nmsgid \"Testing\"\nmsgstr \"软件测试\"\n\n#: lib/solaar/ui/about.py:54\nmsgid \"Logitech documentation\"\nmsgstr \"罗技文档\"\n\n#: lib/solaar/ui/action.py:83 lib/solaar/ui/action.py:87\n#: lib/solaar/ui/window.py:189\nmsgid \"Unpair\"\nmsgstr \"取消配对\"\n\n#: lib/solaar/ui/action.py:86 lib/solaar/ui/diversion_rules.py:103\nmsgid \"Cancel\"\nmsgstr \"取消\"\n\n#: lib/solaar/ui/common.py:35\nmsgid \"Permissions error\"\nmsgstr \"权限错误\"\n\n#: lib/solaar/ui/common.py:37\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"发现罗技接收器或设备（%s），但无访问权限\"\n\n#: lib/solaar/ui/common.py:39\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"若您是刚安装Solaar，请插拔一下罗技接收器或设备\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Cannot connect to device error\"\nmsgstr \"错误: 无法连接到设备\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"已在 %s 上发现 1 个罗技接收器或设备，但连接时发生错误。\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"请尝试插拔设备，或关闭后重新打开设备\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Unpairing failed\"\nmsgstr \"取消配对失败\"\n\n#: lib/solaar/ui/common.py:51\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"取消 %{device} 到 %{receiver} 的配对失败。\"\n\n#: lib/solaar/ui/common.py:53\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"接收器出现错误，无详细信息。\"\n\n#: lib/solaar/ui/config_panel.py:228\nmsgid \"Complete - ENTER to change\"\nmsgstr \"完成 - 按下 ENTER 键以进行更改\"\n\n#: lib/solaar/ui/config_panel.py:228\nmsgid \"Incomplete\"\nmsgstr \"未完成\"\n\n#: lib/solaar/ui/config_panel.py:470 lib/solaar/ui/config_panel.py:522\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d 个值\"\n\n#: lib/solaar/ui/config_panel.py:603\nmsgid \"Changes allowed\"\nmsgstr \"允许更改\"\n\n#: lib/solaar/ui/config_panel.py:604\nmsgid \"No changes allowed\"\nmsgstr \"不允许更改\"\n\n#: lib/solaar/ui/config_panel.py:605\nmsgid \"Ignore this setting\"\nmsgstr \"忽略此设置\"\n\n#: lib/solaar/ui/config_panel.py:649\nmsgid \"Working\"\nmsgstr \"工作中\"\n\n#: lib/solaar/ui/config_panel.py:652\nmsgid \"Read/write operation failed.\"\nmsgstr \"读写操作失败。\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid \"Built-in rules\"\nmsgstr \"内置规则\"\n\n#: lib/solaar/ui/diversion_rules.py:65\nmsgid \"User-defined rules\"\nmsgstr \"自定义规则\"\n\n#: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1033\nmsgid \"Rule\"\nmsgstr \"规则\"\n\n#: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:545\n#: lib/solaar/ui/diversion_rules.py:672\nmsgid \"Sub-rule\"\nmsgstr \"子规则\"\n\n#: lib/solaar/ui/diversion_rules.py:70\nmsgid \"[empty]\"\nmsgstr \"[空]\"\n\n#: lib/solaar/ui/diversion_rules.py:94\nmsgid \"Make changes permanent?\"\nmsgstr \"永久应用更改？\"\n\n#: lib/solaar/ui/diversion_rules.py:99\nmsgid \"Yes\"\nmsgstr \"是\"\n\n#: lib/solaar/ui/diversion_rules.py:101\nmsgid \"No\"\nmsgstr \"否\"\n\n#: lib/solaar/ui/diversion_rules.py:106\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"如果选择否，改动会在 Solaar 关闭后丢失。\"\n\n#: lib/solaar/ui/diversion_rules.py:167\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Solaar 规则编辑器\"\n\n#: lib/solaar/ui/diversion_rules.py:260\nmsgid \"Save changes\"\nmsgstr \"保存更改\"\n\n#: lib/solaar/ui/diversion_rules.py:265\nmsgid \"Discard changes\"\nmsgstr \"放弃更改\"\n\n#: lib/solaar/ui/diversion_rules.py:404\nmsgid \"Insert here\"\nmsgstr \"插入\"\n\n#: lib/solaar/ui/diversion_rules.py:406\nmsgid \"Insert above\"\nmsgstr \"在上方插入\"\n\n#: lib/solaar/ui/diversion_rules.py:408\nmsgid \"Insert below\"\nmsgstr \"在下方插入\"\n\n#: lib/solaar/ui/diversion_rules.py:414\nmsgid \"Insert new rule here\"\nmsgstr \"新建规则\"\n\n#: lib/solaar/ui/diversion_rules.py:416\nmsgid \"Insert new rule above\"\nmsgstr \"在上方添加规则\"\n\n#: lib/solaar/ui/diversion_rules.py:418\nmsgid \"Insert new rule below\"\nmsgstr \"在下方添加规则\"\n\n#: lib/solaar/ui/diversion_rules.py:463\nmsgid \"Paste here\"\nmsgstr \"在此处粘贴\"\n\n#: lib/solaar/ui/diversion_rules.py:465\nmsgid \"Paste above\"\nmsgstr \"在上方粘贴\"\n\n#: lib/solaar/ui/diversion_rules.py:467\nmsgid \"Paste below\"\nmsgstr \"在下方粘贴\"\n\n#: lib/solaar/ui/diversion_rules.py:473\nmsgid \"Paste rule here\"\nmsgstr \"在此处粘贴规则\"\n\n#: lib/solaar/ui/diversion_rules.py:475\nmsgid \"Paste rule above\"\nmsgstr \"在上方粘贴规则\"\n\n#: lib/solaar/ui/diversion_rules.py:477\nmsgid \"Paste rule below\"\nmsgstr \"在下方粘贴规则\"\n\n#: lib/solaar/ui/diversion_rules.py:481\nmsgid \"Paste rule\"\nmsgstr \"粘贴规则\"\n\n#: lib/solaar/ui/diversion_rules.py:510\nmsgid \"Flatten\"\nmsgstr \"展平\"\n\n#: lib/solaar/ui/diversion_rules.py:543\nmsgid \"Insert\"\nmsgstr \"插入\"\n\n#: lib/solaar/ui/diversion_rules.py:546 lib/solaar/ui/diversion_rules.py:674\n#: lib/solaar/ui/diversion_rules.py:1065\nmsgid \"Or\"\nmsgstr \"或\"\n\n#: lib/solaar/ui/diversion_rules.py:547 lib/solaar/ui/diversion_rules.py:673\n#: lib/solaar/ui/diversion_rules.py:1051\nmsgid \"And\"\nmsgstr \"且\"\n\n#: lib/solaar/ui/diversion_rules.py:549\nmsgid \"Condition\"\nmsgstr \"条件\"\n\n#: lib/solaar/ui/diversion_rules.py:551 lib/solaar/ui/rule_conditions.py:146\nmsgid \"Feature\"\nmsgstr \"特性\"\n\n#: lib/solaar/ui/diversion_rules.py:552 lib/solaar/ui/rule_conditions.py:181\nmsgid \"Report\"\nmsgstr \"回报\"\n\n#: lib/solaar/ui/diversion_rules.py:553 lib/solaar/ui/rule_conditions.py:60\nmsgid \"Process\"\nmsgstr \"焦点所在进程\"\n\n#: lib/solaar/ui/diversion_rules.py:554\nmsgid \"Mouse process\"\nmsgstr \"光标所在进程\"\n\n#: lib/solaar/ui/diversion_rules.py:555 lib/solaar/ui/rule_conditions.py:218\nmsgid \"Modifiers\"\nmsgstr \"修饰键\"\n\n#: lib/solaar/ui/diversion_rules.py:556 lib/solaar/ui/rule_conditions.py:270\nmsgid \"Key\"\nmsgstr \"按键\"\n\n#: lib/solaar/ui/diversion_rules.py:557 lib/solaar/ui/rule_conditions.py:311\nmsgid \"KeyIsDown\"\nmsgstr \"按键已按下\"\n\n#: lib/solaar/ui/diversion_rules.py:558 lib/solaar/ui/diversion_rules.py:1359\nmsgid \"Active\"\nmsgstr \"活跃设备\"\n\n#: lib/solaar/ui/diversion_rules.py:559 lib/solaar/ui/diversion_rules.py:1316\n#: lib/solaar/ui/diversion_rules.py:1368 lib/solaar/ui/diversion_rules.py:1418\nmsgid \"Device\"\nmsgstr \"设备\"\n\n#: lib/solaar/ui/diversion_rules.py:560 lib/solaar/ui/diversion_rules.py:1394\nmsgid \"Host\"\nmsgstr \"主机\"\n\n#: lib/solaar/ui/diversion_rules.py:561 lib/solaar/ui/diversion_rules.py:1436\nmsgid \"Setting\"\nmsgstr \"设置\"\n\n#: lib/solaar/ui/diversion_rules.py:562 lib/solaar/ui/rule_conditions.py:326\n#: lib/solaar/ui/rule_conditions.py:375\nmsgid \"Test\"\nmsgstr \"测试\"\n\n#: lib/solaar/ui/diversion_rules.py:563 lib/solaar/ui/rule_conditions.py:500\nmsgid \"Test bytes\"\nmsgstr \"字节检测\"\n\n#: lib/solaar/ui/diversion_rules.py:564 lib/solaar/ui/rule_conditions.py:601\nmsgid \"Mouse Gesture\"\nmsgstr \"鼠标手势\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid \"Action\"\nmsgstr \"操作\"\n\n#: lib/solaar/ui/diversion_rules.py:570 lib/solaar/ui/rule_actions.py:132\nmsgid \"Key press\"\nmsgstr \"按下按键\"\n\n#: lib/solaar/ui/diversion_rules.py:571 lib/solaar/ui/rule_actions.py:183\nmsgid \"Mouse scroll\"\nmsgstr \"移动鼠标\"\n\n#: lib/solaar/ui/diversion_rules.py:572 lib/solaar/ui/rule_actions.py:244\nmsgid \"Mouse click\"\nmsgstr \"鼠标点击\"\n\n#: lib/solaar/ui/diversion_rules.py:573\nmsgid \"Set\"\nmsgstr \"更改设置\"\n\n#: lib/solaar/ui/diversion_rules.py:574 lib/solaar/ui/rule_actions.py:314\nmsgid \"Execute\"\nmsgstr \"执行程序\"\n\n#: lib/solaar/ui/diversion_rules.py:575 lib/solaar/ui/diversion_rules.py:1096\nmsgid \"Later\"\nmsgstr \"延迟\"\n\n#: lib/solaar/ui/diversion_rules.py:604\nmsgid \"Insert new rule\"\nmsgstr \"插入新规则\"\n\n#: lib/solaar/ui/diversion_rules.py:624 lib/solaar/ui/rule_actions.py:74\n#: lib/solaar/ui/rule_actions.py:273 lib/solaar/ui/rule_conditions.py:548\nmsgid \"Delete\"\nmsgstr \"删除\"\n\n#: lib/solaar/ui/diversion_rules.py:646\nmsgid \"Negate\"\nmsgstr \"取反\"\n\n#: lib/solaar/ui/diversion_rules.py:670\nmsgid \"Wrap with\"\nmsgstr \"以…包裹\"\n\n#: lib/solaar/ui/diversion_rules.py:692\nmsgid \"Cut\"\nmsgstr \"剪切\"\n\n#: lib/solaar/ui/diversion_rules.py:707\nmsgid \"Paste\"\nmsgstr \"粘贴\"\n\n#: lib/solaar/ui/diversion_rules.py:713\nmsgid \"Copy\"\nmsgstr \"复制\"\n\n#: lib/solaar/ui/diversion_rules.py:1014\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"此编辑器尚未支持所选的规则组件。\"\n\n#: lib/solaar/ui/diversion_rules.py:1076\nmsgid \"\"\n\"Number of seconds to delay.  Delay between 0 and 1 is done with higher \"\n\"precision.\"\nmsgstr \"延迟秒数。0到1之间的延迟将通过高精度实现\"\n\n#: lib/solaar/ui/diversion_rules.py:1114\nmsgid \"Not\"\nmsgstr \"非\"\n\n#: lib/solaar/ui/diversion_rules.py:1145\nmsgid \"Toggle\"\nmsgstr \"切换\"\n\n#: lib/solaar/ui/diversion_rules.py:1146\nmsgid \"True\"\nmsgstr \"真\"\n\n#: lib/solaar/ui/diversion_rules.py:1147\nmsgid \"False\"\nmsgstr \"假\"\n\n#: lib/solaar/ui/diversion_rules.py:1160\nmsgid \"Unsupported setting\"\nmsgstr \"不支持的设置\"\n\n#: lib/solaar/ui/diversion_rules.py:1322 lib/solaar/ui/diversion_rules.py:1342\n#: lib/solaar/ui/diversion_rules.py:1424 lib/solaar/ui/diversion_rules.py:1669\n#: lib/solaar/ui/diversion_rules.py:1687\nmsgid \"Originating device\"\nmsgstr \"源设备\"\n\n#: lib/solaar/ui/diversion_rules.py:1355\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"设备已激活，且可更改其设置。\"\n\n#: lib/solaar/ui/diversion_rules.py:1364\nmsgid \"Device that originated the current notification.\"\nmsgstr \"触发当前事件的设备\"\n\n#: lib/solaar/ui/diversion_rules.py:1377\nmsgid \"Name of host computer.\"\nmsgstr \"主机名\"\n\n#: lib/solaar/ui/diversion_rules.py:1445\nmsgid \"Value\"\nmsgstr \"值\"\n\n#: lib/solaar/ui/diversion_rules.py:1454\nmsgid \"Item\"\nmsgstr \"项目\"\n\n#: lib/solaar/ui/diversion_rules.py:1728\nmsgid \"Change setting on device\"\nmsgstr \"更改设备上保存的设置\"\n\n#: lib/solaar/ui/diversion_rules.py:1744\nmsgid \"Setting on device\"\nmsgstr \"设备上保存的设置\"\n\n#: lib/solaar/ui/notify.py:115\nmsgid \"unspecified reason\"\nmsgstr \"未定原因\"\n\n#: lib/solaar/ui/pair_window.py:37 lib/solaar/ui/pair_window.py:155\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s: 配对新设备\"\n\n#: lib/solaar/ui/pair_window.py:39\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Bolt接收器仅适用于Bolt设备\"\n\n#: lib/solaar/ui/pair_window.py:41\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"按住配对按钮或按键直到配对指示灯快速闪烁。\"\n\n#: lib/solaar/ui/pair_window.py:44\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"优联接收器仅适用于优联设备\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"其他接收器仅能用于少量设备\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid \"Turn on the device you want to pair.\"\nmsgstr \"打开需配对设备的电源。\"\n\n#: lib/solaar/ui/pair_window.py:49\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"设备不可与附近已上电的接收器处于配对状态\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"如果设备电源已经打开，请先关闭再重新打开。\"\n\n#: lib/solaar/ui/pair_window.py:55\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"此接收器还可再与 %d 个设备配对。\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"此时取消将不会使配对生效。\"\n\n#: lib/solaar/ui/pair_window.py:156\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"在 %(name)s 上输入密码。\"\n\n#: lib/solaar/ui/pair_window.py:159\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"输入 %(passcode)s 后按下回车键。\"\n\n#: lib/solaar/ui/pair_window.py:162\nmsgid \"left\"\nmsgstr \"左键\"\n\n#: lib/solaar/ui/pair_window.py:162\nmsgid \"right\"\nmsgstr \"右键\"\n\n#: lib/solaar/ui/pair_window.py:164\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"按下 %(code)s\\n\"\n\"后同时按下左键和右键。\"\n\n#: lib/solaar/ui/pair_window.py:195\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"无线连接未加密\"\n\n#: lib/solaar/ui/pair_window.py:200\nmsgid \"Found a new device:\"\nmsgstr \"发现新设备:\"\n\n#: lib/solaar/ui/pair_window.py:221\nmsgid \"Pairing failed\"\nmsgstr \"配对失败\"\n\n#: lib/solaar/ui/pair_window.py:223\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"请确认您的设备已在范围内，并保证其电量充足。\"\n\n#: lib/solaar/ui/pair_window.py:225\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"检测到 1 个新设备，但与此接收器不兼容。\"\n\n#: lib/solaar/ui/pair_window.py:227\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"已配对设备超出接收器所支持的数量。\"\n\n#: lib/solaar/ui/pair_window.py:229\nmsgid \"No further details are available about the error.\"\nmsgstr \"无此错误的详细信息。\"\n\n#: lib/solaar/ui/rule_actions.py:48\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"模拟同时点击、按住或释放一个按键。\\n\"\n\"在 Wayland 上需要具备对 /dev/input 的写权限。\"\n\n#: lib/solaar/ui/rule_actions.py:53\nmsgid \"Add key\"\nmsgstr \"添加按键\"\n\n#: lib/solaar/ui/rule_actions.py:56\nmsgid \"Click\"\nmsgstr \"点击\"\n\n#: lib/solaar/ui/rule_actions.py:59\nmsgid \"Depress\"\nmsgstr \"按住\"\n\n#: lib/solaar/ui/rule_actions.py:62\nmsgid \"Release\"\nmsgstr \"释放\"\n\n#: lib/solaar/ui/rule_actions.py:147\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"模拟一次鼠标滚轮滚动。\\n\"\n\"在 Wayland 上需要具备对 /dev/input 的写权限。\"\n\n#: lib/solaar/ui/rule_actions.py:203\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"模拟一次鼠标点击。\\n\"\n\"在 Wayland 上需要具备对 /dev/input 的写权限。\"\n\n#: lib/solaar/ui/rule_actions.py:206\nmsgid \"Button\"\nmsgstr \"按钮\"\n\n#: lib/solaar/ui/rule_actions.py:207\nmsgid \"Count and Action\"\nmsgstr \"计数及行为\"\n\n#: lib/solaar/ui/rule_actions.py:256\nmsgid \"Execute a command with arguments.\"\nmsgstr \"运行一条带有参数的命令。\"\n\n#: lib/solaar/ui/rule_actions.py:259\nmsgid \"Add argument\"\nmsgstr \"添加参数\"\n\n#: lib/solaar/ui/rule_conditions.py:43\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"X11 活动进程。仅在 X11 中可用。\"\n\n#: lib/solaar/ui/rule_conditions.py:73\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"X11 光标所在进程。仅在 X11 中可用。\"\n\n#: lib/solaar/ui/rule_conditions.py:90\nmsgid \"MouseProcess\"\nmsgstr \"光标所在进程\"\n\n#: lib/solaar/ui/rule_conditions.py:114\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"处理报告触发规则时的特性名称。\"\n\n#: lib/solaar/ui/rule_conditions.py:161\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"处理报告触发规则时的回报数字。\"\n\n#: lib/solaar/ui/rule_conditions.py:194\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"激活的键盘修饰键。在 Wayland 中不总是可用。\"\n\n#: lib/solaar/ui/rule_conditions.py:234\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"转换的键未按下或已松开。\\n\"\n\"请通过“转换按键”或“转换G键”设置来配置按键转换。\"\n\n#: lib/solaar/ui/rule_conditions.py:243\nmsgid \"Key down\"\nmsgstr \"按键按下\"\n\n#: lib/solaar/ui/rule_conditions.py:246\nmsgid \"Key up\"\nmsgstr \"按键弹起\"\n\n#: lib/solaar/ui/rule_conditions.py:286\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"转换的键已按下。\\n\"\n\"请通过“转换按键”或“转换G键”设置来配置按键转换。\"\n\n#: lib/solaar/ui/rule_conditions.py:324\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"在规则触发时测试条件。\"\n\n#: lib/solaar/ui/rule_conditions.py:328\nmsgid \"Parameter\"\nmsgstr \"参数\"\n\n#: lib/solaar/ui/rule_conditions.py:401\nmsgid \"begin (inclusive)\"\nmsgstr \"起始 (含)\"\n\n#: lib/solaar/ui/rule_conditions.py:402\nmsgid \"end (exclusive)\"\nmsgstr \"结束 (不含)\"\n\n#: lib/solaar/ui/rule_conditions.py:410\nmsgid \"range\"\nmsgstr \"范围\"\n\n#: lib/solaar/ui/rule_conditions.py:413\nmsgid \"minimum\"\nmsgstr \"最小值\"\n\n#: lib/solaar/ui/rule_conditions.py:414\nmsgid \"maximum\"\nmsgstr \"最大值\"\n\n#: lib/solaar/ui/rule_conditions.py:416\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"从%(0)d 到 %(1)d 字节，范围从 %(2)d 到 %(3)d\"\n\n#: lib/solaar/ui/rule_conditions.py:419 lib/solaar/ui/rule_conditions.py:420\nmsgid \"mask\"\nmsgstr \"掩码\"\n\n#: lib/solaar/ui/rule_conditions.py:421\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"从%(0)d 到 %(1)d 字节，掩码为 %(2)d\"\n\n#: lib/solaar/ui/rule_conditions.py:430\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"规则触发时对指定的比特位进行测试或值域检测。\"\n\n#: lib/solaar/ui/rule_conditions.py:440\nmsgid \"type\"\nmsgstr \"类型\"\n\n#: lib/solaar/ui/rule_conditions.py:528\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"带有可选触发键并跟随有零个或多个鼠标移动轨迹的鼠标手势。\"\n\n#: lib/solaar/ui/rule_conditions.py:533\nmsgid \"Add movement\"\nmsgstr \"增加移动轨迹\"\n\n#: lib/solaar/ui/tray.py:50\nmsgid \"No supported device found\"\nmsgstr \"未发现支持的设备\"\n\n#: lib/solaar/ui/tray.py:55 lib/solaar/ui/window.py:310\n#, python-format\nmsgid \"About %s\"\nmsgstr \"关于 %s\"\n\n#: lib/solaar/ui/tray.py:56 lib/solaar/ui/window.py:308\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"退出 %s\"\n\n#: lib/solaar/ui/tray.py:267 lib/solaar/ui/tray.py:275\nmsgid \"no receiver\"\nmsgstr \"无接收器\"\n\n#: lib/solaar/ui/tray.py:288 lib/solaar/ui/tray.py:293\nmsgid \"offline\"\nmsgstr \"离线\"\n\n#: lib/solaar/ui/tray.py:291\nmsgid \"no status\"\nmsgstr \"无状态\"\n\n#: lib/solaar/ui/window.py:91\nmsgid \"Scanning\"\nmsgstr \"扫描中\"\n\n#: lib/solaar/ui/window.py:122\nmsgid \"Battery\"\nmsgstr \"电池\"\n\n#: lib/solaar/ui/window.py:125\nmsgid \"Wireless Link\"\nmsgstr \"无线连接\"\n\n#: lib/solaar/ui/window.py:129\nmsgid \"Lighting\"\nmsgstr \"照明\"\n\n#: lib/solaar/ui/window.py:163\nmsgid \"Show Technical Details\"\nmsgstr \"显示技术细节\"\n\n#: lib/solaar/ui/window.py:179\nmsgid \"Pair new device\"\nmsgstr \"配对新设备\"\n\n#: lib/solaar/ui/window.py:197\nmsgid \"Select a device\"\nmsgstr \"选择 1 个设备\"\n\n#: lib/solaar/ui/window.py:313\nmsgid \"Rule Editor\"\nmsgstr \"规则编辑器\"\n\n#: lib/solaar/ui/window.py:517\nmsgid \"Path\"\nmsgstr \"路径\"\n\n#: lib/solaar/ui/window.py:520\nmsgid \"USB ID\"\nmsgstr \"\"\n\n#: lib/solaar/ui/window.py:523 lib/solaar/ui/window.py:525\n#: lib/solaar/ui/window.py:540 lib/solaar/ui/window.py:542\nmsgid \"Serial\"\nmsgstr \"序列号\"\n\n#: lib/solaar/ui/window.py:529\nmsgid \"Index\"\nmsgstr \"索引号\"\n\n#: lib/solaar/ui/window.py:531\nmsgid \"Wireless PID\"\nmsgstr \"无线标示符\"\n\n#: lib/solaar/ui/window.py:533\nmsgid \"Product ID\"\nmsgstr \"产品 ID\"\n\n#: lib/solaar/ui/window.py:535\nmsgid \"Protocol\"\nmsgstr \"协议\"\n\n#: lib/solaar/ui/window.py:535\nmsgid \"Unknown\"\nmsgstr \"未知\"\n\n#: lib/solaar/ui/window.py:537\nmsgid \"Polling rate\"\nmsgstr \"轮询速率\"\n\n#: lib/solaar/ui/window.py:544\nmsgid \"Unit ID\"\nmsgstr \"单元 ID\"\n\n#: lib/solaar/ui/window.py:558\nmsgid \"Notifications\"\nmsgstr \"提示\"\n\n#: lib/solaar/ui/window.py:602\nmsgid \"No device paired.\"\nmsgstr \"没有已配对设备。\"\n\n#: lib/solaar/ui/window.py:611\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"此接收器最多可与 %(max_count)s 个设备配对。\"\n\n#: lib/solaar/ui/window.py:622\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"此接收器还可再与 %d 个设备配对。\"\n\n#: lib/solaar/ui/window.py:679\nmsgid \"Battery Voltage\"\nmsgstr \"电池电压\"\n\n#: lib/solaar/ui/window.py:681\nmsgid \"Voltage reported by battery\"\nmsgstr \"电池报告的电压\"\n\n#: lib/solaar/ui/window.py:683\nmsgid \"Battery Level\"\nmsgstr \"电量\"\n\n#: lib/solaar/ui/window.py:685\nmsgid \"Approximate level reported by battery\"\nmsgstr \"电池报告的大致电量\"\n\n#: lib/solaar/ui/window.py:692 lib/solaar/ui/window.py:694\nmsgid \"next reported \"\nmsgstr \"下次报告于 \"\n\n#: lib/solaar/ui/window.py:695\nmsgid \" and next level to be reported.\"\nmsgstr \" 以及下一个报告电量。\"\n\n#: lib/solaar/ui/window.py:711\nmsgid \"encrypted\"\nmsgstr \"已加密\"\n\n#: lib/solaar/ui/window.py:713\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"设备与接收器间的无线连接已加密。\"\n\n#: lib/solaar/ui/window.py:715\nmsgid \"not encrypted\"\nmsgstr \"未加密\"\n\n#: lib/solaar/ui/window.py:719\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"设备和接收器间的无线连接未加密。\\n\"\n\"对于指针设备，这是一个安全问题；对于文本输入设备，这是一个严重的安全问题。\"\n\n#: lib/solaar/ui/window.py:735\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"\"\n\n#~ msgid \" paired devices.\"\n#~ msgstr \" 个已配对设备。\"\n\n#~ msgid \"1 paired device.\"\n#~ msgstr \"1 个已配对设备。\"\n\n#~ msgid \"About\"\n#~ msgstr \"关于\"\n\n#~ msgid \"Add action\"\n#~ msgstr \"添加动作\"\n\n#~ msgid \"\"\n#~ \"Adjust the DPI by sliding the mouse horizontally while holding the button \"\n#~ \"down.\"\n#~ msgstr \"通过在按住按钮的同时滑动鼠标来调节 DPI。\"\n\n#~ msgid \"\"\n#~ \"Automatically switch the mouse wheel between ratchet and freespin mode.\\n\"\n#~ \"The mouse wheel is always free at 0, and always ratcheted at 50\"\n#~ msgstr \"\"\n#~ \"自动切换滚轮的段落和自由滚动模式。\\n\"\n#~ \"在 0 时，滚轮永远为自由滚动模式；在 50 时，滚轮永远为段落模式\"\n\n#~ msgid \"Battery information unknown.\"\n#~ msgstr \"电池信息未知。\"\n\n#~ msgid \"Battery: %(level)s\"\n#~ msgstr \"电池: %(level)s\"\n\n#~ msgid \"Battery: %(percent)d%%\"\n#~ msgstr \"电池: %(percent)d%%\"\n\n#~ msgid \"Count\"\n#~ msgstr \"数量\"\n\n#~ msgid \"DPI Sliding Adjustment\"\n#~ msgstr \"DPI 滑动调节\"\n\n#~ msgid \"Divert G Keys\"\n#~ msgstr \"G 键重定义\"\n\n#~ msgid \"\"\n#~ \"Diverted key or button depressed or released.\\n\"\n#~ \"Use the Key/Button Diversion setting to divert keys and buttons.\"\n#~ msgstr \"\"\n#~ \"重定义的按键或按钮未按下或已释放。\\n\"\n#~ \"要重定义按键/按钮，请使用按键/按钮重定义设置。\"\n\n#~ msgid \"Effectively turns off thumb scrolling in Linux.\"\n#~ msgstr \"在 Linux 中有效关闭拇指滚轮滚动。\"\n\n#~ msgid \"Effectively turns off wheel scrolling in Linux.\"\n#~ msgstr \"在 Linux 中有效关闭滚轮滚动。\"\n\n#~ msgid \"\"\n#~ \"Enable onboard profiles, which often control report rate and keyboard \"\n#~ \"lighting\"\n#~ msgstr \"启用板载预设，通常会接管回报率和键盘灯光\"\n\n#~ msgid \"\"\n#~ \"Found a Logitech Receiver (%s), but did not have permission to open it.\"\n#~ msgstr \"已发现 1 个罗技接收器 (%s)，但您没有访问权限。\"\n\n#~ msgid \"Found a new device\"\n#~ msgstr \"发现 1 个新设备\"\n\n#~ msgid \"Frequency of device polling, in milliseconds\"\n#~ msgstr \"设备轮询频率，单位为毫秒\"\n\n#~ msgid \"HID++ mode for horizontal scroll with the thumb wheel.\"\n#~ msgstr \"为滚轮的水平滚动启用 HID++ 模式。\"\n\n#~ msgid \"HID++ mode for vertical scroll with the wheel.\"\n#~ msgstr \"为滚轮的垂直滚动启用 HID++ 模式。\"\n\n#~ msgid \"\"\n#~ \"If the device is already turned on,\\n\"\n#~ \"turn if off and on again.\"\n#~ msgstr \"\"\n#~ \"若设备的电源已经打开，\\n\"\n#~ \"请先关闭再开启。\"\n\n#~ msgid \"\"\n#~ \"If you've just installed Solaar, try removing the receiver and plugging \"\n#~ \"it back in.\"\n#~ msgstr \"若您刚刚安装 Solaar，请尝试将接收器拔下再重新插上。\"\n\n#~ msgid \"Lighting: %(level)s lux\"\n#~ msgstr \"照明: %(level)s lux\"\n\n#~ msgid \"\"\n#~ \"Make G keys send GKEY HID++ notifications (which trigger Solaar rules but \"\n#~ \"are otherwise ignored).\"\n#~ msgstr \"\"\n#~ \"使 G 键发送 GKEY (G 键) HID++ 通告 (这会触发 Solaar 规则，但如果没有，就会\"\n#~ \"被忽略)\"\n\n#~ msgid \"\"\n#~ \"Make the key or button send HID++ notifications (which trigger Solaar \"\n#~ \"rules but are otherwise ignored).\"\n#~ msgstr \"\"\n#~ \"使按键或按钮发送 HID++ 通告 (这会触发 Solaar 规则，但如果没有，就会被忽略)\"\n\n#~ msgid \"May also make M keys and MR key send HID++ notifications\"\n#~ msgstr \"同样也使 M 键和 MR 键发送 HID++ 通告\"\n\n#~ msgid \"No Logitech device found\"\n#~ msgstr \"未发现罗技设备\"\n\n#~ msgid \"No Logitech receiver found\"\n#~ msgstr \"未发现罗技接收器\"\n\n#~ msgid \"No device paired\"\n#~ msgstr \"无已配对设备\"\n\n#~ msgid \"Only one device can be paired to this receiver\"\n#~ msgstr \"此接收器仅支持配对 1 个设备\"\n\n#~ msgid \"Only one device can be paired to this receiver.\"\n#~ msgstr \"此接收器只能与一个设备配对。\"\n\n#~ msgid \"Polling Rate (ms)\"\n#~ msgstr \"轮询速率 (ms)\"\n\n#~ msgid \"Quit\"\n#~ msgstr \"退出\"\n\n#~ msgid \"Scroll Wheel Rachet\"\n#~ msgstr \"滚轮段落模式\"\n\n#~ msgid \"Send a gesture by sliding the mouse while holding the button down.\"\n#~ msgstr \"通过在按住按钮的同时滑动鼠标来发送手势。\"\n\n#~ msgid \"\"\n#~ \"Shows status of devices connected\\n\"\n#~ \"through wireless Logitech receivers.\"\n#~ msgstr \"\"\n#~ \"显示罗技接收器\\n\"\n#~ \"已连接的设备状态。\"\n\n#~ msgid \"Smooth Scrolling\"\n#~ msgstr \"平滑滚动\"\n\n#~ msgid \"The receiver only supports %d paired device(s).\"\n#~ msgstr \"此接收器仅支持 %d 个配对设备。\"\n\n#~ msgid \"The receiver was unplugged.\"\n#~ msgstr \"接收器被移除。\"\n\n#~ msgid \"\"\n#~ \"The wireless link between this device and its receiver is not encrypted.\\n\"\n#~ \"\\n\"\n#~ \"For pointing devices (mice, trackballs, trackpads), this is a minor \"\n#~ \"security issue.\\n\"\n#~ \"\\n\"\n#~ \"It is, however, a major security issue for text-input devices (keyboards, \"\n#~ \"numpads),\\n\"\n#~ \"because typed text can be sniffed inconspicuously by 3rd parties within \"\n#~ \"range.\"\n#~ msgstr \"\"\n#~ \"设备与接收器间的无线连接未加密。\\n\"\n#~ \"\\n\"\n#~ \"对定位设备（如鼠标、轨迹球、触摸板）来说这不是什么问题。\\n\"\n#~ \"\\n\"\n#~ \"然而这对于内容输入设备（如键盘、数字键盘）却是一个重大的安全问题，\\n\"\n#~ \"您输入的内容有可能被第三方偷偷监听到。\"\n\n#~ msgid \"\"\n#~ \"Try removing the device and plugging it back in or turning it off and \"\n#~ \"then on.\"\n#~ msgstr \"请尝试将设备拔下再重新插上，或关闭电源后重新打开。\"\n\n#~ msgid \"Turn illumination on or off on keyboard.\"\n#~ msgstr \"打开或关闭键盘背光。\"\n\n#~ msgid \"USB id\"\n#~ msgstr \"USB 序号\"\n\n#~ msgid \"Up to %d devices can be paired to this receiver\"\n#~ msgstr \"此接收器可配对至多 %d 个设备\"\n\n#~ msgid \"You may have to first turn the device off and on again.\"\n#~ msgstr \"您可能需要先关闭设备的电源再重新打开。\"\n\n#~ msgid \"closed\"\n#~ msgstr \"关闭\"\n\n#~ msgid \"last known\"\n#~ msgstr \"最后已知\"\n\n#~ msgid \"lux\"\n#~ msgstr \"lux\"\n\n#~ msgid \"none\"\n#~ msgstr \"无\"\n\n#~ msgid \"open\"\n#~ msgstr \"开启\"\n\n#~ msgid \"pair new device\"\n#~ msgstr \"配对新设备\"\n\n#~ msgid \"paired devices\"\n#~ msgstr \"个已配对设备\"\n\n#~ msgid \"pairing lock is \"\n#~ msgstr \"配对锁已\"\n\n#~ msgid \"unknown\"\n#~ msgstr \"未知的\"\n"
  },
  {
    "path": "po/zh_TW.po",
    "content": "# Chinese translations for solaar package\n# Copyright (C) 2014 THE solaar'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the solaar package.\n# Automatically generated, 2014.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: solaar 0.9.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-01 21:43+0300\\n\"\n\"PO-Revision-Date: 2025-12-07 07:17+0800\\n\"\n\"Last-Translator: Peter Dave Hello <hsu@peterdavehello.org>\\n\"\n\"Language-Team: Peter Dave Hello <hsu@peterdavehello.org>\\n\"\n\"Language: zh_TW\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"X-Language: zh_TW\\n\"\n\"X-Source-Language: C\\n\"\n\"X-Generator: Poedit 3.0\\n\"\n\n#: lib/logitech_receiver/base_usb.py:52\nmsgid \"Bolt Receiver\"\nmsgstr \"Bolt 接收器\"\n\n#: lib/logitech_receiver/base_usb.py:64\nmsgid \"Unifying Receiver\"\nmsgstr \"Unifying 接收器\"\n\n#: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87\n#: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113\nmsgid \"Nano Receiver\"\nmsgstr \"Nano 接收器\"\n\n#: lib/logitech_receiver/base_usb.py:125\nmsgid \"Lightspeed Receiver\"\nmsgstr \"Lightspeed 接收器\"\n\n#: lib/logitech_receiver/base_usb.py:135\nmsgid \"EX100 Receiver 27 Mhz\"\nmsgstr \"EX100 27 Mhz 接收器\"\n\n#: lib/logitech_receiver/common.py:649\n#, python-format\nmsgid \"Battery: %(level)s (%(status)s)\"\nmsgstr \"電量：%(level)s (%(status)s)\"\n\n#: lib/logitech_receiver/common.py:652\n#, python-format\nmsgid \"Battery: %(percent)d%% (%(status)s)\"\nmsgstr \"電量：%(percent)d%% (%(status)s)\"\n\n#: lib/logitech_receiver/hidpp20.py:1048\n#: lib/logitech_receiver/settings_templates.py:299\nmsgid \"Disabled\"\nmsgstr \"已停用\"\n\n#: lib/logitech_receiver/hidpp20.py:1049\nmsgid \"Static\"\nmsgstr \"靜態\"\n\n#: lib/logitech_receiver/hidpp20.py:1050\nmsgid \"Pulse\"\nmsgstr \"脈衝\"\n\n#: lib/logitech_receiver/hidpp20.py:1051\nmsgid \"Cycle\"\nmsgstr \"循環\"\n\n#: lib/logitech_receiver/hidpp20.py:1052\nmsgid \"Boot\"\nmsgstr \"開機\"\n\n#: lib/logitech_receiver/hidpp20.py:1053\nmsgid \"Demo\"\nmsgstr \"示範\"\n\n#: lib/logitech_receiver/hidpp20.py:1055\nmsgid \"Breathe\"\nmsgstr \"呼吸\"\n\n#: lib/logitech_receiver/hidpp20.py:1058\nmsgid \"Ripple\"\nmsgstr \"漣漪\"\n\n#: lib/logitech_receiver/hidpp20.py:1059\nmsgid \"Decomposition\"\nmsgstr \"分解\"\n\n#: lib/logitech_receiver/hidpp20.py:1060\nmsgid \"Signature1\"\nmsgstr \"簽名樣式 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1061\nmsgid \"Signature2\"\nmsgstr \"簽名樣式 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1062\nmsgid \"CycleS\"\nmsgstr \"循環式\"\n\n#: lib/logitech_receiver/hidpp20.py:1126\nmsgid \"Unknown Location\"\nmsgstr \"未知位置\"\n\n#: lib/logitech_receiver/hidpp20.py:1127\nmsgid \"Primary\"\nmsgstr \"主要\"\n\n#: lib/logitech_receiver/hidpp20.py:1128\nmsgid \"Logo\"\nmsgstr \"Logo\"\n\n#: lib/logitech_receiver/hidpp20.py:1129\nmsgid \"Left Side\"\nmsgstr \"左側\"\n\n#: lib/logitech_receiver/hidpp20.py:1130\nmsgid \"Right Side\"\nmsgstr \"右側\"\n\n#: lib/logitech_receiver/hidpp20.py:1131\nmsgid \"Combined\"\nmsgstr \"結合\"\n\n#: lib/logitech_receiver/hidpp20.py:1132\nmsgid \"Primary 1\"\nmsgstr \"主要 1\"\n\n#: lib/logitech_receiver/hidpp20.py:1133\nmsgid \"Primary 2\"\nmsgstr \"主要 2\"\n\n#: lib/logitech_receiver/hidpp20.py:1134\nmsgid \"Primary 3\"\nmsgstr \"主要 3\"\n\n#: lib/logitech_receiver/hidpp20.py:1135\nmsgid \"Primary 4\"\nmsgstr \"主要 4\"\n\n#: lib/logitech_receiver/hidpp20.py:1136\nmsgid \"Primary 5\"\nmsgstr \"主要 5\"\n\n#: lib/logitech_receiver/hidpp20.py:1137\nmsgid \"Primary 6\"\nmsgstr \"主要 6\"\n\n#: lib/logitech_receiver/i18n.py:28\nmsgid \"empty\"\nmsgstr \"電池已耗盡\"\n\n#: lib/logitech_receiver/i18n.py:29\nmsgid \"critical\"\nmsgstr \"極低\"\n\n#: lib/logitech_receiver/i18n.py:30\nmsgid \"low\"\nmsgstr \"低\"\n\n#: lib/logitech_receiver/i18n.py:31\nmsgid \"average\"\nmsgstr \"中等\"\n\n#: lib/logitech_receiver/i18n.py:32\nmsgid \"good\"\nmsgstr \"良好\"\n\n#: lib/logitech_receiver/i18n.py:33\nmsgid \"full\"\nmsgstr \"滿格\"\n\n#: lib/logitech_receiver/i18n.py:35\nmsgid \"discharging\"\nmsgstr \"放電中\"\n\n#: lib/logitech_receiver/i18n.py:36\nmsgid \"recharging\"\nmsgstr \"充電中\"\n\n#: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700\nmsgid \"charging\"\nmsgstr \"充電中\"\n\n#: lib/logitech_receiver/i18n.py:38\nmsgid \"not charging\"\nmsgstr \"未充電\"\n\n#: lib/logitech_receiver/i18n.py:39\nmsgid \"almost full\"\nmsgstr \"即將充滿\"\n\n#: lib/logitech_receiver/i18n.py:40\nmsgid \"charged\"\nmsgstr \"已充滿\"\n\n#: lib/logitech_receiver/i18n.py:41\nmsgid \"slow recharge\"\nmsgstr \"慢速充電\"\n\n#: lib/logitech_receiver/i18n.py:42\nmsgid \"invalid battery\"\nmsgstr \"電池無效\"\n\n#: lib/logitech_receiver/i18n.py:43\nmsgid \"thermal error\"\nmsgstr \"溫度異常\"\n\n#: lib/logitech_receiver/i18n.py:44\nmsgid \"error\"\nmsgstr \"錯誤\"\n\n#: lib/logitech_receiver/i18n.py:45\nmsgid \"standard\"\nmsgstr \"標準\"\n\n#: lib/logitech_receiver/i18n.py:46\nmsgid \"fast\"\nmsgstr \"快速\"\n\n#: lib/logitech_receiver/i18n.py:47\nmsgid \"slow\"\nmsgstr \"慢\"\n\n#: lib/logitech_receiver/i18n.py:49\nmsgid \"device timeout\"\nmsgstr \"裝置逾時\"\n\n#: lib/logitech_receiver/i18n.py:50\nmsgid \"device not supported\"\nmsgstr \"不支援此裝置\"\n\n#: lib/logitech_receiver/i18n.py:51\nmsgid \"too many devices\"\nmsgstr \"裝置數量太多\"\n\n#: lib/logitech_receiver/i18n.py:52\nmsgid \"sequence timeout\"\nmsgstr \"序列逾時\"\n\n#: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555\nmsgid \"Firmware\"\nmsgstr \"韌體\"\n\n#: lib/logitech_receiver/i18n.py:55\nmsgid \"Bootloader\"\nmsgstr \"開機載入程式\"\n\n#: lib/logitech_receiver/i18n.py:56\nmsgid \"Hardware\"\nmsgstr \"硬體\"\n\n#: lib/logitech_receiver/i18n.py:57\nmsgid \"Other\"\nmsgstr \"其他\"\n\n#: lib/logitech_receiver/i18n.py:59\nmsgid \"Left Button\"\nmsgstr \"左鍵\"\n\n#: lib/logitech_receiver/i18n.py:60\nmsgid \"Right Button\"\nmsgstr \"右鍵\"\n\n#: lib/logitech_receiver/i18n.py:61\nmsgid \"Middle Button\"\nmsgstr \"中鍵\"\n\n#: lib/logitech_receiver/i18n.py:62\nmsgid \"Back Button\"\nmsgstr \"返回鍵\"\n\n#: lib/logitech_receiver/i18n.py:63\nmsgid \"Forward Button\"\nmsgstr \"前進鍵\"\n\n#: lib/logitech_receiver/i18n.py:64\nmsgid \"Mouse Gesture Button\"\nmsgstr \"滑鼠手勢鍵\"\n\n#: lib/logitech_receiver/i18n.py:65\nmsgid \"Smart Shift\"\nmsgstr \"智慧切換\"\n\n#: lib/logitech_receiver/i18n.py:66\nmsgid \"DPI Switch\"\nmsgstr \"DPI 切換\"\n\n#: lib/logitech_receiver/i18n.py:67\nmsgid \"Left Tilt\"\nmsgstr \"向左傾斜\"\n\n#: lib/logitech_receiver/i18n.py:68\nmsgid \"Right Tilt\"\nmsgstr \"向右傾斜\"\n\n#: lib/logitech_receiver/i18n.py:69\nmsgid \"Left Click\"\nmsgstr \"左鍵\"\n\n#: lib/logitech_receiver/i18n.py:70\nmsgid \"Right Click\"\nmsgstr \"右鍵\"\n\n#: lib/logitech_receiver/i18n.py:71\nmsgid \"Mouse Middle Button\"\nmsgstr \"滑鼠中鍵\"\n\n#: lib/logitech_receiver/i18n.py:72\nmsgid \"Mouse Back Button\"\nmsgstr \"滑鼠返回鍵\"\n\n#: lib/logitech_receiver/i18n.py:73\nmsgid \"Mouse Forward Button\"\nmsgstr \"滑鼠前進鍵\"\n\n#: lib/logitech_receiver/i18n.py:74\nmsgid \"Gesture Button Navigation\"\nmsgstr \"手勢按鈕導覽\"\n\n#: lib/logitech_receiver/i18n.py:75\nmsgid \"Mouse Scroll Left Button\"\nmsgstr \"滑鼠滾輪向左按鈕\"\n\n#: lib/logitech_receiver/i18n.py:76\nmsgid \"Mouse Scroll Right Button\"\nmsgstr \"滑鼠滾輪向右按鈕\"\n\n#: lib/logitech_receiver/i18n.py:78\nmsgid \"pressed\"\nmsgstr \"按下\"\n\n#: lib/logitech_receiver/i18n.py:79\nmsgid \"released\"\nmsgstr \"放開\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"connected\"\nmsgstr \"已連線\"\n\n#: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243\nmsgid \"disconnected\"\nmsgstr \"已斷線\"\n\n#: lib/logitech_receiver/notifications.py:182\nmsgid \"unpaired\"\nmsgstr \"未配對\"\n\n#: lib/logitech_receiver/notifications.py:231\nmsgid \"powered on\"\nmsgstr \"已啟動\"\n\n#: lib/logitech_receiver/notifications.py:283\nmsgid \"ADC measurement notification\"\nmsgstr \"ADC 量測通知\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:483\nmsgid \"pairing lock is closed\"\nmsgstr \"配對鎖已關閉\"\n\n#: lib/logitech_receiver/notifications.py:428\n#: lib/logitech_receiver/notifications.py:483\nmsgid \"pairing lock is open\"\nmsgstr \"配對鎖已開啟\"\n\n#: lib/logitech_receiver/notifications.py:446\nmsgid \"discovery lock is closed\"\nmsgstr \"探索鎖已關閉\"\n\n#: lib/logitech_receiver/notifications.py:446\nmsgid \"discovery lock is open\"\nmsgstr \"探索鎖已開啟\"\n\n#: lib/logitech_receiver/receiver.py:437\nmsgid \"No paired devices.\"\nmsgstr \"沒有已配對的裝置。\"\n\n#: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606\n#, python-format\nmsgid \"%(count)s paired device.\"\nmsgid_plural \"%(count)s paired devices.\"\nmsgstr[0] \"%(count)s 個已配對裝置。\"\n\n#: lib/logitech_receiver/settings.py:602\nmsgid \"register\"\nmsgstr \"暫存器\"\n\n#: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654\nmsgid \"feature\"\nmsgstr \"功能\"\n\n#: lib/logitech_receiver/settings_templates.py:138\nmsgid \"Swap Fx function\"\nmsgstr \"互換 Fx 鍵功能\"\n\n#: lib/logitech_receiver/settings_templates.py:141\nmsgid \"\"\n\"When set, the F1..F12 keys will activate their special function,\\n\"\n\"and you must hold the FN key to activate their standard function.\"\nmsgstr \"\"\n\"啟用後，F1 到 F12 鍵將會啟動特殊功能，\\n\"\n\"若要使用標準功能請同時按住 FN 鍵。\"\n\n#: lib/logitech_receiver/settings_templates.py:146\nmsgid \"\"\n\"When unset, the F1..F12 keys will activate their standard function,\\n\"\n\"and you must hold the FN key to activate their special function.\"\nmsgstr \"\"\n\"停用後，F1 到 F12 鍵將會啟動標準功能，\\n\"\n\"若要使用特殊功能請同時按住 FN 鍵。\"\n\n#: lib/logitech_receiver/settings_templates.py:154\nmsgid \"Hand Detection\"\nmsgstr \"手掌偵測\"\n\n#: lib/logitech_receiver/settings_templates.py:155\nmsgid \"Turn on illumination when the hands hover over the keyboard.\"\nmsgstr \"當手掌置於在鍵盤上方時開啟照明。\"\n\n#: lib/logitech_receiver/settings_templates.py:162\nmsgid \"Scroll Wheel Smooth Scrolling\"\nmsgstr \"滾輪平滑捲動\"\n\n#: lib/logitech_receiver/settings_templates.py:163\n#: lib/logitech_receiver/settings_templates.py:410\n#: lib/logitech_receiver/settings_templates.py:439\nmsgid \"High-sensitivity mode for vertical scroll with the wheel.\"\nmsgstr \"滾輪垂直捲動的高靈敏度模式。\"\n\n#: lib/logitech_receiver/settings_templates.py:170\nmsgid \"Side Scrolling\"\nmsgstr \"側邊捲動\"\n\n#: lib/logitech_receiver/settings_templates.py:172\nmsgid \"\"\n\"When disabled, pushing the wheel sideways sends custom button events\\n\"\n\"instead of the standard side-scrolling events.\"\nmsgstr \"\"\n\"停用後，向側邊推動滾輪將會傳送自訂按鈕事件，\\n\"\n\"而非標準的側邊捲動事件。\"\n\n#: lib/logitech_receiver/settings_templates.py:182\nmsgid \"Sensitivity (DPI - older mice)\"\nmsgstr \"靈敏度（DPI - 較舊的滑鼠）\"\n\n#: lib/logitech_receiver/settings_templates.py:183\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\nmsgid \"Mouse movement sensitivity\"\nmsgstr \"滑鼠移動靈敏度\"\n\n#: lib/logitech_receiver/settings_templates.py:256\nmsgid \"Backlight Timed\"\nmsgstr \"背光計時\"\n\n#: lib/logitech_receiver/settings_templates.py:257\n#: lib/logitech_receiver/settings_templates.py:397\nmsgid \"Set illumination time for keyboard.\"\nmsgstr \"設定鍵盤的照明時間。\"\n\n#: lib/logitech_receiver/settings_templates.py:268\nmsgid \"Backlight\"\nmsgstr \"背光\"\n\n#: lib/logitech_receiver/settings_templates.py:269\nmsgid \"\"\n\"Illumination level on keyboard.  Changes made are only applied in Manual \"\n\"mode.\"\nmsgstr \"鍵盤上的亮度等級。僅在手動模式下適用。\"\n\n#: lib/logitech_receiver/settings_templates.py:301\nmsgid \"Automatic\"\nmsgstr \"自動\"\n\n#: lib/logitech_receiver/settings_templates.py:303\nmsgid \"Manual\"\nmsgstr \"手動\"\n\n#: lib/logitech_receiver/settings_templates.py:305\nmsgid \"Enabled\"\nmsgstr \"已啟用\"\n\n#: lib/logitech_receiver/settings_templates.py:311\nmsgid \"Backlight Level\"\nmsgstr \"背光等級\"\n\n#: lib/logitech_receiver/settings_templates.py:312\nmsgid \"Illumination level on keyboard when in Manual mode.\"\nmsgstr \"手動模式下的鍵盤照明等級。\"\n\n#: lib/logitech_receiver/settings_templates.py:369\nmsgid \"Backlight Delay Hands Out\"\nmsgstr \"手離開後背光延遲\"\n\n#: lib/logitech_receiver/settings_templates.py:370\nmsgid \"\"\n\"Delay in seconds until backlight fades out with hands away from keyboard.\"\nmsgstr \"手離開鍵盤後，背光淡出的延遲秒數。\"\n\n#: lib/logitech_receiver/settings_templates.py:378\nmsgid \"Backlight Delay Hands In\"\nmsgstr \"手靠近後背光延遲\"\n\n#: lib/logitech_receiver/settings_templates.py:379\nmsgid \"Delay in seconds until backlight fades out with hands near keyboard.\"\nmsgstr \"手靠近鍵盤後，背光淡出的延遲秒數。\"\n\n#: lib/logitech_receiver/settings_templates.py:387\nmsgid \"Backlight Delay Powered\"\nmsgstr \"供電後背光延遲\"\n\n#: lib/logitech_receiver/settings_templates.py:388\nmsgid \"Delay in seconds until backlight fades out with external power.\"\nmsgstr \"外部供電時，背光淡出的延遲秒數。\"\n\n#: lib/logitech_receiver/settings_templates.py:396\nmsgid \"Backlight (Seconds)\"\nmsgstr \"背光（秒）\"\n\n#: lib/logitech_receiver/settings_templates.py:408\nmsgid \"Scroll Wheel High Resolution\"\nmsgstr \"滾輪高解析度\"\n\n#: lib/logitech_receiver/settings_templates.py:412\n#: lib/logitech_receiver/settings_templates.py:441\nmsgid \"Set to ignore if scrolling is abnormally fast or slow\"\nmsgstr \"若捲動速度異常快或慢，設定為忽略\"\n\n#: lib/logitech_receiver/settings_templates.py:419\n#: lib/logitech_receiver/settings_templates.py:450\nmsgid \"Scroll Wheel Diversion\"\nmsgstr \"滾輪轉向\"\n\n#: lib/logitech_receiver/settings_templates.py:421\nmsgid \"\"\n\"Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger \"\n\"Solaar rules but are otherwise ignored).\"\nmsgstr \"\"\n\"使輪傳送 LOWRES_WHEEL HID++ 通知（會觸發 Solaar 規則，但其他情況下會被忽\"\n\"略）。\"\n\n#: lib/logitech_receiver/settings_templates.py:428\nmsgid \"Scroll Wheel Direction\"\nmsgstr \"滾輪方向\"\n\n#: lib/logitech_receiver/settings_templates.py:429\nmsgid \"Invert direction for vertical scroll with wheel.\"\nmsgstr \"反轉滾輪的垂直捲動方向。\"\n\n#: lib/logitech_receiver/settings_templates.py:437\nmsgid \"Scroll Wheel Resolution\"\nmsgstr \"滾輪解析度\"\n\n#: lib/logitech_receiver/settings_templates.py:452\nmsgid \"\"\n\"Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"讓滾輪傳送 HIRES_WHEEL HID++ 通知（會觸發 Solaar 規則，但其他情況下會被忽\"\n\"略）。\"\n\n#: lib/logitech_receiver/settings_templates.py:461\nmsgid \"Sensitivity (Pointer Speed)\"\nmsgstr \"靈敏度（指標速度）\"\n\n#: lib/logitech_receiver/settings_templates.py:462\nmsgid \"Speed multiplier for mouse (256 is normal multiplier).\"\nmsgstr \"滑鼠速度倍數（256 為正常倍數）。\"\n\n#: lib/logitech_receiver/settings_templates.py:472\nmsgid \"Thumb Wheel Diversion\"\nmsgstr \"拇指滾輪轉向\"\n\n#: lib/logitech_receiver/settings_templates.py:474\nmsgid \"\"\n\"Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar \"\n\"rules but are otherwise ignored).\"\nmsgstr \"\"\n\"讓拇指滾輪傳送 THUMB_WHEEL HID++ 通知（會觸發 Solaar 規則，但其他情況下會被忽\"\n\"略）。\"\n\n#: lib/logitech_receiver/settings_templates.py:483\nmsgid \"Thumb Wheel Direction\"\nmsgstr \"拇指滾輪方向\"\n\n#: lib/logitech_receiver/settings_templates.py:484\nmsgid \"Invert thumb wheel scroll direction.\"\nmsgstr \"反轉拇指滾輪捲動方向。\"\n\n#: lib/logitech_receiver/settings_templates.py:504\nmsgid \"Onboard Profiles\"\nmsgstr \"內建設定檔\"\n\n#: lib/logitech_receiver/settings_templates.py:505\nmsgid \"\"\n\"Enable an onboard profile, which controls report rate, sensitivity, and \"\n\"button actions\"\nmsgstr \"啟用內建設定檔，可控制回報速率、靈敏度和按鈕動作\"\n\n#: lib/logitech_receiver/settings_templates.py:549\n#: lib/logitech_receiver/settings_templates.py:582\nmsgid \"Report Rate\"\nmsgstr \"回報速率\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\nmsgid \"Frequency of device movement reports\"\nmsgstr \"裝置移動回報的頻率\"\n\n#: lib/logitech_receiver/settings_templates.py:551\n#: lib/logitech_receiver/settings_templates.py:584\n#: lib/logitech_receiver/settings_templates.py:1019\n#: lib/logitech_receiver/settings_templates.py:1047\n#: lib/logitech_receiver/settings_templates.py:1421\n#: lib/logitech_receiver/settings_templates.py:1452\nmsgid \"May need Onboard Profiles set to Disable to be effective.\"\nmsgstr \"可能需要將內建設定檔設為停用才能生效。\"\n\n#: lib/logitech_receiver/settings_templates.py:612\nmsgid \"Divert crown events\"\nmsgstr \"轉向多功能旋鈕事件\"\n\n#: lib/logitech_receiver/settings_templates.py:613\nmsgid \"\"\n\"Make crown send CROWN HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"讓多功能旋鈕傳送 CROWN HID++ 通知（會觸發 Solaar 規則，但其他情況下會被忽\"\n\"略）。\"\n\n#: lib/logitech_receiver/settings_templates.py:621\nmsgid \"Crown smooth scroll\"\nmsgstr \"多功能旋鈕平滑捲動\"\n\n#: lib/logitech_receiver/settings_templates.py:622\nmsgid \"Set crown smooth scroll\"\nmsgstr \"設定多功能旋鈕平滑捲動\"\n\n#: lib/logitech_receiver/settings_templates.py:630\nmsgid \"Divert G and M Keys\"\nmsgstr \"轉向 G 鍵和 M 鍵\"\n\n#: lib/logitech_receiver/settings_templates.py:631\nmsgid \"\"\n\"Make G and M keys send HID++ notifications (which trigger Solaar rules but \"\n\"are otherwise ignored).\"\nmsgstr \"\"\n\"讓 G 鍵和 M 鍵傳送 HID++ 通知（會觸發 Solaar 規則，但其他情況下會被忽略）。\"\n\n#: lib/logitech_receiver/settings_templates.py:645\nmsgid \"Scroll Wheel Ratcheted\"\nmsgstr \"滾輪棘輪\"\n\n#: lib/logitech_receiver/settings_templates.py:646\nmsgid \"\"\n\"Switch the mouse wheel between speed-controlled ratcheting and always \"\n\"freespin.\"\nmsgstr \"在速度控制的棘輪模式和永遠自由捲動之間切換滑鼠滾輪。\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Freespinning\"\nmsgstr \"自由捲動\"\n\n#: lib/logitech_receiver/settings_templates.py:648\nmsgid \"Ratcheted\"\nmsgstr \"棘輪式\"\n\n#: lib/logitech_receiver/settings_templates.py:655\nmsgid \"Scroll Wheel Ratchet Speed\"\nmsgstr \"滾輪棘輪速度\"\n\n#: lib/logitech_receiver/settings_templates.py:657\nmsgid \"\"\n\"Use the mouse wheel speed to switch between ratcheted and freespinning.\\n\"\n\"The mouse wheel is always ratcheted at 50.\"\nmsgstr \"\"\n\"使用滑鼠滾輪速度在棘輪和自由捲動之間切換。\\n\"\n\"滾輪在 50 時永遠處於棘輪狀態。\"\n\n#: lib/logitech_receiver/settings_templates.py:707\nmsgid \"Scroll Wheel Ratchet Torque\"\nmsgstr \"滾輪棘輪扭矩\"\n\n#: lib/logitech_receiver/settings_templates.py:708\nmsgid \"Change the torque needed to overcome the ratchet.\"\nmsgstr \"變更克服棘輪所需的扭矩。\"\n\n#: lib/logitech_receiver/settings_templates.py:743\nmsgid \"Key/Button Actions\"\nmsgstr \"鍵/按鈕動作\"\n\n#: lib/logitech_receiver/settings_templates.py:745\nmsgid \"Change the action for the key or button.\"\nmsgstr \"變更按鍵或按鈕的動作。\"\n\n#: lib/logitech_receiver/settings_templates.py:747\nmsgid \"Overridden by diversion.\"\nmsgstr \"已被轉向覆寫。\"\n\n#: lib/logitech_receiver/settings_templates.py:749\nmsgid \"\"\n\"Changing important actions (such as for the left mouse button) can result in \"\n\"an unusable system.\"\nmsgstr \"變更重要動作（例如滑鼠左鍵）可能會導致系統無法使用。\"\n\n#: lib/logitech_receiver/settings_templates.py:924\nmsgid \"Key/Button Diversion\"\nmsgstr \"鍵/按鈕轉換\"\n\n#: lib/logitech_receiver/settings_templates.py:925\nmsgid \"\"\n\"Make the key or button send HID++ notifications (Diverted) or initiate Mouse \"\n\"Gestures or Sliding DPI\"\nmsgstr \"讓按鍵或按鈕傳送 HID++ 通知（已轉向）或啟動滑鼠手勢或滑動 DPI。\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Diverted\"\nmsgstr \"已轉向\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\nmsgid \"Mouse Gestures\"\nmsgstr \"滑鼠手勢\"\n\n#: lib/logitech_receiver/settings_templates.py:928\n#: lib/logitech_receiver/settings_templates.py:929\n#: lib/logitech_receiver/settings_templates.py:930\nmsgid \"Regular\"\nmsgstr \"一般\"\n\n#: lib/logitech_receiver/settings_templates.py:928\nmsgid \"Sliding DPI\"\nmsgstr \"滑動 DPI\"\n\n#: lib/logitech_receiver/settings_templates.py:1018\n#: lib/logitech_receiver/settings_templates.py:1046\nmsgid \"Sensitivity (DPI)\"\nmsgstr \"靈敏度 (DPI)\"\n\n#: lib/logitech_receiver/settings_templates.py:1123\nmsgid \"Sensitivity Switching\"\nmsgstr \"靈敏度切換\"\n\n#: lib/logitech_receiver/settings_templates.py:1125\nmsgid \"\"\n\"Switch the current sensitivity and the remembered sensitivity when the key \"\n\"or button is pressed.\\n\"\n\"If there is no remembered sensitivity, just remember the current sensitivity\"\nmsgstr \"\"\n\"按下按鍵或按鈕時，切換目前靈敏度和已記憶的靈敏度。\\n\"\n\"若沒有已記憶的靈敏度，則僅記住目前的靈敏度\"\n\n#: lib/logitech_receiver/settings_templates.py:1129\nmsgid \"Off\"\nmsgstr \"關閉\"\n\n#: lib/logitech_receiver/settings_templates.py:1160\nmsgid \"Disable keys\"\nmsgstr \"停用按鍵\"\n\n#: lib/logitech_receiver/settings_templates.py:1161\nmsgid \"Disable specific keyboard keys.\"\nmsgstr \"停用特定鍵盤按鍵。\"\n\n#: lib/logitech_receiver/settings_templates.py:1164\n#, python-format\nmsgid \"Disables the %s key.\"\nmsgstr \"停用 %s 鍵。\"\n\n#: lib/logitech_receiver/settings_templates.py:1177\n#: lib/logitech_receiver/settings_templates.py:1234\nmsgid \"Set OS\"\nmsgstr \"設定作業系統\"\n\n#: lib/logitech_receiver/settings_templates.py:1178\n#: lib/logitech_receiver/settings_templates.py:1235\nmsgid \"Change keys to match OS.\"\nmsgstr \"變更按鍵以符合作業系統。\"\n\n#: lib/logitech_receiver/settings_templates.py:1247\nmsgid \"Change Host\"\nmsgstr \"變更主機\"\n\n#: lib/logitech_receiver/settings_templates.py:1248\nmsgid \"Switch connection to a different host\"\nmsgstr \"切換連線到不同的主機\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Performs a left click.\"\nmsgstr \"執行左鍵點選。\"\n\n#: lib/logitech_receiver/settings_templates.py:1272\nmsgid \"Single tap\"\nmsgstr \"單次點選\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Performs a right click.\"\nmsgstr \"執行右鍵點選。\"\n\n#: lib/logitech_receiver/settings_templates.py:1273\nmsgid \"Single tap with two fingers\"\nmsgstr \"用兩根手指單次點選\"\n\n#: lib/logitech_receiver/settings_templates.py:1274\nmsgid \"Single tap with three fingers\"\nmsgstr \"用三根手指單次點選\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Double tap\"\nmsgstr \"點兩下\"\n\n#: lib/logitech_receiver/settings_templates.py:1278\nmsgid \"Performs a double click.\"\nmsgstr \"執行點兩下。\"\n\n#: lib/logitech_receiver/settings_templates.py:1279\nmsgid \"Double tap with two fingers\"\nmsgstr \"用兩根手指點兩下\"\n\n#: lib/logitech_receiver/settings_templates.py:1280\nmsgid \"Double tap with three fingers\"\nmsgstr \"用三根手指點兩下\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Drags items by dragging the finger after double tapping.\"\nmsgstr \"點兩下後拖曳手指來拖曳項目。\"\n\n#: lib/logitech_receiver/settings_templates.py:1283\nmsgid \"Tap and drag\"\nmsgstr \"點選並拖曳\"\n\n#: lib/logitech_receiver/settings_templates.py:1285\nmsgid \"Tap and drag with two fingers\"\nmsgstr \"用兩根手指點兩下並拖曳\"\n\n#: lib/logitech_receiver/settings_templates.py:1286\nmsgid \"Drags items by dragging the fingers after double tapping.\"\nmsgstr \"點兩下後拖曳手指來拖曳項目。\"\n\n#: lib/logitech_receiver/settings_templates.py:1288\nmsgid \"Tap and drag with three fingers\"\nmsgstr \"用三根手指點選並拖曳\"\n\n#: lib/logitech_receiver/settings_templates.py:1291\nmsgid \"Suppress tap and edge gestures\"\nmsgstr \"停用輕觸和邊緣手勢\"\n\n#: lib/logitech_receiver/settings_templates.py:1292\nmsgid \"Disables tap and edge gestures (equivalent to pressing Fn+LeftClick).\"\nmsgstr \"停用輕觸和邊緣手勢（相當於按下 Fn+左鍵點選）。\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\nmsgid \"Scroll with one finger\"\nmsgstr \"用一根手指捲動\"\n\n#: lib/logitech_receiver/settings_templates.py:1294\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scrolls.\"\nmsgstr \"捲動。\"\n\n#: lib/logitech_receiver/settings_templates.py:1295\n#: lib/logitech_receiver/settings_templates.py:1298\nmsgid \"Scroll with two fingers\"\nmsgstr \"用兩根手指捲動\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scroll horizontally with two fingers\"\nmsgstr \"用兩根手指水平捲動\"\n\n#: lib/logitech_receiver/settings_templates.py:1296\nmsgid \"Scrolls horizontally.\"\nmsgstr \"水平捲動。\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scroll vertically with two fingers\"\nmsgstr \"用兩根手指垂直捲動\"\n\n#: lib/logitech_receiver/settings_templates.py:1297\nmsgid \"Scrolls vertically.\"\nmsgstr \"垂直捲動。\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Inverts the scrolling direction.\"\nmsgstr \"反轉捲動方向。\"\n\n#: lib/logitech_receiver/settings_templates.py:1299\nmsgid \"Natural scrolling\"\nmsgstr \"自然捲動\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Enables the thumbwheel.\"\nmsgstr \"啟用拇指滾輪。\"\n\n#: lib/logitech_receiver/settings_templates.py:1300\nmsgid \"Thumbwheel\"\nmsgstr \"拇指滾輪\"\n\n#: lib/logitech_receiver/settings_templates.py:1311\n#: lib/logitech_receiver/settings_templates.py:1315\nmsgid \"Swipe from the top edge\"\nmsgstr \"從上緣滑動\"\n\n#: lib/logitech_receiver/settings_templates.py:1312\nmsgid \"Swipe from the left edge\"\nmsgstr \"從左緣滑動\"\n\n#: lib/logitech_receiver/settings_templates.py:1313\nmsgid \"Swipe from the right edge\"\nmsgstr \"從右緣滑動\"\n\n#: lib/logitech_receiver/settings_templates.py:1314\nmsgid \"Swipe from the bottom edge\"\nmsgstr \"從下緣滑動\"\n\n#: lib/logitech_receiver/settings_templates.py:1316\nmsgid \"Swipe two fingers from the left edge\"\nmsgstr \"從左緣滑動兩根手指\"\n\n#: lib/logitech_receiver/settings_templates.py:1317\nmsgid \"Swipe two fingers from the right edge\"\nmsgstr \"從右緣滑動兩根手指\"\n\n#: lib/logitech_receiver/settings_templates.py:1318\nmsgid \"Swipe two fingers from the bottom edge\"\nmsgstr \"從下緣滑動兩根手指\"\n\n#: lib/logitech_receiver/settings_templates.py:1319\nmsgid \"Swipe two fingers from the top edge\"\nmsgstr \"從上緣滑動兩根手指\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Pinch to zoom out; spread to zoom in.\"\nmsgstr \"捏合以縮小；張開以放大。\"\n\n#: lib/logitech_receiver/settings_templates.py:1320\nmsgid \"Zoom with two fingers.\"\nmsgstr \"用兩根手指縮放。\"\n\n#: lib/logitech_receiver/settings_templates.py:1321\nmsgid \"Pinch to zoom out.\"\nmsgstr \"捏合以縮小。\"\n\n#: lib/logitech_receiver/settings_templates.py:1322\nmsgid \"Spread to zoom in.\"\nmsgstr \"張開以放大。\"\n\n#: lib/logitech_receiver/settings_templates.py:1323\nmsgid \"Zoom with three fingers.\"\nmsgstr \"用三根手指縮放。\"\n\n#: lib/logitech_receiver/settings_templates.py:1324\nmsgid \"Zoom with two fingers\"\nmsgstr \"用兩根手指縮放\"\n\n#: lib/logitech_receiver/settings_templates.py:1342\nmsgid \"Pixel zone\"\nmsgstr \"像素區域\"\n\n#: lib/logitech_receiver/settings_templates.py:1343\nmsgid \"Ratio zone\"\nmsgstr \"比例區域\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Scale factor\"\nmsgstr \"縮放係數\"\n\n#: lib/logitech_receiver/settings_templates.py:1344\nmsgid \"Sets the cursor speed.\"\nmsgstr \"設定游標速度。\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left\"\nmsgstr \"左\"\n\n#: lib/logitech_receiver/settings_templates.py:1348\nmsgid \"Left-most coordinate.\"\nmsgstr \"最左邊的座標。\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom\"\nmsgstr \"底部\"\n\n#: lib/logitech_receiver/settings_templates.py:1349\nmsgid \"Bottom coordinate.\"\nmsgstr \"底部座標。\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width\"\nmsgstr \"寬度\"\n\n#: lib/logitech_receiver/settings_templates.py:1350\nmsgid \"Width.\"\nmsgstr \"寬度。\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height\"\nmsgstr \"高度\"\n\n#: lib/logitech_receiver/settings_templates.py:1351\nmsgid \"Height.\"\nmsgstr \"高度。\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Cursor speed.\"\nmsgstr \"游標速度。\"\n\n#: lib/logitech_receiver/settings_templates.py:1352\nmsgid \"Scale\"\nmsgstr \"縮放\"\n\n#: lib/logitech_receiver/settings_templates.py:1358\nmsgid \"Gestures\"\nmsgstr \"手勢\"\n\n#: lib/logitech_receiver/settings_templates.py:1359\nmsgid \"Tweak the mouse/touchpad behaviour.\"\nmsgstr \"調整滑鼠/觸控板行為。\"\n\n#: lib/logitech_receiver/settings_templates.py:1375\nmsgid \"Gestures Diversion\"\nmsgstr \"手勢轉換\"\n\n#: lib/logitech_receiver/settings_templates.py:1376\nmsgid \"Divert mouse/touchpad gestures.\"\nmsgstr \"轉換滑鼠/觸控板手勢。\"\n\n#: lib/logitech_receiver/settings_templates.py:1392\nmsgid \"Gesture params\"\nmsgstr \"手勢參數\"\n\n#: lib/logitech_receiver/settings_templates.py:1393\nmsgid \"Change numerical parameters of a mouse/touchpad.\"\nmsgstr \"變更滑鼠/觸控板的數值參數。\"\n\n#: lib/logitech_receiver/settings_templates.py:1417\nmsgid \"M-Key LEDs\"\nmsgstr \"M 鍵 LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1419\nmsgid \"Control the M-Key LEDs.\"\nmsgstr \"控制 M 鍵 LED。\"\n\n#: lib/logitech_receiver/settings_templates.py:1423\n#: lib/logitech_receiver/settings_templates.py:1454\nmsgid \"May need G Keys diverted to be effective.\"\nmsgstr \"可能需要轉向 G 鍵才能生效。\"\n\n#: lib/logitech_receiver/settings_templates.py:1429\n#, python-format\nmsgid \"Lights up the %s key.\"\nmsgstr \"點亮 %s 鍵。\"\n\n#: lib/logitech_receiver/settings_templates.py:1448\nmsgid \"MR-Key LED\"\nmsgstr \"MR 鍵 LED\"\n\n#: lib/logitech_receiver/settings_templates.py:1450\nmsgid \"Control the MR-Key LED.\"\nmsgstr \"控制 MR 鍵 LED。\"\n\n#: lib/logitech_receiver/settings_templates.py:1471\nmsgid \"Persistent Key/Button Mapping\"\nmsgstr \"持久按鍵/按鈕對應\"\n\n#: lib/logitech_receiver/settings_templates.py:1473\nmsgid \"Permanently change the mapping for the key or button.\"\nmsgstr \"永久變更按鍵或按鈕的對應。\"\n\n#: lib/logitech_receiver/settings_templates.py:1475\nmsgid \"\"\n\"Changing important keys or buttons (such as for the left mouse button) can \"\n\"result in an unusable system.\"\nmsgstr \"變更重要的按鍵或按鈕（例如滑鼠左鍵）可能會導致系統無法使用。\"\n\n#: lib/logitech_receiver/settings_templates.py:1532\nmsgid \"Sidetone\"\nmsgstr \"側音\"\n\n#: lib/logitech_receiver/settings_templates.py:1533\nmsgid \"Set sidetone level.\"\nmsgstr \"設定側音等級。\"\n\n#: lib/logitech_receiver/settings_templates.py:1542\nmsgid \"Equalizer\"\nmsgstr \"均衡器\"\n\n#: lib/logitech_receiver/settings_templates.py:1543\nmsgid \"Set equalizer levels.\"\nmsgstr \"設定等化器等級。\"\n\n#: lib/logitech_receiver/settings_templates.py:1565\nmsgid \"Hz\"\nmsgstr \"Hz\"\n\n#: lib/logitech_receiver/settings_templates.py:1571\nmsgid \"Power Management\"\nmsgstr \"電源管理\"\n\n#: lib/logitech_receiver/settings_templates.py:1572\nmsgid \"Power off in minutes (0 for never).\"\nmsgstr \"幾分鐘後關機（0 表示永不關機）。\"\n\n#: lib/logitech_receiver/settings_templates.py:1584\nmsgid \"Brightness Control\"\nmsgstr \"亮度控制\"\n\n#: lib/logitech_receiver/settings_templates.py:1585\nmsgid \"Control overall brightness\"\nmsgstr \"控制整體亮度\"\n\n#: lib/logitech_receiver/settings_templates.py:1628\n#: lib/logitech_receiver/settings_templates.py:1681\nmsgid \"LED Control\"\nmsgstr \"LED 控制\"\n\n#: lib/logitech_receiver/settings_templates.py:1629\n#: lib/logitech_receiver/settings_templates.py:1682\nmsgid \"Switch control of LED zones between device and Solaar\"\nmsgstr \"在裝置與 Solaar 之間切換 LED 區域控制\"\n\n#: lib/logitech_receiver/settings_templates.py:1644\n#: lib/logitech_receiver/settings_templates.py:1692\nmsgid \"LED Zone Effects\"\nmsgstr \"LED 區域效果\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"LED Control needs to be set to Solaar to be effective.\"\nmsgstr \"需要將 LED 控制設為 Solaar 才能生效。\"\n\n#: lib/logitech_receiver/settings_templates.py:1645\n#: lib/logitech_receiver/settings_templates.py:1693\nmsgid \"Set effect for LED Zone\"\nmsgstr \"設定 LED 區域的效果\"\n\n#: lib/logitech_receiver/settings_templates.py:1647\nmsgid \"Color\"\nmsgstr \"顏色\"\n\n#: lib/logitech_receiver/settings_templates.py:1648\nmsgid \"Speed\"\nmsgstr \"速度\"\n\n#: lib/logitech_receiver/settings_templates.py:1649\nmsgid \"Period\"\nmsgstr \"週期\"\n\n#: lib/logitech_receiver/settings_templates.py:1650\nmsgid \"Intensity\"\nmsgstr \"強度\"\n\n#: lib/logitech_receiver/settings_templates.py:1651\nmsgid \"Ramp\"\nmsgstr \"漸變\"\n\n#: lib/logitech_receiver/settings_templates.py:1666\nmsgid \"LEDs\"\nmsgstr \"LED 燈\"\n\n#: lib/logitech_receiver/settings_templates.py:1703\nmsgid \"Per-key Lighting\"\nmsgstr \"單鍵照明\"\n\n#: lib/logitech_receiver/settings_templates.py:1704\nmsgid \"Control per-key lighting.\"\nmsgstr \"控制單鍵照明。\"\n\n#: lib/logitech_receiver/settings_templates.py:1786\nmsgid \"Force Sensing Buttons\"\nmsgstr \"力道感測按鈕\"\n\n#: lib/logitech_receiver/settings_templates.py:1787\nmsgid \"Change the force required to activate button.\"\nmsgstr \"調整觸發按鈕所需的力道。\"\n\n#: lib/logitech_receiver/settings_templates.py:1804\nmsgid \"Force Sensing Button\"\nmsgstr \"力道感測按鈕\"\n\n#: lib/logitech_receiver/settings_templates.py:1814\nmsgid \"Haptic Feeback Level\"\nmsgstr \"觸覺回饋等級\"\n\n#: lib/logitech_receiver/settings_templates.py:1815\nmsgid \"Change power of haptic feedback.  (Zero to turn off.)\"\nmsgstr \"變更觸覺回饋的力度，設為 0 可關閉。\"\n\n#: lib/logitech_receiver/settings_templates.py:1857\nmsgid \"Play Haptic Waveform\"\nmsgstr \"播放觸覺波形\"\n\n#: lib/logitech_receiver/settings_templates.py:1858\nmsgid \"Tell device to play a haptic waveform.\"\nmsgstr \"指示裝置播放觸覺波形。\"\n\n#: lib/solaar/ui/__init__.py:120\nmsgid \"Another Solaar process is already running so just expose its window\"\nmsgstr \"已有另一個 Solaar 處理程序正在執行，因此將會顯示其視窗\"\n\n#: lib/solaar/ui/about/model.py:36\nmsgid \"\"\n\"Manages Logitech receivers,\\n\"\n\"keyboards, mice, and tablets.\"\nmsgstr \"\"\n\"管理羅技接收器、\\n\"\n\"鍵盤、滑鼠和平板電腦。\"\n\n#: lib/solaar/ui/about/model.py:63\nmsgid \"Additional Programming\"\nmsgstr \"額外程式設計\"\n\n#: lib/solaar/ui/about/model.py:64\nmsgid \"GUI design\"\nmsgstr \"圖形介面設計\"\n\n#: lib/solaar/ui/about/model.py:66\nmsgid \"Testing\"\nmsgstr \"測試\"\n\n#: lib/solaar/ui/about/model.py:74\nmsgid \"Logitech documentation\"\nmsgstr \"羅技說明文件\"\n\n#: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92\n#: lib/solaar/ui/window.py:208\nmsgid \"Unpair\"\nmsgstr \"取消配對\"\n\n#: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141\nmsgid \"Cancel\"\nmsgstr \"取消\"\n\n#: lib/solaar/ui/common.py:42\nmsgid \"Permissions error\"\nmsgstr \"權限錯誤\"\n\n#: lib/solaar/ui/common.py:44\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device (%s), but did not have permission to \"\n\"open it.\"\nmsgstr \"找到羅技接收器或裝置 (%s)，但沒有權限開啟。\"\n\n#: lib/solaar/ui/common.py:46\nmsgid \"\"\n\"If you've just installed Solaar, try disconnecting the receiver or device \"\n\"and then reconnecting it.\"\nmsgstr \"若剛安裝 Solaar，請嘗試中斷接收器或裝置的連線，然後重新連接。\"\n\n#: lib/solaar/ui/common.py:49\nmsgid \"Cannot connect to device error\"\nmsgstr \"無法連接到裝置錯誤\"\n\n#: lib/solaar/ui/common.py:51\n#, python-format\nmsgid \"\"\n\"Found a Logitech receiver or device at %s, but encountered an error \"\n\"connecting to it.\"\nmsgstr \"在 %s 找到羅技接收器或裝置，但連接時發生錯誤。\"\n\n#: lib/solaar/ui/common.py:53\nmsgid \"\"\n\"Try disconnecting the device and then reconnecting it or turning it off and \"\n\"then on.\"\nmsgstr \"請嘗試中斷裝置連線然後重新連接，或將其關閉後再開啟。\"\n\n#: lib/solaar/ui/common.py:56\nmsgid \"Unpairing failed\"\nmsgstr \"取消配對失敗\"\n\n#: lib/solaar/ui/common.py:58\n#, python-brace-format\nmsgid \"Failed to unpair %{device} from %{receiver}.\"\nmsgstr \"無法取消 %{device} 與 %{receiver} 的配對。\"\n\n#: lib/solaar/ui/common.py:63\nmsgid \"The receiver returned an error, with no further details.\"\nmsgstr \"接收器傳回錯誤，未提供進一步詳細資訊。\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Complete - ENTER to change\"\nmsgstr \"完成 - 按 ENTER 鍵變更\"\n\n#: lib/solaar/ui/config_panel.py:245\nmsgid \"Incomplete\"\nmsgstr \"未完成\"\n\n#: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543\n#, python-format\nmsgid \"%d value\"\nmsgid_plural \"%d values\"\nmsgstr[0] \"%d 個值\"\n\n#: lib/solaar/ui/config_panel.py:642\nmsgid \"Changes allowed\"\nmsgstr \"允許變更\"\n\n#: lib/solaar/ui/config_panel.py:643\nmsgid \"No changes allowed\"\nmsgstr \"不允許變更\"\n\n#: lib/solaar/ui/config_panel.py:644\nmsgid \"Ignore this setting\"\nmsgstr \"忽略此設定\"\n\n#: lib/solaar/ui/config_panel.py:690\nmsgid \"Working\"\nmsgstr \"工作中\"\n\n#: lib/solaar/ui/config_panel.py:693\nmsgid \"Read/write operation failed.\"\nmsgstr \"讀取/寫入操作失敗。\"\n\n#: lib/solaar/ui/desktop_notifications.py:112\nmsgid \"unspecified reason\"\nmsgstr \"未指定原因\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"Built-in rules\"\nmsgstr \"內建規則\"\n\n#: lib/solaar/ui/diversion_rules.py:103\nmsgid \"User-defined rules\"\nmsgstr \"使用者定義規則\"\n\n#: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126\nmsgid \"Rule\"\nmsgstr \"規則\"\n\n#: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382\n#: lib/solaar/ui/diversion_rules.py:509\nmsgid \"Sub-rule\"\nmsgstr \"子規則\"\n\n#: lib/solaar/ui/diversion_rules.py:108\nmsgid \"[empty]\"\nmsgstr \"[空白]\"\n\n#: lib/solaar/ui/diversion_rules.py:132\nmsgid \"Make changes permanent?\"\nmsgstr \"要永久套用變更嗎？\"\n\n#: lib/solaar/ui/diversion_rules.py:137\nmsgid \"Yes\"\nmsgstr \"是\"\n\n#: lib/solaar/ui/diversion_rules.py:139\nmsgid \"No\"\nmsgstr \"否\"\n\n#: lib/solaar/ui/diversion_rules.py:144\nmsgid \"If you choose No, changes will be lost when Solaar is closed.\"\nmsgstr \"若選擇否，關閉 Solaar 時將會遺失變更。\"\n\n#: lib/solaar/ui/diversion_rules.py:273\nmsgid \"Paste here\"\nmsgstr \"在此貼上\"\n\n#: lib/solaar/ui/diversion_rules.py:275\nmsgid \"Paste above\"\nmsgstr \"在上方貼上\"\n\n#: lib/solaar/ui/diversion_rules.py:277\nmsgid \"Paste below\"\nmsgstr \"在下方貼上\"\n\n#: lib/solaar/ui/diversion_rules.py:283\nmsgid \"Paste rule here\"\nmsgstr \"在此貼上規則\"\n\n#: lib/solaar/ui/diversion_rules.py:285\nmsgid \"Paste rule above\"\nmsgstr \"在上方貼上規則\"\n\n#: lib/solaar/ui/diversion_rules.py:287\nmsgid \"Paste rule below\"\nmsgstr \"在下方貼上規則\"\n\n#: lib/solaar/ui/diversion_rules.py:291\nmsgid \"Paste rule\"\nmsgstr \"貼上規則\"\n\n#: lib/solaar/ui/diversion_rules.py:306\nmsgid \"Insert here\"\nmsgstr \"在此插入\"\n\n#: lib/solaar/ui/diversion_rules.py:308\nmsgid \"Insert above\"\nmsgstr \"在上方插入\"\n\n#: lib/solaar/ui/diversion_rules.py:310\nmsgid \"Insert below\"\nmsgstr \"在下方插入\"\n\n#: lib/solaar/ui/diversion_rules.py:316\nmsgid \"Insert new rule here\"\nmsgstr \"在此插入新規則\"\n\n#: lib/solaar/ui/diversion_rules.py:318\nmsgid \"Insert new rule above\"\nmsgstr \"在上方插入新規則\"\n\n#: lib/solaar/ui/diversion_rules.py:320\nmsgid \"Insert new rule below\"\nmsgstr \"在下方插入新規則\"\n\n#: lib/solaar/ui/diversion_rules.py:347\nmsgid \"Flatten\"\nmsgstr \"平面化\"\n\n#: lib/solaar/ui/diversion_rules.py:380\nmsgid \"Insert\"\nmsgstr \"插入\"\n\n#: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511\n#: lib/solaar/ui/diversion_rules.py:1158\nmsgid \"Or\"\nmsgstr \"或\"\n\n#: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510\n#: lib/solaar/ui/diversion_rules.py:1144\nmsgid \"And\"\nmsgstr \"且\"\n\n#: lib/solaar/ui/diversion_rules.py:386\nmsgid \"Condition\"\nmsgstr \"條件\"\n\n#: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154\nmsgid \"Feature\"\nmsgstr \"功能\"\n\n#: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188\nmsgid \"Report\"\nmsgstr \"回報\"\n\n#: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69\nmsgid \"Process\"\nmsgstr \"處理程序\"\n\n#: lib/solaar/ui/diversion_rules.py:391\nmsgid \"Mouse process\"\nmsgstr \"滑鼠處理程序\"\n\n#: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225\nmsgid \"Modifiers\"\nmsgstr \"修飾鍵\"\n\n#: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277\nmsgid \"Key\"\nmsgstr \"按鍵\"\n\n#: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318\nmsgid \"KeyIsDown\"\nmsgstr \"按鍵處於按下狀態\"\n\n#: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432\nmsgid \"Active\"\nmsgstr \"使用中\"\n\n#: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390\n#: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487\nmsgid \"Device\"\nmsgstr \"裝置\"\n\n#: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467\nmsgid \"Host\"\nmsgstr \"主機\"\n\n#: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506\nmsgid \"Setting\"\nmsgstr \"設定\"\n\n#: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333\n#: lib/solaar/ui/rule_conditions.py:382\nmsgid \"Test\"\nmsgstr \"測試\"\n\n#: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507\nmsgid \"Test bytes\"\nmsgstr \"測試位元組\"\n\n#: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608\nmsgid \"Mouse Gesture\"\nmsgstr \"滑鼠手勢\"\n\n#: lib/solaar/ui/diversion_rules.py:405\nmsgid \"Action\"\nmsgstr \"動作\"\n\n#: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138\nmsgid \"Key press\"\nmsgstr \"按鍵按下\"\n\n#: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191\nmsgid \"Mouse scroll\"\nmsgstr \"滑鼠捲動\"\n\n#: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256\nmsgid \"Mouse click\"\nmsgstr \"滑鼠點選\"\n\n#: lib/solaar/ui/diversion_rules.py:410\nmsgid \"Set\"\nmsgstr \"設定\"\n\n#: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328\nmsgid \"Execute\"\nmsgstr \"執行\"\n\n#: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189\nmsgid \"Later\"\nmsgstr \"稍後\"\n\n#: lib/solaar/ui/diversion_rules.py:441\nmsgid \"Insert new rule\"\nmsgstr \"插入新規則\"\n\n#: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82\n#: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556\nmsgid \"Delete\"\nmsgstr \"刪除\"\n\n#: lib/solaar/ui/diversion_rules.py:483\nmsgid \"Negate\"\nmsgstr \"否定\"\n\n#: lib/solaar/ui/diversion_rules.py:507\nmsgid \"Wrap with\"\nmsgstr \"包裝為\"\n\n#: lib/solaar/ui/diversion_rules.py:537\nmsgid \"Cut\"\nmsgstr \"剪下\"\n\n#: lib/solaar/ui/diversion_rules.py:553\nmsgid \"Paste\"\nmsgstr \"貼上\"\n\n#: lib/solaar/ui/diversion_rules.py:559\nmsgid \"Copy\"\nmsgstr \"複製\"\n\n#: lib/solaar/ui/diversion_rules.py:568\nmsgid \"Solaar Rule Editor\"\nmsgstr \"Solaar 規則編輯器\"\n\n#: lib/solaar/ui/diversion_rules.py:668\nmsgid \"Save changes\"\nmsgstr \"儲存變更\"\n\n#: lib/solaar/ui/diversion_rules.py:673\nmsgid \"Discard changes\"\nmsgstr \"捨棄變更\"\n\n#: lib/solaar/ui/diversion_rules.py:1104\nmsgid \"This editor does not support the selected rule component yet.\"\nmsgstr \"此編輯器尚未支援所選的規則元件。\"\n\n#: lib/solaar/ui/diversion_rules.py:1169\nmsgid \"\"\n\"Number of seconds to delay.  Delay between 0 and 1 is done with higher \"\n\"precision.\"\nmsgstr \"延遲的秒數。0 到 1 秒之間的延遲會以較高的精確度執行。\"\n\n#: lib/solaar/ui/diversion_rules.py:1207\nmsgid \"Not\"\nmsgstr \"非\"\n\n#: lib/solaar/ui/diversion_rules.py:1238\nmsgid \"Toggle\"\nmsgstr \"切換\"\n\n#: lib/solaar/ui/diversion_rules.py:1239\nmsgid \"True\"\nmsgstr \"真\"\n\n#: lib/solaar/ui/diversion_rules.py:1240\nmsgid \"False\"\nmsgstr \"假\"\n\n#: lib/solaar/ui/diversion_rules.py:1253\nmsgid \"Unsupported setting\"\nmsgstr \"不支援的設定\"\n\n#: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415\n#: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748\n#: lib/solaar/ui/diversion_rules.py:1766\nmsgid \"Originating device\"\nmsgstr \"來源裝置\"\n\n#: lib/solaar/ui/diversion_rules.py:1428\nmsgid \"Device is active and its settings can be changed.\"\nmsgstr \"裝置處於使用中狀態，可以變更其設定。\"\n\n#: lib/solaar/ui/diversion_rules.py:1437\nmsgid \"Device that originated the current notification.\"\nmsgstr \"產生目前通知的裝置。\"\n\n#: lib/solaar/ui/diversion_rules.py:1450\nmsgid \"Name of host computer.\"\nmsgstr \"主機電腦名稱。\"\n\n#: lib/solaar/ui/diversion_rules.py:1520\nmsgid \"Value\"\nmsgstr \"值\"\n\n#: lib/solaar/ui/diversion_rules.py:1529\nmsgid \"Item\"\nmsgstr \"項目\"\n\n#: lib/solaar/ui/diversion_rules.py:1808\nmsgid \"Change setting on device\"\nmsgstr \"變更裝置上的設定\"\n\n#: lib/solaar/ui/diversion_rules.py:1824\nmsgid \"Setting on device\"\nmsgstr \"裝置上的設定\"\n\n#: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167\n#, python-format\nmsgid \"%(receiver_name)s: pair new device\"\nmsgstr \"%(receiver_name)s：配對新的裝置\"\n\n#: lib/solaar/ui/pair_window.py:46\nmsgid \"Bolt receivers are only compatible with Bolt devices.\"\nmsgstr \"Bolt 接收器僅相容於 Bolt 裝置。\"\n\n#: lib/solaar/ui/pair_window.py:48\nmsgid \"Press a pairing button or key until the pairing light flashes quickly.\"\nmsgstr \"請按住配對按鈕或按鍵，直到配對指示燈快速閃爍。\"\n\n#: lib/solaar/ui/pair_window.py:51\nmsgid \"Unifying receivers are only compatible with Unifying devices.\"\nmsgstr \"Unifying 接收器僅相容於 Unifying 裝置。\"\n\n#: lib/solaar/ui/pair_window.py:53\nmsgid \"Other receivers are only compatible with a few devices.\"\nmsgstr \"其他接收器僅支援少數裝置。\"\n\n#: lib/solaar/ui/pair_window.py:55\nmsgid \"For most devices, turn on the device you want to pair.\"\nmsgstr \"多數裝置只要開啟想要配對的裝置即可。\"\n\n#: lib/solaar/ui/pair_window.py:56\nmsgid \"If the device is already turned on, turn it off and on again.\"\nmsgstr \"若裝置已開啟，請將其關閉後再重新開啟。\"\n\n#: lib/solaar/ui/pair_window.py:58\nmsgid \"The device must not be paired with a nearby powered-on receiver.\"\nmsgstr \"裝置不得與附近已開啟的接收器配對。\"\n\n#: lib/solaar/ui/pair_window.py:61\nmsgid \"\"\n\"For devices with multiple channels, press, hold, and release the button for \"\n\"the channel you wish to pair\\n\"\n\"or use the channel switch button to select a channel and then press, hold, \"\n\"and release the channel switch button.\"\nmsgstr \"\"\n\"對於有多個通道的裝置，請按住並放開想要配對通道的按鈕，\\n\"\n\"或使用通道切換按鈕選擇通道後，再按住並放開通道切換按鈕。\"\n\n#: lib/solaar/ui/pair_window.py:68\nmsgid \"The channel indicator light should be blinking rapidly.\"\nmsgstr \"通道指示燈應會快速閃爍。\"\n\n#: lib/solaar/ui/pair_window.py:72\n#, python-format\nmsgid \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairing remaining.\"\nmsgid_plural \"\"\n\"\\n\"\n\"\\n\"\n\"This receiver has %d pairings remaining.\"\nmsgstr[0] \"\"\n\"\\n\"\n\"\\n\"\n\"此接收器剩餘 %d 次配對。\"\n\n#: lib/solaar/ui/pair_window.py:78\nmsgid \"\"\n\"\\n\"\n\"Cancelling at this point will not use up a pairing.\"\nmsgstr \"\"\n\"\\n\"\n\"在此階段取消不會消耗配對次數。\"\n\n#: lib/solaar/ui/pair_window.py:168\n#, python-format\nmsgid \"Enter passcode on %(name)s.\"\nmsgstr \"請在 %(name)s 上輸入密碼。\"\n\n#: lib/solaar/ui/pair_window.py:171\n#, python-format\nmsgid \"Type %(passcode)s and then press the enter key.\"\nmsgstr \"請輸入 %(passcode)s，然後按 Enter 鍵。\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"left\"\nmsgstr \"左\"\n\n#: lib/solaar/ui/pair_window.py:176\nmsgid \"right\"\nmsgstr \"右\"\n\n#: lib/solaar/ui/pair_window.py:178\n#, python-format\nmsgid \"\"\n\"Press %(code)s\\n\"\n\"and then press left and right buttons simultaneously.\"\nmsgstr \"\"\n\"請按下 %(code)s\\n\"\n\"然後同時按下左鍵和右鍵。\"\n\n#: lib/solaar/ui/pair_window.py:221\nmsgid \"The wireless link is not encrypted\"\nmsgstr \"無線連線未加密\"\n\n#: lib/solaar/ui/pair_window.py:226\nmsgid \"Found a new device:\"\nmsgstr \"發現一個新裝置：\"\n\n#: lib/solaar/ui/pair_window.py:247\nmsgid \"Pairing failed\"\nmsgstr \"配對失敗\"\n\n#: lib/solaar/ui/pair_window.py:249\nmsgid \"Make sure your device is within range, and has a decent battery charge.\"\nmsgstr \"請確認裝置在範圍內，且電池電量充足。\"\n\n#: lib/solaar/ui/pair_window.py:251\nmsgid \"A new device was detected, but it is not compatible with this receiver.\"\nmsgstr \"偵測到新裝置，但與此接收器不相容。\"\n\n#: lib/solaar/ui/pair_window.py:253\nmsgid \"More paired devices than receiver can support.\"\nmsgstr \"已配對的裝置數量超過接收器可支援的數量。\"\n\n#: lib/solaar/ui/pair_window.py:255\nmsgid \"No further details are available about the error.\"\nmsgstr \"沒有關於此錯誤的進一步詳細資訊。\"\n\n#: lib/solaar/ui/rule_actions.py:54\nmsgid \"\"\n\"Simulate a chorded key click or depress or release.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"模擬組合鍵點選或按下或放開。\\n\"\n\"在 Wayland 上需要對 /dev/uinput 的寫入權限。\"\n\n#: lib/solaar/ui/rule_actions.py:60\nmsgid \"Add key\"\nmsgstr \"新增按鍵\"\n\n#: lib/solaar/ui/rule_actions.py:63\nmsgid \"Click\"\nmsgstr \"點選\"\n\n#: lib/solaar/ui/rule_actions.py:66\nmsgid \"Depress\"\nmsgstr \"按下\"\n\n#: lib/solaar/ui/rule_actions.py:69\nmsgid \"Release\"\nmsgstr \"放開\"\n\n#: lib/solaar/ui/rule_actions.py:153\nmsgid \"\"\n\"Simulate a mouse scroll.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"模擬滑鼠捲動。\\n\"\n\"在 Wayland 上需要對 /dev/uinput 的寫入權限。\"\n\n#: lib/solaar/ui/rule_actions.py:211\nmsgid \"\"\n\"Simulate a mouse click.\\n\"\n\"On Wayland requires write access to /dev/uinput.\"\nmsgstr \"\"\n\"模擬滑鼠點選。\\n\"\n\"在 Wayland 上需要對 /dev/uinput 的寫入權限。\"\n\n#: lib/solaar/ui/rule_actions.py:216\nmsgid \"Button\"\nmsgstr \"按鈕\"\n\n#: lib/solaar/ui/rule_actions.py:218\nmsgid \"Action (and Count, if click)\"\nmsgstr \"動作（若為點選則含次數）\"\n\n#: lib/solaar/ui/rule_actions.py:269\nmsgid \"Execute a command with arguments.\"\nmsgstr \"執行帶有參數的命令。\"\n\n#: lib/solaar/ui/rule_actions.py:273\nmsgid \"Add argument\"\nmsgstr \"新增參數\"\n\n#: lib/solaar/ui/rule_conditions.py:52\nmsgid \"X11 active process. For use in X11 only.\"\nmsgstr \"X11 使用中處理程序。僅適用於 X11。\"\n\n#: lib/solaar/ui/rule_conditions.py:82\nmsgid \"X11 mouse process. For use in X11 only.\"\nmsgstr \"X11 滑鼠處理程序。僅適用於 X11。\"\n\n#: lib/solaar/ui/rule_conditions.py:99\nmsgid \"MouseProcess\"\nmsgstr \"滑鼠處理程序\"\n\n#: lib/solaar/ui/rule_conditions.py:123\nmsgid \"Feature name of notification triggering rule processing.\"\nmsgstr \"觸發規則處理的通知功能名稱。\"\n\n#: lib/solaar/ui/rule_conditions.py:169\nmsgid \"Report number of notification triggering rule processing.\"\nmsgstr \"回報觸發規則處理的通知數量。\"\n\n#: lib/solaar/ui/rule_conditions.py:201\nmsgid \"Active keyboard modifiers. Not always available in Wayland.\"\nmsgstr \"使用中的鍵盤修飾鍵。在 Wayland 中並非總是可用。\"\n\n#: lib/solaar/ui/rule_conditions.py:241\nmsgid \"\"\n\"Diverted key or button depressed or released.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"轉向按鍵或按鈕被按下或放開。\\n\"\n\"使用按鍵/按鈕轉向和轉向 G 鍵設定來轉向按鍵和按鈕。\"\n\n#: lib/solaar/ui/rule_conditions.py:250\nmsgid \"Key down\"\nmsgstr \"按鍵按下\"\n\n#: lib/solaar/ui/rule_conditions.py:253\nmsgid \"Key up\"\nmsgstr \"按鍵鬆開\"\n\n#: lib/solaar/ui/rule_conditions.py:293\nmsgid \"\"\n\"Diverted key or button is currently down.\\n\"\n\"Use the Key/Button Diversion and Divert G Keys settings to divert keys and \"\n\"buttons.\"\nmsgstr \"\"\n\"轉向按鍵或按鈕目前處於按下狀態。\\n\"\n\"使用按鍵/按鈕轉向和轉向 G 鍵設定來轉向按鍵和按鈕。\"\n\n#: lib/solaar/ui/rule_conditions.py:331\nmsgid \"Test condition on notification triggering rule processing.\"\nmsgstr \"在通知觸發規則處理上測試條件。\"\n\n#: lib/solaar/ui/rule_conditions.py:335\nmsgid \"Parameter\"\nmsgstr \"參數\"\n\n#: lib/solaar/ui/rule_conditions.py:408\nmsgid \"begin (inclusive)\"\nmsgstr \"開始（包含）\"\n\n#: lib/solaar/ui/rule_conditions.py:409\nmsgid \"end (exclusive)\"\nmsgstr \"結束（不包含）\"\n\n#: lib/solaar/ui/rule_conditions.py:417\nmsgid \"range\"\nmsgstr \"範圍\"\n\n#: lib/solaar/ui/rule_conditions.py:420\nmsgid \"minimum\"\nmsgstr \"最小值\"\n\n#: lib/solaar/ui/rule_conditions.py:421\nmsgid \"maximum\"\nmsgstr \"最大值\"\n\n#: lib/solaar/ui/rule_conditions.py:423\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d\"\nmsgstr \"位元組 %(0)d 到 %(1)d，範圍從 %(2)d 到 %(3)d\"\n\n#: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427\nmsgid \"mask\"\nmsgstr \"遮罩\"\n\n#: lib/solaar/ui/rule_conditions.py:428\n#, python-format\nmsgid \"bytes %(0)d to %(1)d, mask %(2)d\"\nmsgstr \"位元組 %(0)d 到 %(1)d，遮罩 %(2)d\"\n\n#: lib/solaar/ui/rule_conditions.py:437\nmsgid \"\"\n\"Bit or range test on bytes in notification message triggering rule \"\n\"processing.\"\nmsgstr \"在通知訊息觸發規則處理中對位元組進行位元或範圍測試。\"\n\n#: lib/solaar/ui/rule_conditions.py:447\nmsgid \"type\"\nmsgstr \"類型\"\n\n#: lib/solaar/ui/rule_conditions.py:535\nmsgid \"\"\n\"Mouse gesture with optional initiating button followed by zero or more mouse \"\n\"movements.\"\nmsgstr \"滑鼠手勢，可選擇性地帶有起始按鈕，後接零個或多個滑鼠移動。\"\n\n#: lib/solaar/ui/rule_conditions.py:541\nmsgid \"Add movement\"\nmsgstr \"新增移動\"\n\n#: lib/solaar/ui/tray.py:55\nmsgid \"No supported device found\"\nmsgstr \"找不到支援的裝置\"\n\n#: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328\n#, python-format\nmsgid \"About %s\"\nmsgstr \"關於 %s\"\n\n#: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326\n#, python-format\nmsgid \"Quit %s\"\nmsgstr \"結束 %s\"\n\n#: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281\nmsgid \"no receiver\"\nmsgstr \"無接收器\"\n\n#: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299\n#: lib/solaar/ui/window.py:728\nmsgid \"offline\"\nmsgstr \"離線\"\n\n#: lib/solaar/ui/tray.py:297\nmsgid \"no status\"\nmsgstr \"無狀態\"\n\n#: lib/solaar/ui/window.py:110\nmsgid \"Scanning\"\nmsgstr \"掃描中\"\n\n#: lib/solaar/ui/window.py:141\nmsgid \"Battery\"\nmsgstr \"電池\"\n\n#: lib/solaar/ui/window.py:144\nmsgid \"Wireless Link\"\nmsgstr \"無線連線\"\n\n#: lib/solaar/ui/window.py:148\nmsgid \"Lighting\"\nmsgstr \"亮度\"\n\n#: lib/solaar/ui/window.py:182\nmsgid \"Show Technical Details\"\nmsgstr \"顯示技術細節\"\n\n#: lib/solaar/ui/window.py:198\nmsgid \"Pair new device\"\nmsgstr \"配對新裝置\"\n\n#: lib/solaar/ui/window.py:216\nmsgid \"Select a device\"\nmsgstr \"請選擇裝置\"\n\n#: lib/solaar/ui/window.py:331\nmsgid \"Rule Editor\"\nmsgstr \"規則編輯器\"\n\n#: lib/solaar/ui/window.py:522\nmsgid \"Path\"\nmsgstr \"路徑\"\n\n#: lib/solaar/ui/window.py:524\nmsgid \"USB ID\"\nmsgstr \"USB ID\"\n\n#: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529\n#: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546\nmsgid \"Serial\"\nmsgstr \"序號\"\n\n#: lib/solaar/ui/window.py:533\nmsgid \"Index\"\nmsgstr \"索引\"\n\n#: lib/solaar/ui/window.py:535\nmsgid \"Wireless PID\"\nmsgstr \"無線 PID\"\n\n#: lib/solaar/ui/window.py:537\nmsgid \"Product ID\"\nmsgstr \"產品 ID\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Protocol\"\nmsgstr \"通訊協定\"\n\n#: lib/solaar/ui/window.py:539\nmsgid \"Unknown\"\nmsgstr \"不明\"\n\n#: lib/solaar/ui/window.py:541\nmsgid \"Polling rate\"\nmsgstr \"輪詢速率\"\n\n#: lib/solaar/ui/window.py:548\nmsgid \"Unit ID\"\nmsgstr \"單位 ID\"\n\n#: lib/solaar/ui/window.py:559\nmsgid \"none\"\nmsgstr \"無\"\n\n#: lib/solaar/ui/window.py:560\nmsgid \"Notifications\"\nmsgstr \"通知\"\n\n#: lib/solaar/ui/window.py:604\nmsgid \"No device paired.\"\nmsgstr \"沒有已配對的裝置。\"\n\n#: lib/solaar/ui/window.py:613\n#, python-format\nmsgid \"Up to %(max_count)s device can be paired to this receiver.\"\nmsgid_plural \"Up to %(max_count)s devices can be paired to this receiver.\"\nmsgstr[0] \"此接收器最多可配對 %(max_count)s 個裝置。\"\n\n#: lib/solaar/ui/window.py:620\nmsgid \"Only one device can be paired to this receiver.\"\nmsgstr \"此接收器只能配對一個裝置\"\n\n#: lib/solaar/ui/window.py:624\n#, python-format\nmsgid \"This receiver has %d pairing remaining.\"\nmsgid_plural \"This receiver has %d pairings remaining.\"\nmsgstr[0] \"此接收器剩餘 %d 次配對。\"\n\n#: lib/solaar/ui/window.py:681\nmsgid \"Battery Voltage\"\nmsgstr \"電池電壓\"\n\n#: lib/solaar/ui/window.py:683\nmsgid \"Voltage reported by battery\"\nmsgstr \"電池回報的電壓\"\n\n#: lib/solaar/ui/window.py:685\nmsgid \"Battery Level\"\nmsgstr \"電池電量\"\n\n#: lib/solaar/ui/window.py:687\nmsgid \"Approximate level reported by battery\"\nmsgstr \"電池回報的大約電量\"\n\n#: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696\nmsgid \"next reported \"\nmsgstr \"下一次回報的 \"\n\n#: lib/solaar/ui/window.py:697\nmsgid \" and next level to be reported.\"\nmsgstr \" 以及下一個將回報的等級。\"\n\n#: lib/solaar/ui/window.py:702\nmsgid \"last known\"\nmsgstr \"最後已知\"\n\n#: lib/solaar/ui/window.py:713\nmsgid \"encrypted\"\nmsgstr \"已加密\"\n\n#: lib/solaar/ui/window.py:715\nmsgid \"The wireless link between this device and its receiver is encrypted.\"\nmsgstr \"此裝置與其接收器之間的無線連線已加密。\"\n\n#: lib/solaar/ui/window.py:717\nmsgid \"not encrypted\"\nmsgstr \"未加密\"\n\n#: lib/solaar/ui/window.py:721\nmsgid \"\"\n\"The wireless link between this device and its receiver is not encrypted.\\n\"\n\"This is a security issue for pointing devices, and a major security issue \"\n\"for text-input devices.\"\nmsgstr \"\"\n\"此裝置與其接收器之間的無線連線未加密。\\n\"\n\"這對指向型裝置僅是安全性問題，對文字輸入裝置則是重大的安全性問題。\"\n\n#: lib/solaar/ui/window.py:737\n#, python-format\nmsgid \"%(light_level)d lux\"\nmsgstr \"%(light_level)d lux\"\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[tool.ruff]\nline-length = 127\ntarget-version = \"py37\"\n\n[tool.ruff.lint]\nselect = [\n    \"F\", # Pyflakes\n    \"E\", # pycodestyle\n    \"W\", # pycodestyle\n    \"B\", # flake8-bugbear\n    \"I\", # isort\n]\n\n[tool.ruff.lint.isort]\nforce-single-line = true\nlines-between-types = 1\n"
  },
  {
    "path": "release.sh",
    "content": "#!/usr/bin/env bash\n\nrepo=pwr-Solaar/Solaar\n\nusage() {\n    basename=\"$(basename $0)\"\n    cat <<HELP\nUsage: $basename [options]\nOptions:\n  --dry-run           Does everything except tagging\n  --help              Display this help and exit successfully\nHELP\n}\n\nwhile [ $# != 0 ]\ndo\n    case $1 in\n    --dry-run)\n        DRY_RUN=yes\n        ;;\n    --*)\n        echo \"\"\n        echo \"Error: unknown option: $1\"\n        echo \"\"\n        usage\n        exit 1\n        ;;\n    -*)\n        echo \"\"\n        echo \"Error: unknown option: $1\"\n        echo \"\"\n        usage\n        exit 1\n        ;;\n    esac\n\n    shift\ndone\n\nversion=$(cat lib/solaar/version)\n\nprerelease=false\necho $version | grep '.*rc.*' >/dev/null\n[ $? -eq 0 ] && prerelease=true\n\nstable_branch=stable\n\nref=$(git symbolic-ref HEAD)\n[ $? -ne 0 ] && echo 'Error: Failed current branch' && exit 1\nbranch=${ref##*/}\n\ncommit=$(git rev-list --max-count=1 HEAD)\n[ $? -ne 0 ] && echo 'Error: Failed to get HEAD' && exit 1\n\nremote=$(git config --get branch.$branch.remote)\n[ $? -ne 0 ] && echo 'Error: Failed to get remote' && exit 1\n\nremote_ref=$(git config --get branch.$branch.merge)\n[ $? -ne 0 ] && echo 'Error: Failed to get remote HEAD' && exit 1\nremote_branch=${remote_ref##*/}\n\ngithub_token=$(cat ~/.github-token)\n[ $? -ne 0 ] && echo 'Error: Failed to get github token (check ~/.github_token)' && exit 1\n\njq -V >/dev/null\n[ $? -ne 0 ] && echo 'Error: jq is not installed' && exit 1\n\necho -e \"\\n\\t** You are tagging a release for version $version **\\n\"\necho \"Version: $version\"\necho \"Commit: $commit\"\necho \"Pre-release: $prerelease\"\necho \"Remote: $remote\"\nif [ \"$branch\" == \"$remote_branch\" ]; then\n    echo \"Branch: $branch\"\nelse\n    echo \"Local branch: $branch\"\n    echo \"Remote branch: $remote_branch\"\nfi\n\necho -e '\\nPlease read RELEASE.md before continuing.\\n'\n\nread -p 'Are you sure you want to proceed? (y/n) ' -n 1 -r < /dev/tty\necho\n[[ ! $REPLY =~ ^[Yy]$ ]] && echo 'Release aborted.' && exit 1\n\nread -p 'Are you *really* sure you want to proceed? (y/n) ' -n 1 -r < /dev/tty\necho\n[[ ! $REPLY =~ ^[Yy]$ ]] && echo 'Release aborted.' && exit 1\n\n# Check if version is in the changelog\ngrep '^# '\"$version\" CHANGELOG.md >/dev/null\n[ $? -ne 0 ] && echo 'Error: Version is not present in the changelog' && exit 1\n\n# Check for uncommitted changes\ngit diff --quiet HEAD >/dev/null\n[ $? -ne 0 ] && echo -e '\\nError: Uncommitted changes found' && exit 1\n\n# Check if commit is a version bump\ngit show -s --format=%B HEAD | grep \"^release $version\">/dev/null\n#[ $? -ne 0 ] && echo -e '\\nError: Commit does not look like a version bump' && exit 1\n\n# Check if commit has been pushed to remote\nremote_commit=$(git rev-list --max-count=1 $remote/$branch)\n[ $? -ne 0 ] && echo -e '\\nError: Failed to get remote HEAD' && exit 1\n[ \"$commit\" != \"$remote_commit\" ] && echo -e '\\nError: Commit has not been pushed to the remote' && exit 1\n\n# Check if tag already exists\ngit rev-list --max-count=1 $version >/dev/null 2>/dev/null\n[ $? -eq 0 ] && echo -e '\\nError: Tag already exists' && exit 1\n\n# Check if tag already exists on remote\ngit ls-remote $remote | grep \"refs/tags/$version$\" >/dev/null\n[ $? -eq 0 ] && echo -e '\\nError: Tag already exists on remote' && exit 1\n\necho\n\n# Create tag\necho 'Creating tag...'\n{\n    echo \"release $version\"\n    echo\n    found=no\n    while read -r line; do\n        if [[ \"$line\" == \"# \"* ]]; then\n            [ \"$line\" == \"# $version\" ] && found=yes || found=no\n        fi\n        [ \"$found\" == 'yes' ] && [ \"${line:0:1}\" == '*' ] && echo \"$line\"\n    done < CHANGELOG.md\n} > /tmp/solaar-changelog\n[ -z \"$DRY_RUN\" ] && git tag -s $version -F /tmp/solaar-changelog >/dev/null || true\n[ $? -ne 0 ] && echo -e '\\nError: Failed to create tag' && exit 1\n\n# Push tag\necho 'Pushing tag...'\n[ -z \"$DRY_RUN\" ] && git push $remote $version >/dev/null || true\n[ $? -ne 0 ] && echo -e '\\nError: Failed to push tag' && exit 1\n\n# Point stable branch to latest version tag\necho 'Updating stable branch...'\nif [[ -z \"$DRY_RUN\" && $prerelease == \"false\" ]]\nthen\n    # Check if stable branch does not exist\n    git rev-list --max-count=1 $stable_branch >/dev/null 2>/dev/null\n    [ $? -ne 0 ] && echo -e '\\nWarning: Creating stable branch for a first time' && git branch $stable_branch\n    # Fast forward and push stable branch\n    git checkout $stable_branch\n    git merge --ff $version\n    git push $remote $stable_branch >/dev/null || true\n    git checkout $branch\nfi\n\n# Create github release\nbody() {\n    cat <<EOF\n{\n  \"tag_name\": \"$version\",\n  \"name\": \"$version\",\n  \"body\": \"$(awk '{printf \"%s\\\\n\", $0}' /tmp/solaar-changelog)\",\n  \"prerelease\": $prerelease,\n  \"draft\": false\n}\nEOF\n}\necho 'Creating github release...'\n##[ -z \"$DRY_RUN\" ] && url=$(curl -X POST --data \"$(body)\" \"https://api.github.com/repos/$repo/releases?access_token=$github_token\" 2>/dev/null | jq -r .html_url)\n[ -z \"$DRY_RUN\" ] && url=$(curl -H 'Authorization: $github_token' -X POST --data \"$(body)\" \"https://api.github.com/repos/$repo/releases\" 2>/dev/null | jq -r .html_url)\n\n[ -z \"$DRY_RUN\" ] && [ -z \"$url\" ] && echo -e '\\nError: Failed to create a github release' && exit 1\n\n[ -z \"$DRY_RUN\" ] && echo -e \"\\nRelease created: $url\"\n\nrm /tmp/solaar-changelog\n"
  },
  {
    "path": "rules.d/42-logitech-unify-permissions.rules",
    "content": "# This rule was added by Solaar.\n#\n# Allows non-root users to have raw access to Logitech devices.\n# Allowing users to write to the device is potentially dangerous\n# because they could perform firmware updates.\nKERNEL==\"uinput\", SUBSYSTEM==\"misc\", TAG+=\"uaccess\", OPTIONS+=\"static_node=uinput\"\n\nACTION == \"remove\", GOTO=\"solaar_end\"\nSUBSYSTEM != \"hidraw\", GOTO=\"solaar_end\"\n\n# USB-connected Logitech receivers and devices\nATTRS{idVendor}==\"046d\", GOTO=\"solaar_apply\"\n\n# Lenovo nano receiver\nATTRS{idVendor}==\"17ef\", ATTRS{idProduct}==\"6042\", GOTO=\"solaar_apply\"\n\n# Bluetooth-connected Logitech devices\nKERNELS == \"0005:046D:*\", GOTO=\"solaar_apply\"\n\nGOTO=\"solaar_end\"\n\nLABEL=\"solaar_apply\"\n\n# Allow any seated user to access the receiver.\n# uaccess: modern ACL-enabled udev\nTAG+=\"uaccess\"\n\n# Grant members of the \"plugdev\" group access to receiver (useful for SSH users)\n#MODE=\"0660\", GROUP=\"plugdev\"\n\nLABEL=\"solaar_end\"\n# vim: ft=udevrules\n"
  },
  {
    "path": "rules.d-uinput/42-logitech-unify-permissions.rules",
    "content": "# This rule was added by Solaar.\n#\n# Allows non-root users to have raw access to Logitech devices.\n# Allowing users to write to the device is potentially dangerous\n# because they could perform firmware updates.\nKERNEL==\"uinput\", SUBSYSTEM==\"misc\", TAG+=\"uaccess\", OPTIONS+=\"static_node=uinput\"\n\nACTION == \"remove\", GOTO=\"solaar_end\"\nSUBSYSTEM != \"hidraw\", GOTO=\"solaar_end\"\n\n# USB-connected Logitech receivers and devices\nATTRS{idVendor}==\"046d\", GOTO=\"solaar_apply\"\n\n# Lenovo nano receiver\nATTRS{idVendor}==\"17ef\", ATTRS{idProduct}==\"6042\", GOTO=\"solaar_apply\"\n\n# Bluetooth-connected Logitech devices\nKERNELS == \"0005:046D:*\", GOTO=\"solaar_apply\"\n\nGOTO=\"solaar_end\"\n\nLABEL=\"solaar_apply\"\n\n# Allow any seated user to access the receiver.\n# uaccess: modern ACL-enabled udev\nTAG+=\"uaccess\"\n\n# Grant members of the \"plugdev\" group access to receiver (useful for SSH users)\n#MODE=\"0660\", GROUP=\"plugdev\"\n\nLABEL=\"solaar_end\"\n# vim: ft=udevrules\n"
  },
  {
    "path": "setup.py",
    "content": "import subprocess\nimport textwrap\n\nfrom glob import glob\nfrom os.path import dirname\nfrom pathlib import Path\n\nfrom setuptools import find_packages\nfrom setuptools import setup\n\nNAME = \"Solaar\"\nversion = Path(\"lib/solaar/version\").read_text().strip()\n\ntry:  # get commit from git describe\n    commit = subprocess.check_output([\"git\", \"describe\", \"--always\"], stderr=subprocess.DEVNULL).strip().decode()\n    Path(\"lib/solaar/commit\").write_text(f\"{commit}\\n\")\nexcept Exception:  # get commit from Ubuntu dpkg-parsechangelog\n    try:\n        commit = (\n            subprocess.check_output([\"dpkg-parsechangelog\", \"--show-field\", \"Version\"], stderr=subprocess.DEVNULL)\n            .strip()\n            .decode()\n        )\n        commit = commit.split(\"~\")\n        Path(\"lib/solaar/commit\").write_text(f\"{commit[0]}\\n\")\n    except Exception as e:\n        print(\"Exception using dpkg-parsechangelog\", e)\n\n\ndef _data_files():\n    yield \"share/icons/hicolor/scalable/apps\", glob(\"share/solaar/icons/solaar*.svg\")\n    yield \"share/icons/hicolor/32x32/apps\", glob(\"share/solaar/icons/solaar-light_*.png\")\n\n    for mo in glob(\"share/locale/*/LC_MESSAGES/solaar.mo\"):\n        yield dirname(mo), [mo]\n\n    yield \"share/applications\", [\"share/applications/solaar.desktop\"]\n    yield \"lib/udev/rules.d\", [\"rules.d/42-logitech-unify-permissions.rules\"]\n    yield \"share/metainfo\", [\"share/solaar/io.github.pwr_solaar.solaar.metainfo.xml\"]\n\n\nsetup(\n    name=NAME.lower(),\n    version=version,\n    description=\"Linux device manager for Logitech receivers, keyboards, mice, and tablets.\",\n    long_description=textwrap.dedent(\n        \"\"\"\n        Solaar is a Linux device manager for many Logitech peripherals that connect through\n        Unifying and other receivers or via USB or Bluetooth.\n        Solaar is able to pair/unpair devices with receivers and show and modify some of the\n        modifiable features of devices.\n        For instructions on installing Solaar see https://pwr-solaar.github.io/Solaar/installation\"\"\"\n    ),\n    author=\"Daniel Pavel\",\n    license=\"GPLv2\",\n    url=\"http://pwr-solaar.github.io/Solaar/\",\n    classifiers=[\n        \"Development Status :: 4 - Beta\",\n        \"Environment :: X11 Applications :: GTK\",\n        \"Environment :: Console\",\n        \"Intended Audience :: End Users/Desktop\",\n        \"License :: DFSG approved\",\n        \"License :: OSI Approved :: GNU General Public License v2 (GPLv2)\",\n        \"Natural Language :: English\",\n        \"Programming Language :: Python :: 3 :: Only\",\n        \"Operating System :: POSIX :: Linux\",\n        \"Topic :: Utilities\",\n    ],\n    platforms=[\"linux\"],\n    python_requires=\">=3.8\",\n    install_requires=[\n        'evdev (>= 1.1.2) ; platform_system==\"Linux\"',\n        \"pyudev (>= 0.13)\",\n        \"PyYAML (>= 3.12)\",\n        \"python-xlib (>= 0.27)\",\n        \"psutil (>= 5.4.3)\",\n        'dbus-python ; platform_system==\"Linux\"',\n        \"PyGObject\",\n        \"typing_extensions\",\n    ],\n    extras_require={\n        \"report-descriptor\": [\"hid-parser\"],\n        \"desktop-notifications\": [\"Notify (>= 0.7)\"],\n        \"git-commit\": [\"python-git-info\"],\n        \"test\": [\"pytest\", \"pytest-mock\", \"pytest-cov\"],\n        \"dev\": [\"ruff\"],\n    },\n    package_dir={\"\": \"lib\"},\n    packages=find_packages(where=\"lib\"),\n    data_files=list(_data_files()),\n    include_package_data=True,\n    entry_points={\n        \"console_scripts\": [\n            \"solaar = solaar.gtk:main\",\n        ],\n    },\n)\n"
  },
  {
    "path": "share/README",
    "content": "Solaar application icon drawn by me, roughly guided by Logitech's Unifying logo.\n\nAll other images are from the GNOME and Oxygen free icon themes.\n"
  },
  {
    "path": "share/applications/solaar.desktop",
    "content": "[Desktop Entry]\nName=Solaar\nComment=Logitech Unifying Receiver peripherals manager\nComment[fr]=Gestionnaire de périphériques pour les récepteurs Logitech Unifying\nComment[hr]=Upravitelj Logitechovih uređaja povezanih putem Unifying i Nano prijemnika\nComment[ru]=Управление приёмником Logitech Unifying Receiver\nComment[de]=Logitech Unifying Empfänger Geräteverwaltung\nComment[es]=Administrador de periféricos de Logitech Receptor Unifying\nComment[pl]=Menedżer urządzeń peryferyjnych odbiornika Logitech Unifying\nComment[sv]=Kringutrustningshanterare för Logitech Unifying-mottagare\nComment[zh_CN]=罗技优联设备管理器\nComment[zh_TW]=羅技Unifying 裝置管理器\nComment[zh_HK]=羅技Unifying 裝置管理器\nExec=solaar\nIcon=solaar\nStartupNotify=true\nTerminal=false\nType=Application\nKeywords=logitech;unifying;receiver;mouse;keyboard;\nCategories=Utility;GTK;\n#Categories=Utility;GTK;Settings;HardwareSettings;\nX-GNOME-UsesNotifications=true\n"
  },
  {
    "path": "share/autostart/solaar.desktop",
    "content": "[Desktop Entry]\nName=Solaar\nComment=Logitech Unifying Receiver peripherals manager\nComment[fr]=Gestionnaire de périphériques pour les récepteurs Logitech Unifying\nComment[hr]=Upravitelj Logitechovih uređaja povezanih putem Unifying i Nano prijemnika\nComment[ru]=Управление приёмником Logitech Unifying Receiver\nComment[de]=Logitech Unifying Empfänger Geräteverwaltung\nComment[es]=Administrador de periféricos de Logitech Receptor Unifying\nComment[pl]=Menedżer urządzeń peryferyjnych odbiornika Logitech Unifying\nComment[sv]=Kringutrustningshanterare för Logitech Unifying-mottagare\nComment[zh_CN]=罗技优联设备管理器\nComment[zh_TW]=羅技Unifying 裝置管理器\nComment[zh_HK]=羅技Unifying 裝置管理器\nExec=solaar --window=hide\nIcon=solaar\nStartupNotify=true\nTerminal=false\nType=Application\nKeywords=logitech;unifying;receiver;mouse;keyboard;\nCategories=Utility;GTK;\n#Categories=Utility;GTK;Settings;HardwareSettings;\n"
  },
  {
    "path": "share/solaar/io.github.pwr_solaar.solaar.metainfo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- Copyright 2020-2022 Peter F. Patel-Schneider -->\n<component type=\"desktop-application\">\n  <id>io.github.pwr_solaar.solaar</id>\n\n  <name>Solaar</name>\n  <summary>Linux manager for Logitech keyboards, mice, and trackpads</summary>\n  <developer id=\"pwr-solaar.github.io\">\n    <name>pwr-Solaar</name>\n  </developer>\n  <url type=\"homepage\">https://pwr-solaar.github.io/Solaar/</url>\n  <url type=\"vcs-browser\">https://github.com/pwr-Solaar/Solaar</url>\n  <content_rating type=\"oars-1.0\" />\n  <update_contact>pfpschneider_AT_gmail.com</update_contact>\n\n  <metadata_license>CC-BY-4.0</metadata_license>\n  <project_license>GPL-2.0-only</project_license>\n\n  <recommends>\n    <control>pointing</control>\n    <control>keyboard</control>\n    <control>touch</control>\n  </recommends>\n\n  <description>\n    <p>\n      Solaar is a Linux manager for many Logitech keyboards, mice, and trackpads that connect wirelessly to a USB, Lightspeed, or Nano receiver, connect directly via a USB cable, or connect via Bluetooth. Solaar does not work with peripherals from other companies.\n    </p>\n    <p>\n      Solaar can be used as a GUI application or via its command-line interface. Both interfaces are able to list the connected devices and show information about each device, often including battery status. Solaar is able to pair and unpair devices with receivers as supported by the device and receiver. Solaar can also control some changeable features of devices, such as smooth scrolling or function key behavior.\n    </p>\n    <p>\n      Solaar&apos;s GUI normally uses an icon in the system tray and starts with its main window visible.\n    </p>\n  </description>\n\n  <launchable type=\"desktop-id\">solaar.desktop</launchable>\n  <screenshots>\n    <screenshot type=\"default\">\n      <image>https://raw.githubusercontent.com/pwr-Solaar/Solaar/master/docs/screenshots/Solaar-main-window-button-actions.png</image>\n    </screenshot>\n    <screenshot>\n      <image>https://raw.githubusercontent.com/pwr-Solaar/Solaar/master/docs/screenshots/Solaar-main-window-receiver.png</image>\n    </screenshot>\n    <screenshot>\n      <image>https://raw.githubusercontent.com/pwr-Solaar/Solaar/master/docs/screenshots/Solaar-menu.png</image>\n    </screenshot>\n  </screenshots>\n\n  <releases>\n    <release version=\"1.1.19\" date=\"2026-01-08\"/>\n    <release version=\"1.1.18\" date=\"2025-12-11\"/>\n    <release version=\"1.1.16\" date=\"2025-10-23\"/>\n    <release version=\"1.1.14\" date=\"2025-01-01\"/>\n    <release version=\"1.1.13\" date=\"2024-05-11\"/>\n    <release version=\"1.1.12\" date=\"2024-04-27\"/>\n    <release version=\"1.1.11\" date=\"2024-02-18\"/>\n    <release version=\"1.1.10\" date=\"2023-09-23\"/>\n    <release version=\"1.1.9\" date=\"2023-04-05\"/>\n    <release version=\"1.1.8\" date=\"2022-12-17\"/>\n    <release version=\"1.1.7\" date=\"2022-11-03\"/>\n    <release version=\"1.1.6\" date=\"2022-10-24\"/>\n    <release version=\"1.1.5\" date=\"2022-09-14\"/>\n    <release version=\"1.1.4\" date=\"2022-07-04\"/>\n    <release version=\"1.1.3\" date=\"2022-04-25\"/>\n    <release version=\"1.1.2\" date=\"2022-03-26\"/>\n    <release version=\"1.1.1\" date=\"2021-12-25\"/>\n    <release version=\"1.1.0\" date=\"2021-12-20\"/>\n  </releases>\n\n  <provides>\n    <binary>solaar</binary>\n    <!-- USB Receivers - 27MHz, Unifying, Nano, Bolt -->\n    <modalias>usb:v17EFp6042d*</modalias>\n    <modalias>usb:v046DpC517d*</modalias>\n    <modalias>usb:v046DpC518d*</modalias>\n    <modalias>usb:v046DpC51Ad*</modalias>\n    <modalias>usb:v046DpC51Bd*</modalias>\n    <modalias>usb:v046DpC521d*</modalias>\n    <modalias>usb:v046DpC525d*</modalias>\n    <modalias>usb:v046DpC526d*</modalias>\n    <modalias>usb:v046DpC52Bd*</modalias>\n    <modalias>usb:v046DpC52Ed*</modalias>\n    <modalias>usb:v046DpC52Fd*</modalias>\n    <modalias>usb:v046DpC531d*</modalias>\n    <modalias>usb:v046DpC532d*</modalias>\n    <modalias>usb:v046DpC534d*</modalias>\n    <modalias>usb:v046DpC537d*</modalias>\n    <modalias>usb:v046DpC539d*</modalias>\n    <modalias>usb:v046DpC53Ad*</modalias>\n    <modalias>usb:v046DpC53Dd*</modalias>\n    <modalias>usb:v046DpC53Fd*</modalias>\n    <modalias>usb:v046DpC541d*</modalias>\n    <modalias>usb:v046DpC545d*</modalias>\n    <modalias>usb:v046DpC547d*</modalias>\n    <modalias>usb:v046DpC548d*</modalias>\n    <!-- USB Devices - Logitech says USB IDs are 0xC07D - 0xC094, 0xC32B - 0xC344 -->\n    <!-- Solaar also knows about two others -->\n    <modalias>usb:v046DpC06Bd*</modalias>\n    <modalias>usb:v046DpC07Cd*</modalias>\n    <modalias>usb:v046DpC07Dd*</modalias>\n    <modalias>usb:v046DpC07Ed*</modalias>\n    <modalias>usb:v046DpC07Fd*</modalias>\n    <modalias>usb:v046DpC08*d*</modalias>\n    <modalias>usb:v046DpC090d*</modalias>\n    <modalias>usb:v046DpC091d*</modalias>\n    <modalias>usb:v046DpC092d*</modalias>\n    <modalias>usb:v046DpC093d*</modalias>\n    <modalias>usb:v046DpC094d*</modalias>\n    <modalias>usb:v046DpC32Bd*</modalias>\n    <modalias>usb:v046DpC32Cd*</modalias>\n    <modalias>usb:v046DpC32Dd*</modalias>\n    <modalias>usb:v046DpC32Ed*</modalias>\n    <modalias>usb:v046DpC32Fd*</modalias>\n    <modalias>usb:v046DpC33*d*</modalias>\n    <modalias>usb:v046DpC340d*</modalias>\n    <modalias>usb:v046DpC341d*</modalias>\n    <modalias>usb:v046DpC342d*</modalias>\n    <modalias>usb:v046DpC343d*</modalias>\n    <modalias>usb:v046DpC344d*</modalias>\n    <!-- Bluetooth Devices - these appear to be known with usb prefixes -->\n    <!-- Logitech says their IDs are 0xB012 - 0xB0xx, 0xB32A - 0xB3xx -->\n    <modalias>usb:v046DpB012d*</modalias>\n    <modalias>usb:v046DpB013d*</modalias>\n    <modalias>usb:v046DpB014d*</modalias>\n    <modalias>usb:v046DpB015d*</modalias>\n    <modalias>usb:v046DpB016d*</modalias>\n    <modalias>usb:v046DpB017d*</modalias>\n    <modalias>usb:v046DpB018d*</modalias>\n    <modalias>usb:v046DpB019d*</modalias>\n    <modalias>usb:v046DpB01Ad*</modalias>\n    <modalias>usb:v046DpB01Bd*</modalias>\n    <modalias>usb:v046DpB01Cd*</modalias>\n    <modalias>usb:v046DpB01Dd*</modalias>\n    <modalias>usb:v046DpB01Ed*</modalias>\n    <modalias>usb:v046DpB01Fd*</modalias>\n    <modalias>usb:v046DpB02*d*</modalias>\n    <modalias>usb:v046DpB03*d*</modalias>\n    <modalias>usb:v046DpB04*d*</modalias>\n    <modalias>usb:v046DpB05*d*</modalias>\n    <modalias>usb:v046DpB06*d*</modalias>\n    <modalias>usb:v046DpB07*d*</modalias>\n    <modalias>usb:v046DpB08*d*</modalias>\n    <modalias>usb:v046DpB09*d*</modalias>\n    <modalias>usb:v046DpB0A*d*</modalias>\n    <modalias>usb:v046DpB0B*d*</modalias>\n    <modalias>usb:v046DpB0C*d*</modalias>\n    <modalias>usb:v046DpB0D*d*</modalias>\n    <modalias>usb:v046DpB0E*d*</modalias>\n    <modalias>usb:v046DpB0F*d*</modalias>\n    <modalias>usb:v046DpB32Ad*</modalias>\n    <modalias>usb:v046DpB32Bd*</modalias>\n    <modalias>usb:v046DpB32Cd*</modalias>\n    <modalias>usb:v046DpB32Dd*</modalias>\n    <modalias>usb:v046DpB32Ed*</modalias>\n    <modalias>usb:v046DpB32Fd*</modalias>\n    <modalias>usb:v046DpB33*d*</modalias>\n    <modalias>usb:v046DpB34*d*</modalias>\n    <modalias>usb:v046DpB35*d*</modalias>\n    <modalias>usb:v046DpB36*d*</modalias>\n    <modalias>usb:v046DpB37*d*</modalias>\n    <modalias>usb:v046DpB38*d*</modalias>\n    <modalias>usb:v046DpB39*d*</modalias>\n    <modalias>usb:v046DpB3A*d*</modalias>\n    <modalias>usb:v046DpB3B*d*</modalias>\n    <modalias>usb:v046DpB3C*d*</modalias>\n    <modalias>usb:v046DpB3D*d*</modalias>\n    <modalias>usb:v046DpB3E*d*</modalias>\n    <modalias>usb:v046DpB3F*d*</modalias>\n  </provides>\n</component>\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/hid_parser/__init__.py",
    "content": ""
  },
  {
    "path": "tests/hid_parser/test_data.py",
    "content": "from hid_parser.data import Button\nfrom hid_parser.data import Consumer\n\n\ndef test_consumer():\n    consumer = Consumer()\n\n    assert consumer.PLAY_PAUSE == 0xCD\n\n\ndef test_button():\n    button = Button()\n\n    assert button.NO_BUTTON == 0x0\n    assert button.BUTTON_1 == 0x1\n"
  },
  {
    "path": "tests/hidapi/__init__.py",
    "content": ""
  },
  {
    "path": "tests/hidapi/test_hidapi.py",
    "content": "import platform\n\nfrom unittest import mock\n\nif platform.system() == \"Linux\":\n    import hidapi.udev_impl as hidapi\nelse:\n    import hidapi.hidapi_impl as hidapi\n\n\ndef test_find_paired_node():\n    hidapi.enumerate(mock.Mock())\n"
  },
  {
    "path": "tests/logitech_receiver/__init__.py",
    "content": ""
  },
  {
    "path": "tests/logitech_receiver/fake_hidpp.py",
    "content": "## Copyright (C) 2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n\"\"\"HID++ data and functions common to several logitech_receiver test files\"\"\"\n\nfrom __future__ import annotations\n\nimport errno\nimport threading\n\nfrom dataclasses import dataclass\nfrom dataclasses import field\nfrom struct import pack\nfrom typing import Any\nfrom typing import Optional\n\nfrom logitech_receiver import device\nfrom logitech_receiver import hidpp20\nfrom solaar import configuration\n\n\ndef open_path(path: Optional[str]) -> int:\n    if path is None:\n        raise OSError(errno.EACCES, \"Fake access error\")\n    return int(path, 16)  # can raise exception\n\n\ndef ping(responses, handle, devnumber, long_message=False):\n    for r in responses:\n        if handle == r.handle and devnumber == r.devnumber and r.id == 0x0010:\n            return r.response\n\n\ndef request(\n    responses,\n    handle,\n    devnumber,\n    id,\n    *params,\n    no_reply=False,\n    return_error=False,\n    long_message=False,\n    protocol=1.0,\n):\n    params = b\"\".join(pack(\"B\", p) if isinstance(p, int) else p for p in params)\n    print(\"REQUEST \", hex(handle), hex(devnumber), hex(id), params.hex())\n    for r in responses:\n        if handle == r.handle and devnumber == r.devnumber and r.id == id and bytes.fromhex(r.params) == params:\n            print(\"RESPONSE\", hex(r.handle), hex(r.devnumber), hex(r.id), r.params, r.response)\n            return bytes.fromhex(r.response) if r.response is not None else None\n\n\n@dataclass\nclass Response:\n    response: str | float\n    id: int\n    params: str = \"\"\n    handle: int = 0x11\n    devnumber: int = 0xFF\n    no_reply: bool = False\n\n\ndef replace_number(responses, number):  # change the devnumber for a list of responses\n    return [Response(r.response, r.id, r.params, r.handle, number, r.no_reply) for r in responses]\n\n\ndef adjust_responses_index(index, responses):  # change index-4 responses to index\n    return [Response(r.response, r.id - 0x400 + (index << 8), r.params, r.handle, r.devnumber, r.no_reply) for r in responses]\n\n\nr_empty = [  # a HID++ device with no responses except for ping\n    Response(1.0, 0x0010),  # ping\n]\n\nr_keyboard_1 = [  # a HID++ 1.0 keyboard\n    Response(1.0, 0x0010),  # ping\n    Response(\"001234\", 0x81F1, \"01\"),  # firmware\n    Response(\"003412\", 0x81F1, \"02\"),  # firmware\n    Response(\"002345\", 0x81F1, \"03\"),  # firmware\n    Response(\"003456\", 0x81F1, \"04\"),  # firmware\n    Response(\"050050\", 0x8107),  # battery status\n]\n\nr_keyboard_2 = [  # a HID++ 2.0 keyboard\n    Response(4.2, 0x0010),  # ping\n    Response(\"010001\", 0x0000, \"0001\"),  # feature set at 0x01\n    Response(\"020003\", 0x0000, \"0020\"),  # CONFIG_CHANGE at 0x02\n    Response(\"030001\", 0x0000, \"0003\"),  # device information at 0x03\n    Response(\"040003\", 0x0000, \"0100\"),  # unknown 0100 at 0x04\n    Response(\"050003\", 0x0000, \"1B04\"),  # reprogrammable keys V4 at 0x05\n    Response(\"060003\", 0x0000, \"0007\"),  # device friendly name at 0x06\n    Response(\"070003\", 0x0000, \"0005\"),  # device name at 0x07\n    Response(\"080003\", 0x0000, \"1000\"),  # battery status at 0x08\n    Response(\"08\", 0x0100),  # 8 features\n    Response(\"00010001\", 0x0110, \"01\"),  # feature set at 0x01\n    Response(\"00200003\", 0x0110, \"02\"),  # CONFIG_CHANGE at 0x02\n    Response(\"00030001\", 0x0110, \"03\"),  # device information at 0x03\n    Response(\"01000003\", 0x0110, \"04\"),  # unknown 0100 at 0x04\n    Response(\"1B040003\", 0x0110, \"05\"),  # reprogrammable keys V4 at 0x05\n    Response(\"00070003\", 0x0000, \"06\"),  # device friendly name at 0x06\n    Response(\"00050003\", 0x0000, \"07\"),  # device name at 0x07\n    Response(\"10000001\", 0x0110, \"08\"),  # battery status at 0x02\n    Response(\"0212345678000D1234567890ABAA01\", 0x0300),  # device information\n    Response(\"04\", 0x0500),  # reprogrammable keys V4\n    Response(\"00110012AB010203CD00\", 0x0510, \"00\"),  # reprogrammable keys V4\n    Response(\"01110022AB010203CD00\", 0x0510, \"01\"),  # reprogrammable keys V4\n    Response(\"00010111AB010203CD00\", 0x0510, \"02\"),  # reprogrammable keys V4\n    Response(\"03110032AB010204CD00\", 0x0510, \"03\"),  # reprogrammable keys V4\n    Response(\"00030333AB010203CD00\", 0x0510, \"04\"),  # reprogrammable keys V4\n    Response(\"12\", 0x0600),  # friendly namme\n    Response(\"004142434445464748494A4B4C4D4E\", 0x0610, \"00\"),\n    Response(\"0E4F50515253000000000000000000\", 0x0610, \"0E\"),\n    Response(\"12\", 0x0700),  # name and kind\n    Response(\"4142434445464748494A4B4C4D4E4F\", 0x0710, \"00\"),\n    Response(\"505152530000000000000000000000\", 0x0710, \"0F\"),\n    Response(\"00\", 0x0720),\n    Response(\"12345678\", 0x0800),  # battery status\n]\n\nr_mouse_1 = [  # a HID++ 1.0 mouse\n    Response(1.0, 0x0010),  # ping\n]\n\nr_mouse_2 = [  # a HID++ 2.0 mouse with few responses except for ping\n    Response(4.2, 0x0010),  # ping\n]\n\nr_mouse_3 = [  # a HID++ 2.0 mouse\n    Response(4.5, 0x0010),  # ping\n    Response(\"010001\", 0x0000, \"0001\"),  # feature set at 0x01\n    Response(\"020002\", 0x0000, \"8060\"),  # report rate at 0x02\n    Response(\"040001\", 0x0000, \"0003\"),  # device information at 0x04\n    Response(\"050002\", 0x0000, \"0005\"),  # device type and name at 0x05\n    Response(\"08\", 0x0100),  # 8 features\n    Response(\"00010001\", 0x0110, \"01\"),  # feature set at 0x01\n    Response(\"80600002\", 0x0110, \"02\"),  # report rate at 0x02\n    Response(\"00030001\", 0x0110, \"04\"),  # device information at 0x04\n    Response(\"00050002\", 0x0110, \"05\"),  # device type and name at 0x05\n    Response(\"09\", 0x0210),  # report rate - current rate\n    Response(\"03123456790008123456780000AA01\", 0x0400),  # device information\n    Response(\"0141424302030100\", 0x0410, \"00\"),  # firmware 0\n    Response(\"0241\", 0x0410, \"01\"),  # firmware 1\n    Response(\"05\", 0x0410, \"02\"),  # firmware 2\n    Response(\"12\", 0x0500),  # name count - 18 characters\n    Response(\"414241424142414241424142414241\", 0x0510, \"00\"),  # name - first 15 characters\n    Response(\"444544000000000000000000000000\", 0x0510, \"0F\"),  # name - last 3 characters\n]\n\n\nresponses_key = [  # responses for Reprogrammable Keys V4 at 0x05\n    Response(\"08\", 0x0500),  # Reprogrammable Keys V4 count\n    Response(\"00500038010001010400000000000000\", 0x0510, \"00\"),  # left button\n    Response(\"00510039010001010400000000000000\", 0x0510, \"01\"),  # right button\n    Response(\"0052003A310003070500000000000000\", 0x0510, \"02\"),  # middle button\n    Response(\"0053003C710002030100000000000000\", 0x0510, \"03\"),  # back button\n    Response(\"0056003E710002030100000000000000\", 0x0510, \"04\"),  # forward button\n    Response(\"00C300A9310003070300000000000000\", 0x0510, \"05\"),  # smart shift?\n    Response(\"00C4009D310003070500000000000000\", 0x0510, \"06\"),  # ?\n    Response(\"00D700B4A00004000300000000000000\", 0x0510, \"07\"),  # ?\n    Response(\"00500000000000000000000000000000\", 0x0520, \"0050\"),  # left button\n    Response(\"00510000000000000000000000000000\", 0x0520, \"0051\"),  # ...\n    Response(\"00520100500000000000000000000000\", 0x0520, \"0052\"),\n    Response(\"00530500000000000000000000000000\", 0x0520, \"0053\"),\n    Response(\"00561100000000000000000000000000\", 0x0520, \"0056\"),\n    Response(\"00C30000000000000000000000000000\", 0x0520, \"00C3\"),\n    Response(\"00C40000500000000000000000000000\", 0x0520, \"00C4\"),\n    Response(\"00D70000510000000000000000000000\", 0x0520, \"00D7\"),\n    Response(\"0041\", 0x0400),  # flags\n    Response(\"0401\", 0x0410),  # count\n    Response(\"0050\", 0x0420, \"00FF\"),  # left button\n    Response(\"0051\", 0x0420, \"01FF\"),  # right button\n    Response(\"0052\", 0x0420, \"02FF\"),  # middle button\n    Response(\"0053\", 0x0420, \"03FF\"),  # back button\n    Response(\"0050000100500000\", 0x0430, \"0050FF\"),  # left button current\n    Response(\"0051000100500001\", 0x0430, \"0051FF\"),  # right button current\n    Response(\"0052000100500001\", 0x0430, \"0052FF\"),  # middle button current\n    Response(\"0053000100500001\", 0x0430, \"0053FF\"),  # back button current\n    Response(\"0050FF01005000\", 0x0440, \"0050FF01005000\"),  # left button write\n    Response(\"0051FF01005000\", 0x0440, \"0051FF01005000\"),  # right button write\n    Response(\"0051FF01005100\", 0x0440, \"0051FF01005100\"),  # right button set write\n]\n\nresponses_remap = [  # responses for Persistent Remappable Actions at 0x04 and reprogrammable keys at 0x05\n    Response(\"0041\", 0x0400),\n    Response(\"03\", 0x0410),\n    Response(\"0301\", 0x0410, \"00\"),\n    Response(\"0050\", 0x0420, \"00FF\"),\n    Response(\"0050000200010001\", 0x0430, \"0050FF\"),  # Left Button\n    Response(\"0051\", 0x0420, \"01FF\"),\n    Response(\"0051000200010000\", 0x0430, \"0051FF\"),  # Left Button\n    Response(\"0052\", 0x0420, \"02FF\"),\n    Response(\"0052000100510000\", 0x0430, \"0052FF\"),  # key DOWN\n    Response(\"050002\", 0x0000, \"1B04\"),  # REPROGRAMMABLE_KEYS_V4\n] + responses_key\n\nresponses_gestures = [  # the commented-out messages are not used by either the setting or other testing\n    Response(\"4203410141020400320480148C21A301\", 0x0400, \"0000\"),  # items\n    Response(\"A302A11EA30A4105822C852DAD2AAD2B\", 0x0400, \"0008\"),\n    Response(\"8F408F418F434204AF54912282558264\", 0x0400, \"0010\"),\n    Response(\"01000000000000000000000000000000\", 0x0400, \"0018\"),\n    Response(\"01000000000000000000000000000000\", 0x0410, \"000101\"),  # enable\n    #    Response(\"02000000000000000000000000000000\", 0x0410, \"000102\"),\n    #    Response(\"04000000000000000000000000000000\", 0x0410, \"000104\"),\n    #    Response(\"08000000000000000000000000000000\", 0x0410, \"000108\"),\n    Response(\"00000000000000000000000000000000\", 0x0410, \"000110\"),\n    #    Response(\"20000000000000000000000000000000\", 0x0410, \"000120\"),\n    #    Response(\"40000000000000000000000000000000\", 0x0410, \"000140\"),\n    #    Response(\"00000000000000000000000000000000\", 0x0410, \"000180\"),\n    #    Response(\"00000000000000000000000000000000\", 0x0410, \"010101\"),\n    #    Response(\"00000000000000000000000000000000\", 0x0410, \"010102\"),\n    #    Response(\"04000000000000000000000000000000\", 0x0410, \"010104\"),\n    #    Response(\"00000000000000000000000000000000\", 0x0410, \"010108\"),\n    Response(\"6F000000000000000000000000000000\", 0x0410, \"0001FF\"),\n    Response(\"04000000000000000000000000000000\", 0x0410, \"01010F\"),\n    Response(\"00000000000000000000000000000000\", 0x0430, \"000101\"),  # divert\n    #    Response(\"00000000000000000000000000000000\", 0x0430, \"000102\"),\n    #    Response(\"00000000000000000000000000000000\", 0x0430, \"000104\"),\n    #    Response(\"00000000000000000000000000000000\", 0x0430, \"000108\"),\n    Response(\"00000000000000000000000000000000\", 0x0430, \"000110\"),\n    #    Response(\"00000000000000000000000000000000\", 0x0430, \"000120\"),\n    #    Response(\"00000000000000000000000000000000\", 0x0430, \"000140\"),\n    #    Response(\"00000000000000000000000000000000\", 0x0430, \"000180\"),\n    #    Response(\"00000000000000000000000000000000\", 0x0430, \"010101\"),\n    #    Response(\"00000000000000000000000000000000\", 0x0430, \"010102\"),\n    Response(\"00000000000000000000000000000000\", 0x0430, \"0001FF\"),\n    Response(\"00000000000000000000000000000000\", 0x0430, \"010103\"),\n    Response(\"08000000000000000000000000000000\", 0x0450, \"01FF\"),\n    Response(\"08000000000000000000000000000000\", 0x0450, \"02FF\"),\n    Response(\"08000000000000000000000000000000\", 0x0450, \"03FF\"),\n    Response(\"00040000000000000000000000000000\", 0x0450, \"04FF\"),\n    Response(\"5C020000000000000000000000000000\", 0x0450, \"05FF\"),\n    Response(\"01000000000000000000000000000000\", 0x0460, \"00FF\"),\n    Response(\"01000000000000000000000000000000\", 0x0470, \"00FF\"),\n    Response(\"01\", 0x0420, \"00010101\"),  # set index 1\n    Response(\"00\", 0x0420, \"00010100\"),  # unset index 1\n    Response(\"01\", 0x0420, \"00011010\"),  # set index 4\n    Response(\"00\", 0x0420, \"00011000\"),  # unset index 4\n    Response(\"01\", 0x0440, \"00010101\"),  # divert index 1\n    Response(\"00\", 0x0440, \"00010100\"),  # undivert index 1\n    Response(\"000080FF\", 0x0480, \"000080FF\"),  # write param 0\n    Response(\"000180FF\", 0x0480, \"000180FF\"),  # write param 0\n]\n\nzone_responses_1 = [  # responses for COLOR LED EFFECTS\n    Response(\"00000102\", 0x0710, \"00FF00\"),\n    Response(\"0000000300040005\", 0x0720, \"000000\"),\n    Response(\"0001000B00080009\", 0x0720, \"000100\"),\n]\nzone_responses_2 = [  # responses for RGB EFFECTS\n    Response(\"0000000102\", 0x0700, \"00FF00\"),\n    Response(\"0000000300040005\", 0x0700, \"000000\"),\n    Response(\"0001000200080009\", 0x0700, \"000100\"),\n]\neffects_responses_1 = [Response(\"0100000001\", 0x0700)] + zone_responses_1\neffects_responses_2 = [Response(\"FFFF0100000001\", 0x0700, \"FFFF00\")] + zone_responses_2\n\nresponses_profiles = [  # OnboardProfile in RAM\n    Response(\"0104010101020100FE0200\", 0x0900),\n    Response(\"000101FF\", 0x0950, \"00000000\"),\n    Response(\"FFFFFFFF\", 0x0950, \"00000004\"),\n    Response(\"01010290018003000700140028FFFFFF\", 0x0950, \"00010000\"),\n    Response(\"FFFF0000000000000000000000000000\", 0x0950, \"00010010\"),\n    Response(\"8000FFFF900aFF00800204548000FFFF\", 0x0950, \"00010020\"),\n    Response(\"900aFF00800204548000FFFF900aFF00\", 0x0950, \"00010030\"),\n    Response(\"800204548000FFFF900aFF0080020454\", 0x0950, \"00010040\"),\n    Response(\"8000FFFF900aFF00800204548000FFFF\", 0x0950, \"00010050\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"00010060\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"00010070\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"00010080\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"00010090\"),\n    Response(\"54004500370000000000000000000000\", 0x0950, \"000100A0\"),\n    Response(\"00000000000000000000000000000000\", 0x0950, \"000100B0\"),\n    Response(\"00000000000000000000000000000000\", 0x0950, \"000100C0\"),\n    Response(\"0A01020300500407000000FFFFFFFFFF\", 0x0950, \"000100D0\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"000100E0\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB\", 0x0950, \"000100EE\"),\n]\nresponses_profiles_rom = [  # OnboardProfile in ROM\n    Response(\"0104010101020100FE0200\", 0x0900),\n    Response(\"00000000\", 0x0950, \"00000000\"),\n    Response(\"010101FF\", 0x0950, \"01000000\"),\n    Response(\"FFFFFFFF\", 0x0950, \"01000004\"),\n    Response(\"01010290018003000700140028FFFFFF\", 0x0950, \"01010000\"),\n    Response(\"FFFF0000000000000000000000000000\", 0x0950, \"01010010\"),\n    Response(\"8000FFFF900aFF00800204548000FFFF\", 0x0950, \"01010020\"),\n    Response(\"900aFF00800204548000FFFF900aFF00\", 0x0950, \"01010030\"),\n    Response(\"800204548000FFFF900aFF0080020454\", 0x0950, \"01010040\"),\n    Response(\"8000FFFF900aFF00800204548000FFFF\", 0x0950, \"01010050\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"01010060\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"01010070\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"01010080\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"01010090\"),\n    Response(\"54004500370000000000000000000000\", 0x0950, \"010100A0\"),\n    Response(\"00000000000000000000000000000000\", 0x0950, \"010100B0\"),\n    Response(\"00000000000000000000000000000000\", 0x0950, \"010100C0\"),\n    Response(\"0A01020300500407000000FFFFFFFFFF\", 0x0950, \"010100D0\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"010100E0\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB\", 0x0950, \"010100EE\"),\n]\nresponses_profiles_rom_2 = [  # OnboardProfile in ROM\n    Response(\"0104010101020100FE0200\", 0x0900),\n    Response(\"FFFFFFFF\", 0x0950, \"00000000\"),\n    Response(\"010101FF\", 0x0950, \"01000000\"),\n    Response(\"FFFFFFFF\", 0x0950, \"01000004\"),\n    Response(\"01010290018003000700140028FFFFFF\", 0x0950, \"01010000\"),\n    Response(\"FFFF0000000000000000000000000000\", 0x0950, \"01010010\"),\n    Response(\"8000FFFF900aFF00800204548000FFFF\", 0x0950, \"01010020\"),\n    Response(\"900aFF00800204548000FFFF900aFF00\", 0x0950, \"01010030\"),\n    Response(\"800204548000FFFF900aFF0080020454\", 0x0950, \"01010040\"),\n    Response(\"8000FFFF900aFF00800204548000FFFF\", 0x0950, \"01010050\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"01010060\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"01010070\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"01010080\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"01010090\"),\n    Response(\"54004500370000000000000000000000\", 0x0950, \"010100A0\"),\n    Response(\"00000000000000000000000000000000\", 0x0950, \"010100B0\"),\n    Response(\"00000000000000000000000000000000\", 0x0950, \"010100C0\"),\n    Response(\"0A01020300500407000000FFFFFFFFFF\", 0x0950, \"010100D0\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0950, \"010100E0\"),\n    Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB\", 0x0950, \"010100EE\"),\n]\n\ncomplex_responses_1 = [  # COLOR_LED_EFFECTS\n    Response(4.2, 0x0010),  # ping\n    Response(\"010001\", 0x0000, \"0001\"),  # FEATURE SET at x01\n    Response(\"020001\", 0x0000, \"0020\"),  # CONFIG_CHANGE at x02\n    Response(\"0A\", 0x0100),  # 10 features\n    Response(\"070001\", 0x0000, \"8070\"),  # COLOR_LED_EFFECTS at 0x07\n    *effects_responses_1,\n]\n\ncomplex_responses_2 = [  # RGB_EFFECTS + reprogrammable keys + persistent actions\n    Response(4.2, 0x0010),  # ping\n    Response(\"010001\", 0x0000, \"0001\"),  # FEATURE SET at x01\n    Response(\"020001\", 0x0000, \"0020\"),  # CONFIG_CHANGE at x02\n    Response(\"0A\", 0x0100),  # 10 features\n    Response(\"070001\", 0x0000, \"8071\"),  # RGB_EFFECTS at 0x07\n    *effects_responses_2,\n    Response(\"040001\", 0x0000, \"1C00\"),  # Persistent Remappable Actions at 0x04\n    *responses_remap,\n    Response(\"080001\", 0x0000, \"6501\"),  # Gestures at 0x08\n    *adjust_responses_index(8, responses_gestures),\n    Response(\"060003\", 0x0000, \"1982\"),  # Backlight 2 at 0x06\n    Response(\"010118000001020003000400\", 0x0600),\n    Response(\"090003\", 0x0000, \"8100\"),  # Onboard Profiles at 0x09\n    *responses_profiles,\n]\n\nresponses_speedchange = [\n    Response(\"0100\", 0x0400),\n    Response(\"010001\", 0x0000, \"0001\"),  # FEATURE SET at x01\n    Response(\"0A\", 0x0100),  # 10 features\n    Response(\"0120\", 0x0410, \"0120\"),\n    Response(\"050001\", 0x0000, \"1B04\"),  # REPROG_CONTROLS_V4\n    Response(\"01\", 0x0500),\n    Response(\"00ED009D310003070500000000000000\", 0x0510, \"00\"),  # DPI Change\n    Response(\"00ED0000000000000000000000000000\", 0x0520, \"00ED\"),  # DPI Change current\n    Response(\"060000\", 0x0000, \"2205\"),  # POINTER_SPEED\n]\n\n\n# A fake device that uses provided data (responses) to respond to HID++ commands.\n# Some methods from the real device are used to set up data structures needed for settings\n@dataclass\nclass Device:\n    name: str = \"TESTD\"\n    online: bool = True\n    protocol: float = 2.0\n    responses: Any = field(default_factory=list)\n    codename: str = \"TESTC\"\n    feature: Optional[int] = None\n    offset: Optional[int] = 4\n    version: Optional[int] = 0\n    wpid: Optional[str] = \"0000\"\n    setting_callback: Any = None\n    sliding = profiles = _backlight = _keys = _remap_keys = _led_effects = _gestures = None\n    _gestures_lock = threading.Lock()\n    number = \"d1\"\n    present = True\n\n    read_register = device.Device.read_register\n    write_register = device.Device.write_register\n    backlight = device.Device.backlight\n    keys = device.Device.keys\n    remap_keys = device.Device.remap_keys\n    led_effects = device.Device.led_effects\n    gestures = device.Device.gestures\n    __hash__ = device.Device.__hash__\n    feature_request = device.Device.feature_request\n\n    def __post_init__(self):\n        self._name = self.name\n        self._protocol = self.protocol\n        self.persister = configuration._DeviceEntry()\n        self.features = hidpp20.FeaturesArray(self)\n        self.settings = []\n        self.receiver = []\n        if self.feature is not None:\n            self.features = hidpp20.FeaturesArray(self)\n            self.responses = [\n                Response(\"010001\", 0x0000, \"0001\"),\n                Response(\"20\", 0x0100),\n            ] + self.responses\n            self.responses.append(\n                Response(\n                    f\"{int(self.offset):0>2X}00{int(self.version):0>2X}\",\n                    0x0000,\n                    f\"{int(self.feature):0>4X}\",\n                )\n            )\n        if self.setting_callback is None:\n            self.setting_callback = lambda x, y, z: None\n        self.add_notification_handler = lambda x, y: None\n\n    def request(self, id, *params, no_reply=False, long_message=False, protocol=2.0):\n        params = b\"\".join(pack(\"B\", p) if isinstance(p, int) else p for p in params)\n        print(\"REQUEST \", self._name, hex(id), params.hex().upper())\n        for r in self.responses:\n            if id == r.id and params == bytes.fromhex(r.params):\n                print(\"RESPONSE\", self._name, hex(r.id), r.params, r.response)\n                return bytes.fromhex(r.response) if isinstance(r.response, str) else r.response\n        print(\"RESPONSE\", self._name, None)\n\n    def ping(self, handle=None, devnumber=None, long_message=False):\n        print(\"PING\", self._protocol)\n        return self._protocol\n\n    def handle_notification(self, handle):\n        pass\n\n    def changed(self, *args, **kwargs):\n        pass\n\n    def set_battery_info(self, *args, **kwargs):\n        pass\n\n    def status_string(self):\n        pass\n\n\ndef match_requests(number, responses, call_args_list):\n    for i in range(0 - number, 0):\n        param = b\"\".join(pack(\"B\", p) if isinstance(p, int) else p for p in call_args_list[i][0][1:]).hex().upper()\n        print(\"MATCH\", i, hex(call_args_list[i][0][0]), param, hex(responses[i].id), responses[i].params)\n        assert call_args_list[i][0][0] == responses[i].id\n        assert param == responses[i].params\n"
  },
  {
    "path": "tests/logitech_receiver/test_base.py",
    "content": "import struct\nimport sys\n\nfrom typing import Union\nfrom unittest import mock\n\nimport pytest\n\nfrom logitech_receiver import base\nfrom logitech_receiver import exceptions\nfrom logitech_receiver.base import HIDPP_SHORT_MESSAGE_ID\nfrom logitech_receiver.common import LOGITECH_VENDOR_ID\nfrom logitech_receiver.common import BusID\nfrom logitech_receiver.hidpp10_constants import ErrorCode as Hidpp10Error\nfrom logitech_receiver.hidpp20_constants import ErrorCode as Hidpp20Error\n\n\n@pytest.mark.parametrize(\n    \"usb_id, expected_name, expected_receiver_kind\",\n    [\n        (0xC548, \"Bolt Receiver\", \"bolt\"),\n        (0xC52B, \"Unifying Receiver\", \"unifying\"),\n        (0xC531, \"Nano Receiver\", \"nano\"),\n        (0xC53F, \"Lightspeed Receiver\", None),\n        (0xC517, \"EX100 Receiver 27 Mhz\", \"27Mhz\"),\n    ],\n)\ndef test_product_information(usb_id, expected_name, expected_receiver_kind):\n    res = base.product_information(usb_id)\n\n    assert res[\"name\"] == expected_name\n    assert isinstance(res[\"vendor_id\"], int)\n    assert isinstance(res[\"product_id\"], int)\n\n    if expected_receiver_kind:\n        assert res[\"receiver_kind\"] == expected_receiver_kind\n\n\ndef test_filter_receivers_known():\n    bus_id = 2\n    product_id = 0xC548\n\n    receiver_info = base.get_known_receiver_info(bus_id, LOGITECH_VENDOR_ID, product_id)\n\n    assert receiver_info[\"name\"] == \"Bolt Receiver\"\n    assert receiver_info[\"receiver_kind\"] == \"bolt\"\n\n\ndef test_filter_receivers_unknown():\n    bus_id = 1\n    product_id = 0xC500\n\n    receiver_info = base.get_known_receiver_info(bus_id, LOGITECH_VENDOR_ID, product_id)\n\n    assert receiver_info[\"bus_id\"] == bus_id\n    assert receiver_info[\"product_id\"] == product_id\n\n\n@pytest.mark.parametrize(\n    \"product_id, bus, hidpp_short, hidpp_long, expected\",\n    [\n        (0xC548, BusID.USB, True, False, {\"name\": \"Bolt Receiver\", \"usb_interface\": 2}),\n        (0xC07D, BusID.USB, True, False, {\"usb_interface\": 1}),\n        (0xC07E, BusID.USB, False, True, {\"usb_interface\": 1}),\n        (0xC07E, BusID.BLUETOOTH, False, True, {\"bus_id\": 5}),\n        (0xA07E, BusID.USB, False, True, {\"product_id\": 0xA07E}),\n        (0xA07C, BusID.USB, False, False, None),\n        (0xC07F, BusID.USB, None, None, {\"usb_interface\": 2}),\n        (0xC07F, BusID.BLUETOOTH, None, None, None),\n        (0xB013, BusID.BLUETOOTH, None, None, {\"product_id\": 0xB013}),\n    ],\n)\ndef test_filter_products_of_interest(product_id, bus, hidpp_short, hidpp_long, expected):\n    receiver_info = base.filter_products_of_interest(\n        bus,\n        LOGITECH_VENDOR_ID,\n        product_id,\n        hidpp_short=hidpp_short,\n        hidpp_long=hidpp_long,\n    )\n\n    if expected is None:\n        assert receiver_info == expected\n    else:\n        assert all([receiver_info[key] == expected_value for key, expected_value in expected.items()])\n        assert receiver_info[\"vendor_id\"] == LOGITECH_VENDOR_ID\n        assert receiver_info[\"product_id\"]\n\n\ndef test_match():\n    record = {\"vendor_id\": LOGITECH_VENDOR_ID}\n\n    res = base._match_device(record, 0, LOGITECH_VENDOR_ID, 0)\n\n    assert res is True\n\n\n@pytest.mark.parametrize(\n    \"report_id, sub_id, address, valid_notification\",\n    [\n        (0x1, 0x72, 0x57, True),\n        (0x1, 0x40, 0x63, True),\n        (0x1, 0x40, 0x71, True),\n        (0x1, 0x80, 0x71, False),\n        (0x1, 0x00, 0x70, False),\n        (0x20, 0x09, 0x71, False),\n        (0x1, 0x37, 0x71, False),\n    ],\n)\ndef test_make_notification(report_id, sub_id, address, valid_notification):\n    devnumber = 123\n    data = bytes([sub_id, address, 0x02, 0x03, 0x04])\n\n    result = base.make_notification(report_id, devnumber, data)\n\n    if valid_notification:\n        assert isinstance(result, base.HIDPPNotification)\n        assert result.report_id == report_id\n        assert result.devnumber == devnumber\n        assert result.sub_id == sub_id\n        assert result.address == address\n        assert result.data == bytes([0x02, 0x03, 0x04])\n    else:\n        assert result is None\n\n\ndef test_get_next_sw_id():\n    res1 = base._get_next_sw_id()\n    res2 = base._get_next_sw_id()\n\n    assert res1 == 2\n    assert res2 == 3\n\n\n@pytest.mark.parametrize(\n    \"prefix, error_code, return_error, raise_exception\",\n    [\n        (b\"\\x8f\", Hidpp10Error.INVALID_SUB_ID_COMMAND, False, False),\n        (b\"\\x8f\", Hidpp10Error.INVALID_SUB_ID_COMMAND, True, False),\n        (b\"\\xff\", Hidpp20Error.UNKNOWN, False, True),\n    ],\n)\ndef test_request_errors(\n    prefix: bytes, error_code: Union[Hidpp10Error, Hidpp20Error], return_error: bool, raise_exception: bool\n):\n    handle = 0\n    device_number = 66\n\n    next_sw_id = 0x02\n    reply_data_sw_id = struct.pack(\"!H\", 0x0000 | next_sw_id)\n\n    with mock.patch(\n        \"logitech_receiver.base._read\",\n        return_value=(HIDPP_SHORT_MESSAGE_ID, device_number, prefix + reply_data_sw_id + struct.pack(\"B\", error_code)),\n    ), mock.patch(\"logitech_receiver.base._read_input_buffer\"), mock.patch(\n        \"logitech_receiver.base.write\", return_value=None\n    ), mock.patch(\"logitech_receiver.base._get_next_sw_id\", return_value=next_sw_id):\n        if raise_exception:\n            with pytest.raises(exceptions.FeatureCallError) as context:\n                base.request(handle, device_number, next_sw_id, return_error=return_error)\n            assert context.value.number == device_number\n            assert context.value.request == next_sw_id\n            assert context.value.error == error_code\n            assert context.value.params == b\"\"\n\n        else:\n            result = base.request(handle, device_number, next_sw_id, return_error=return_error)\n            assert result == (error_code if return_error else None)\n\n\n@pytest.mark.skipif(sys.platform == \"darwin\", reason=\"Test only runs on Linux\")\n@pytest.mark.parametrize(\n    \"simulated_error, expected_result\",\n    [\n        (Hidpp10Error.INVALID_SUB_ID_COMMAND, 1.0),\n        (Hidpp10Error.RESOURCE_ERROR, None),\n        (Hidpp10Error.CONNECTION_REQUEST_FAILED, None),\n        (Hidpp10Error.UNKNOWN_DEVICE, exceptions.NoSuchDevice),\n    ],\n)\ndef test_ping_errors(simulated_error: Hidpp10Error, expected_result):\n    handle = 1\n    device_number = 1\n\n    next_sw_id = 0x05\n    reply_data_sw_id = struct.pack(\"!H\", 0x0010 | next_sw_id)\n\n    with mock.patch(\n        \"logitech_receiver.base._read\",\n        return_value=(HIDPP_SHORT_MESSAGE_ID, device_number, b\"\\x8f\" + reply_data_sw_id + bytes([simulated_error])),\n    ), mock.patch(\"logitech_receiver.base._get_next_sw_id\", return_value=next_sw_id):\n        if isinstance(expected_result, type) and issubclass(expected_result, Exception):\n            with pytest.raises(expected_result) as context:\n                base.ping(handle=handle, devnumber=device_number)\n            assert context.value.number == device_number\n            assert context.value.request == struct.unpack(\"!H\", reply_data_sw_id)[0]\n\n        else:\n            result = base.ping(handle=handle, devnumber=device_number)\n            assert result == expected_result\n"
  },
  {
    "path": "tests/logitech_receiver/test_base_usb.py",
    "content": "import pytest\n\nfrom logitech_receiver import base_usb\nfrom logitech_receiver.common import LOGITECH_VENDOR_ID\n\n\ndef test_ensure_known_receivers_mappings_are_valid():\n    for key, receiver in base_usb.KNOWN_RECEIVERS.items():\n        assert key == receiver[\"product_id\"]\n\n\ndef test_get_receiver_info():\n    expected = {\n        \"vendor_id\": LOGITECH_VENDOR_ID,\n        \"product_id\": 0xC548,\n        \"usb_interface\": 2,\n        \"name\": \"Bolt Receiver\",\n        \"receiver_kind\": \"bolt\",\n        \"max_devices\": 6,\n        \"may_unpair\": True,\n    }\n\n    res = base_usb.get_receiver_info(0xC548)\n\n    assert res == expected\n\n\ndef test_get_receiver_info_unknown_device_fails():\n    with pytest.raises(ValueError):\n        base_usb.get_receiver_info(0xC500)\n"
  },
  {
    "path": "tests/logitech_receiver/test_common.py",
    "content": "from enum import IntFlag\n\nimport pytest\nimport yaml\n\nfrom logitech_receiver import common\n\n\ndef test_crc16():\n    value = b\"123456789\"\n    expected = 0x29B1\n\n    result = common.crc16(value)\n\n    assert result == expected\n\n\ndef test_named_int():\n    named_int = common.NamedInt(0x2, \"pulse\")\n\n    assert named_int.name == \"pulse\"\n    assert named_int == 2\n    assert repr(named_int) == \"NamedInt(2, 'pulse')\"\n\n\ndef test_named_int_comparison():\n    named_int = common.NamedInt(0, \"entry\")\n    named_int_equal = common.NamedInt(0, \"entry\")\n    named_int_unequal_name = common.NamedInt(0, \"unequal\")\n    named_int_unequal_value = common.NamedInt(5, \"entry\")\n    named_int_unequal = common.NamedInt(2, \"unequal\")\n\n    assert named_int == named_int_equal\n    assert named_int != named_int_unequal_name\n    assert named_int != named_int_unequal_value\n    assert named_int != named_int_unequal\n    assert named_int is not None\n    assert named_int == 0\n    assert named_int == \"entry\"\n\n\ndef test_named_int_comparison_exception():\n    named_int = common.NamedInt(0, \"entry\")\n\n    with pytest.raises(TypeError):\n        assert named_int == b\"\\x00\"\n\n\ndef test_named_int_conversions():\n    named_int = common.NamedInt(2, \"two\")\n\n    assert named_int.bytes() == b\"\\x00\\x02\"\n    assert str(named_int) == \"two\"\n\n\ndef test_named_int_yaml():\n    named_int = common.NamedInt(2, \"two\")\n\n    yaml_string = yaml.dump(named_int)\n\n    #    assert yaml_string == \"!NamedInt {name: two, value: 2}\\n\"\n\n    yaml_load = yaml.safe_load(yaml_string)\n\n    assert yaml_load == named_int\n\n\ndef test_named_ints():\n    named_ints = common.NamedInts(empty=0, critical=5, low=20, good=50, full=90)\n\n    assert named_ints.empty == 0\n    assert named_ints.empty.name == \"empty\"\n    assert named_ints.critical == 5\n    assert named_ints.critical.name == \"critical\"\n    assert named_ints.low == 20\n    assert named_ints.low.name == \"low\"\n    assert named_ints.good == 50\n    assert named_ints.good.name == \"good\"\n    assert named_ints.full == 90\n    assert named_ints.full.name == \"full\"\n\n    assert len(named_ints) == 5\n    assert 5 in named_ints\n    assert 6 not in named_ints\n    assert \"critical\" in named_ints\n    assert \"easy\" not in named_ints\n    assert common.NamedInt(5, \"critical\") in named_ints\n    assert common.NamedInt(5, \"five\") not in named_ints\n    assert common.NamedInt(6, \"critical\") not in named_ints\n    assert named_ints[5] == \"critical\"\n    assert named_ints[\"critical\"] == \"critical\"\n    assert named_ints[66] is None\n    assert named_ints[\"5\"] is None\n    assert len(named_ints[:]) == len(named_ints)\n    assert len(named_ints[0:100]) == len(named_ints)\n    assert len(named_ints[5:90]) == 3\n    assert len(named_ints[5:]) == 4\n    assert named_ints[90:5] == []\n\n\ndef test_named_ints_fallback():\n    named_ints = common.NamedInts(empty=0, critical=5, low=20, good=50, full=90)\n    named_ints._fallback = lambda x: str(x)\n\n    fallback = named_ints[80]\n\n    assert fallback == common.NamedInt(80, \"80\")\n\n\ndef test_named_ints_list():\n    named_ints_list = common.NamedInts.list([0, 5, 20, 50, 90])\n\n    assert len(named_ints_list) == 5\n    assert 50 in named_ints_list\n    assert 60 not in named_ints_list\n\n\ndef test_named_ints_range():\n    named_ints_range = common.NamedInts.range(0, 5)\n\n    assert len(named_ints_range) == 6\n    assert 4 in named_ints_range\n    assert 6 not in named_ints_range\n\n\n@pytest.mark.parametrize(\n    \"code, expected_flags\",\n    [\n        (0, []),\n        (0b0010, [\"two\"]),\n        (0b0101, [\"one\", \"three\"]),\n        (0b1001, [\"one\", \"unknown:000008\"]),\n    ],\n)\ndef test_named_ints_flag_names(code, expected_flags):\n    named_ints_flag_bits = common.NamedInts(one=0b001, two=0b010, three=0b100)\n\n    flags = list(named_ints_flag_bits.flag_names(code))\n\n    assert flags == expected_flags\n\n\n@pytest.mark.parametrize(\n    \"code, expected_flags\",\n    [\n        (0, []),\n        (0b0010, [\"two\"]),\n        (0b0101, [\"one\", \"three\"]),\n        (0b1001, [\"one\", \"unknown:000008\"]),\n    ],\n)\ndef test_flag_names(code, expected_flags):\n    class ExampleFlag(IntFlag):\n        one = 0x1\n        two = 0x2\n        three = 0x4\n\n    flags = common.flag_names(ExampleFlag, code)\n\n    assert list(flags) == expected_flags\n\n\ndef test_named_ints_setitem():\n    named_ints = common.NamedInts(empty=0, critical=5, low=20, good=50, full=90)\n\n    named_ints[55] = \"better\"\n    named_ints[60] = common.NamedInt(60, \"sixty\")\n    with pytest.raises(TypeError):\n        named_ints[70] = 70\n    with pytest.raises(ValueError):\n        named_ints[70] = \"empty\"\n    with pytest.raises(ValueError):\n        named_ints[50] = \"new\"\n\n    assert named_ints[55] == \"better\"\n    assert named_ints[60] == \"sixty\"\n\n\ndef test_named_ints_other():\n    named_ints = common.NamedInts(empty=0, critical=5)\n    named_ints_2 = common.NamedInts(good=50)\n\n    union = named_ints.__or__(named_ints_2)\n\n    assert list(named_ints) == [common.NamedInt(0, \"empty\"), common.NamedInt(5, \"critical\")]\n    assert len(named_ints) == 2\n    assert repr(named_ints) == \"NamedInts(NamedInt(0, 'empty'), NamedInt(5, 'critical'))\"\n    assert len(union) == 3\n    assert list(union) == [common.NamedInt(0, \"empty\"), common.NamedInt(5, \"critical\"), common.NamedInt(50, \"good\")]\n\n\ndef test_unsorted_named_ints():\n    named_ints = common.UnsortedNamedInts(critical=5, empty=0)\n    named_ints_2 = common.UnsortedNamedInts(good=50)\n\n    union = named_ints.__or__(named_ints_2)\n    unionr = named_ints_2.__or__(named_ints)\n\n    assert len(union) == 3\n    assert list(union) == [common.NamedInt(5, \"critical\"), common.NamedInt(0, \"empty\"), common.NamedInt(50, \"good\")]\n    assert len(unionr) == 3\n    assert list(unionr) == [common.NamedInt(50, \"good\"), common.NamedInt(5, \"critical\"), common.NamedInt(0, \"empty\")]\n\n\n@pytest.mark.parametrize(\n    \"bytes_input, expected_output\",\n    [\n        (b\"\\x01\\x02\\x03\\x04\", \"01020304\"),\n        (b\"\", \"\"),\n    ],\n)\ndef test_strhex(bytes_input, expected_output):\n    result = common.strhex(bytes_input)\n\n    assert result == expected_output\n\n\ndef test_bytest2int():\n    value = b\"\\x12\\x34\\x56\\x78\"\n    expected = 0x12345678\n\n    result = common.bytes2int(value)\n\n    assert result == expected\n\n\ndef test_int2bytes():\n    value = 0x12345678\n    expected = b\"\\x12\\x34\\x56\\x78\"\n\n    result = common.int2bytes(value)\n\n    assert result == expected\n\n\ndef test_kw_exception():\n    e = common.KwException(foo=0, bar=\"bar\")\n\n    assert e.foo == 0\n    assert e.bar == \"bar\"\n\n\n@pytest.mark.parametrize(\n    \"status, expected_level, expected_ok, expected_charging, expected_string\",\n    [\n        (common.BatteryStatus.FULL, common.BatteryLevelApproximation.FULL, True, True, \"Battery: full (full)\"),\n        (common.BatteryStatus.ALMOST_FULL, common.BatteryLevelApproximation.GOOD, True, True, \"Battery: good (almost full)\"),\n        (common.BatteryStatus.RECHARGING, common.BatteryLevelApproximation.GOOD, True, True, \"Battery: good (recharging)\"),\n        (\n            common.BatteryStatus.SLOW_RECHARGE,\n            common.BatteryLevelApproximation.LOW,\n            True,\n            True,\n            \"Battery: low (slow recharge)\",\n        ),\n        (common.BatteryStatus.DISCHARGING, None, True, False, \"\"),\n    ],\n)\ndef test_battery(status, expected_level, expected_ok, expected_charging, expected_string):\n    battery = common.Battery(None, None, status, None)\n\n    assert battery.status == status\n    assert battery.level == expected_level\n    assert battery.ok() == expected_ok\n    assert battery.charging() == expected_charging\n    assert battery.to_str() == expected_string\n\n\ndef test_battery_2():\n    battery = common.Battery(50, None, common.BatteryStatus.DISCHARGING, None)\n\n    assert battery.status == common.BatteryStatus.DISCHARGING\n    assert battery.level == 50\n    assert battery.ok()\n    assert not battery.charging()\n    assert battery.to_str() == \"Battery: 50% (discharging)\"\n"
  },
  {
    "path": "tests/logitech_receiver/test_desktop_notifications.py",
    "content": "from unittest import mock\n\nfrom logitech_receiver import desktop_notifications\n\n# depends on external environment, so make some tests dependent on availability\n\n\ndef test_init():\n    result = desktop_notifications.init()\n\n    assert result == desktop_notifications.available\n\n\ndef test_uninit():\n    assert desktop_notifications.uninit() is None\n\n\nclass MockDevice(mock.Mock):\n    name = \"MockDevice\"\n\n    def close():\n        return True\n\n\ndef test_show():\n    dev = MockDevice()\n    reason = \"unknown\"\n    result = desktop_notifications.show(dev, reason)\n    assert result is not None if desktop_notifications.available else result is None\n"
  },
  {
    "path": "tests/logitech_receiver/test_device.py",
    "content": "## Copyright (C) 2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nfrom dataclasses import dataclass\nfrom functools import partial\nfrom typing import Optional\n\nimport pytest\n\nfrom logitech_receiver import common\nfrom logitech_receiver import device\nfrom logitech_receiver import hidpp20\nfrom logitech_receiver.common import BatteryLevelApproximation\nfrom logitech_receiver.common import BatteryStatus\n\nfrom . import fake_hidpp\n\n\nclass LowLevelInterfaceFake:\n    def __init__(self, responses=None):\n        self.responses = responses\n\n    def open_path(self, path) -> int:\n        return fake_hidpp.open_path(path)\n\n    def find_paired_node(self, receiver_path: str, index: int, timeout: int):\n        return None\n\n    def request(self, response, *args, **kwargs):\n        func = partial(fake_hidpp.request, self.responses)\n        return func(response, *args, **kwargs)\n\n    def ping(self, response, *args, **kwargs):\n        func = partial(fake_hidpp.ping, self.responses)\n        return func(response, *args, **kwargs)\n\n    def close(self, *args, **kwargs):\n        pass\n\n\n@dataclass\nclass DeviceInfoStub:\n    path: str\n    product_id: str\n    vendor_id: int = 1133\n    hidpp_short: bool = False\n    hidpp_long: bool = True\n    bus_id: int = 0x0003  # USB\n    serial: str = \"aa:aa:aa;aa\"\n\n\ndi_bad_handle = DeviceInfoStub(None, product_id=\"CCCC\")\ndi_error = DeviceInfoStub(11, product_id=\"CCCC\")\ndi_CCCC = DeviceInfoStub(\"11\", product_id=\"CCCC\")\ndi_C318 = DeviceInfoStub(\"11\", product_id=\"C318\")\ndi_B530 = DeviceInfoStub(\"11\", product_id=\"B350\", bus_id=0x0005)\ndi_C068 = DeviceInfoStub(\"11\", product_id=\"C06B\")\ndi_C08A = DeviceInfoStub(\"11\", product_id=\"C08A\")\ndi_DDDD = DeviceInfoStub(\"11\", product_id=\"DDDD\")\n\n\n@pytest.mark.parametrize(\n    \"device_info, responses, expected_success\",\n    [\n        (di_bad_handle, fake_hidpp.r_empty, None),\n        (di_error, fake_hidpp.r_empty, False),\n        (di_CCCC, fake_hidpp.r_empty, True),\n    ],\n)\ndef test_create_device(device_info, responses, expected_success):\n    low_level_mock = LowLevelInterfaceFake(responses)\n    if expected_success is None:\n        with pytest.raises(PermissionError):\n            device.create_device(low_level_mock, device_info)\n    elif not expected_success:\n        with pytest.raises(Exception):  # noqa: B017\n            device.create_device(low_level_mock, device_info)\n    else:\n        test_device = device.create_device(low_level_mock, device_info)\n        assert bool(test_device) == expected_success\n\n\n@pytest.mark.parametrize(\n    \"device_info, responses, expected_codename, expected_name, expected_kind\",\n    [(di_CCCC, fake_hidpp.r_empty, \"?? (CCCC)\", \"Unknown device CCCC\", \"?\")],\n)\ndef test_device_name(device_info, responses, expected_codename, expected_name, expected_kind):\n    low_level = LowLevelInterfaceFake(responses)\n\n    test_device = device.create_device(low_level, device_info)\n\n    assert test_device.codename == expected_codename\n    assert test_device.name == expected_name\n    assert test_device.kind == expected_kind\n\n\n@pytest.mark.parametrize(\n    \"device_info, responses, handle, _name, _codename, number, protocol, registers\",\n    zip(\n        [di_CCCC, di_C318, di_B530, di_C068, di_C08A, di_DDDD],\n        [\n            fake_hidpp.r_empty,\n            fake_hidpp.r_keyboard_1,\n            fake_hidpp.r_keyboard_2,\n            fake_hidpp.r_mouse_1,\n            fake_hidpp.r_mouse_2,\n            fake_hidpp.r_mouse_3,\n        ],\n        [0x11, 0x11, 0x11, 0x11, 0x11, 0x11],\n        [None, \"Illuminated Keyboard\", \"Craft Advanced Keyboard\", \"G700 Gaming Mouse\", \"MX Vertical Wireless Mouse\", None],\n        [None, \"Illuminated\", \"Craft\", \"G700\", \"MX Vertical\", None],\n        [0xFF, 0x0, 0xFF, 0x0, 0xFF, 0xFF],\n        [1.0, 1.0, 4.5, 1.0, 4.5, 4.5],\n        [[], [], [], (common.NamedInt(7, \"battery status\"), common.NamedInt(81, \"three leds\")), [], []],\n    ),\n)\ndef test_device_info(device_info, responses, handle, _name, _codename, number, protocol, registers):\n    test_device = device.Device(LowLevelInterfaceFake(responses), None, None, None, handle=handle, device_info=device_info)\n\n    assert test_device.handle == handle\n    assert test_device._name == _name\n    assert test_device._codename == _codename\n    assert test_device.number == number\n    assert test_device._protocol == protocol\n    assert test_device.registers == registers\n\n    assert bool(test_device)\n\n    test_device.__del__()\n    assert not bool(test_device)\n\n\n@dataclass\nclass FakeReceiver:\n    path: str = \"11\"\n    handle: int = 0x11\n    codename: Optional[str] = None\n\n    def device_codename(self, number):\n        return self.codename\n\n    def __contains__(self, dev):\n        return True\n\n\npi_CCCC = {\"wpid\": \"CCCC\", \"kind\": 0, \"serial\": None, \"polling\": \"1ms\", \"power_switch\": \"top\"}\npi_2011 = {\"wpid\": \"2011\", \"kind\": 1, \"serial\": \"1234\", \"polling\": \"2ms\", \"power_switch\": \"bottom\"}\npi_4066 = {\"wpid\": \"4066\", \"kind\": 1, \"serial\": \"5678\", \"polling\": \"4ms\", \"power_switch\": \"left\"}\npi_1007 = {\"wpid\": \"1007\", \"kind\": 2, \"serial\": \"1234\", \"polling\": \"8ms\", \"power_switch\": \"right\"}\npi_407B = {\"wpid\": \"407B\", \"kind\": 2, \"serial\": \"5678\", \"polling\": \"1ms\", \"power_switch\": \"left\"}\npi_DDDD = {\"wpid\": \"DDDD\", \"kind\": 2, \"serial\": \"1234\", \"polling\": \"2ms\", \"power_switch\": \"top\"}\n\n\n@pytest.mark.parametrize(\n    \"number, pairing_info, responses, handle, _name, codename, p, p2, name\",\n    zip(\n        range(1, 7),\n        [pi_CCCC, pi_2011, pi_4066, pi_1007, pi_407B, pi_DDDD],\n        [\n            fake_hidpp.r_empty,\n            fake_hidpp.r_keyboard_1,\n            fake_hidpp.r_keyboard_2,\n            fake_hidpp.r_mouse_1,\n            fake_hidpp.r_mouse_2,\n            fake_hidpp.r_mouse_3,\n        ],\n        [0x11, 0x11, 0x11, 0x11, 0x11, 0x11],\n        [None, \"Wireless Keyboard K520\", \"Craft Advanced Keyboard\", \"MX Air\", \"MX Vertical Wireless Mouse\", None],\n        [\"CODE\", \"K520\", \"Craft\", \"MX Air\", \"MX Vertical\", \"CODE\"],\n        [None, 1.0, 4.5, 1.0, 4.5, None],\n        [1.0, 1.0, 4.5, 1.0, 4.5, 4.5],\n        [\n            \"CODE\",\n            \"Wireless Keyboard K520\",\n            \"Craft Advanced Keyboard\",\n            \"MX Air\",\n            \"MX Vertical Wireless Mouse\",\n            \"ABABABABABABABADED\",\n        ],\n    ),\n)\ndef test_device_receiver(number, pairing_info, responses, handle, _name, codename, p, p2, name):\n    low_level = LowLevelInterfaceFake(responses)\n    low_level.request = partial(fake_hidpp.request, fake_hidpp.replace_number(responses, number))\n    low_level.ping = partial(fake_hidpp.ping, fake_hidpp.replace_number(responses, number))\n\n    test_device = device.Device(low_level, FakeReceiver(codename=\"CODE\"), number, True, pairing_info, handle=handle)\n    test_device.receiver.device = test_device\n\n    assert test_device.handle == handle\n    assert test_device._name == _name\n    assert test_device.codename == codename\n    assert test_device.number == number\n    assert test_device._protocol == p\n    assert test_device.protocol == p2\n    assert test_device.codename == codename\n    assert test_device.name == name\n\n    assert test_device == test_device\n    assert not (test_device != test_device)\n    assert bool(test_device)\n\n    test_device.__del__()\n\n\n@pytest.mark.parametrize(\n    \"number, info, responses, handle, unitId, modelId, task_id, kind, firmware, serial, id, psl, rate\",\n    zip(\n        range(1, 7),\n        [pi_CCCC, pi_2011, pi_4066, pi_1007, pi_407B, pi_DDDD],\n        [\n            fake_hidpp.r_empty,\n            fake_hidpp.r_keyboard_1,\n            fake_hidpp.r_keyboard_2,\n            fake_hidpp.r_mouse_1,\n            fake_hidpp.r_mouse_2,\n            fake_hidpp.r_mouse_3,\n        ],\n        [None, 0x11, 0x11, 0x11, 0x11, 0x11],\n        [None, None, \"12345678\", None, None, \"12345679\"],  # unitId\n        [None, None, \"1234567890AB\", None, None, \"123456780000\"],  # modelId\n        [None, None, {\"btid\": \"1234\", \"wpid\": \"5678\", \"usbid\": \"90AB\"}, None, None, {\"usbid\": \"1234\"}],  # tid_map\n        [\"?\", 1, 1, 2, 2, 2],  # kind\n        [(), True, (), (), (), True],  # firmware\n        [None, \"1234\", \"5678\", \"1234\", \"5678\", \"1234\"],  # serial\n        [\"\", \"1234\", \"12345678\", \"1234\", \"5678\", \"12345679\"],  # id\n        [\"top\", \"bottom\", \"left\", \"right\", \"left\", \"top\"],  # power switch location\n        [\"1ms\", \"2ms\", \"4ms\", \"8ms\", \"1ms\", \"9ms\"],  # polling rate\n    ),\n)\ndef test_device_ids(number, info, responses, handle, unitId, modelId, task_id, kind, firmware, serial, id, psl, rate):\n    low_level = LowLevelInterfaceFake(responses)\n    low_level.request = partial(fake_hidpp.request, fake_hidpp.replace_number(responses, number))\n    low_level.ping = partial(fake_hidpp.ping, fake_hidpp.replace_number(responses, number))\n\n    test_device = device.Device(low_level, FakeReceiver(), number, True, info, handle=handle)\n\n    assert test_device.unitId == unitId\n    assert test_device.modelId == modelId\n    assert test_device.tid_map == task_id\n    assert test_device.kind == kind\n    assert test_device.firmware == firmware or len(test_device.firmware) > 0 and firmware is True\n    assert test_device.id == id\n    assert test_device.power_switch_location == psl\n    assert test_device.polling_rate == rate\n\n\nclass FakeDevice(device.Device):  # a fully functional Device but its HID++ functions look at local data\n    def __init__(self, responses, *args, **kwargs):\n        self.responses = responses\n        super().__init__(LowLevelInterfaceFake(responses), *args, **kwargs)\n\n    request = fake_hidpp.Device.request\n    ping = fake_hidpp.Device.ping\n\n\n@pytest.mark.parametrize(\n    \"device_info, responses, protocol, led, keys, remap, gestures, backlight, profiles\",\n    [\n        (di_CCCC, fake_hidpp.r_empty, 1.0, type(None), None, None, None, None, None),\n        (di_C318, fake_hidpp.r_empty, 1.0, type(None), None, None, None, None, None),\n        (di_B530, fake_hidpp.r_keyboard_1, 1.0, type(None), None, None, None, None, None),\n        (di_B530, fake_hidpp.r_keyboard_2, 2.0, type(None), 4, 0, 0, None, None),\n        (di_B530, fake_hidpp.complex_responses_1, 4.5, hidpp20.LEDEffectsInfo, 0, 0, 0, None, None),\n        (di_B530, fake_hidpp.complex_responses_2, 4.5, hidpp20.RGBEffectsInfo, 8, 3, 1, True, True),\n    ],\n)\ndef test_device_complex(device_info, responses, protocol, led, keys, remap, gestures, backlight, profiles, mocker):\n    test_device = FakeDevice(responses, None, None, True, device_info=device_info)\n    test_device._name = \"TestDevice\"\n    test_device._protocol = protocol\n    spy_request = mocker.spy(test_device, \"request\")\n\n    assert type(test_device.led_effects) == led\n    if keys is None:\n        assert test_device.keys == keys\n    else:\n        assert len(test_device.keys) == keys\n    if remap is None:\n        assert test_device.remap_keys == remap\n    else:\n        assert len(test_device.remap_keys) == remap\n    assert (test_device.gestures is None) == (gestures is None)\n    assert (test_device.backlight is None) == (backlight is None)\n    assert (test_device.profiles is None) == (profiles is None)\n\n    test_device.set_configuration(55)\n    if protocol > 1.0:\n        spy_request.assert_called_with(0x210, 55, no_reply=False)\n    test_device.reset()\n    if protocol > 1.0:\n        spy_request.assert_called_with(0x210, 0, no_reply=False)\n\n\n@pytest.mark.parametrize(\n    \"device_info, responses, protocol, p, persister, settings\",\n    [\n        (di_CCCC, fake_hidpp.r_empty, 1.0, None, None, 0),\n        (di_C318, fake_hidpp.r_empty, 1.0, {}, {}, 0),\n        (di_C318, fake_hidpp.r_keyboard_1, 1.0, {\"n\": \"n\"}, {\"n\": \"n\"}, 1),\n        (di_B530, fake_hidpp.r_keyboard_2, 4.5, {\"m\": \"m\"}, {\"m\": \"m\"}, 1),\n        (di_C068, fake_hidpp.r_mouse_1, 1.0, {\"o\": \"o\"}, {\"o\": \"o\"}, 2),\n        (di_C08A, fake_hidpp.r_mouse_2, 4.5, {\"p\": \"p\"}, {\"p\": \"p\"}, 0),\n    ],\n)\ndef test_device_settings(device_info, responses, protocol, p, persister, settings, mocker):\n    mocker.patch(\"solaar.configuration.persister\", return_value=p)\n    test_device = FakeDevice(responses, None, None, True, device_info=device_info)\n    test_device._name = \"TestDevice\"\n    test_device._protocol = protocol\n\n    assert test_device.persister == persister\n    assert len(test_device.settings) == settings\n\n\n@pytest.mark.parametrize(\n    \"device_info, responses, protocol, expected_battery, changed\",\n    [\n        (di_C318, fake_hidpp.r_empty, 1.0, None, {\"active\": True, \"alert\": 0, \"reason\": None}),\n        (\n            di_C318,\n            fake_hidpp.r_keyboard_1,\n            1.0,\n            common.Battery(BatteryLevelApproximation.GOOD.value, None, BatteryStatus.DISCHARGING, None),\n            {\"active\": True, \"alert\": 0, \"reason\": None},\n        ),\n        (\n            di_B530,\n            fake_hidpp.r_keyboard_2,\n            4.5,\n            common.Battery(18, 52, None, None),\n            {\"active\": True, \"alert\": 0, \"reason\": None},\n        ),\n    ],\n)\ndef test_device_battery(device_info, responses, protocol, expected_battery, changed, mocker):\n    test_device = FakeDevice(responses, None, None, online=True, device_info=device_info)\n    test_device._name = \"TestDevice\"\n    test_device._protocol = protocol\n    spy_changed = mocker.spy(test_device, \"changed\")\n\n    assert test_device.battery() == expected_battery\n    test_device.read_battery()\n    spy_changed.assert_called_with(**changed)\n"
  },
  {
    "path": "tests/logitech_receiver/test_diversion.py",
    "content": "import textwrap\n\nfrom unittest import mock\nfrom unittest.mock import mock_open\n\nimport pytest\n\nfrom logitech_receiver import diversion\nfrom logitech_receiver.base import HIDPPNotification\nfrom logitech_receiver.hidpp20_constants import SupportedFeature\n\n\n@pytest.fixture\ndef rule_config():\n    rule_content = \"\"\"\n    %YAML 1.3\n    ---\n    - MouseGesture: Mouse Left\n    - KeyPress:\n      - [Control_L, Alt_L, Left]\n      - click\n    ...\n    ---\n    - MouseGesture: Mouse Up\n    - KeyPress:\n      - [Super_L, Up]\n      - click\n    ...\n    ---\n    - Test: [thumb_wheel_up, 10]\n    - KeyPress:\n      - [Control_L, Page_Down]\n      - click\n    ...\n    ---\n    \"\"\"\n    return textwrap.dedent(rule_content)\n\n\ndef test_load_rule_config(rule_config):\n    expected_rules = [\n        [\n            diversion.MouseGesture,\n            diversion.KeyPress,\n        ],\n        [diversion.MouseGesture, diversion.KeyPress],\n        [diversion.Test, diversion.KeyPress],\n    ]\n\n    with mock.patch(\"builtins.open\", new=mock_open(read_data=rule_config)):\n        loaded_rules = diversion._load_rule_config(file_path=mock.Mock())\n\n    assert len(loaded_rules.components) == 2  # predefined and user configured rules\n    user_configured_rules = loaded_rules.components[0]\n    assert isinstance(user_configured_rules, diversion.Rule)\n\n    for components, expected_components in zip(user_configured_rules.components, expected_rules):\n        for component, expected_component in zip(components.components, expected_components):\n            assert isinstance(component, expected_component)\n\n\ndef test_diversion_rule():\n    args = [\n        {\n            \"Rule\": [  # Implement problematic keys for Craft and MX Master\n                {\"Rule\": [{\"Key\": [\"Brightness Down\", \"pressed\"]}, {\"KeyPress\": \"XF86_MonBrightnessDown\"}]},\n                {\"Rule\": [{\"Key\": [\"Brightness Up\", \"pressed\"]}, {\"KeyPress\": \"XF86_MonBrightnessUp\"}]},\n            ]\n        },\n    ]\n\n    rule = diversion.Rule(args)\n\n    assert len(rule.components) == 1\n    root_rule = rule.components[0]\n    assert isinstance(root_rule, diversion.Rule)\n\n    assert len(root_rule.components) == 2\n    for component in root_rule.components:\n        assert isinstance(component, diversion.Rule)\n        assert len(component.components) == 2\n\n        key = component.components[0]\n        assert isinstance(key, diversion.Key)\n        key = component.components[1]\n        assert isinstance(key, diversion.KeyPress)\n\n\ndef test_key_is_down():\n    result = diversion.key_is_down(key=diversion.CONTROL.G2)\n\n    assert result is False\n\n\ndef test_feature():\n    expected_data = {\"Feature\": \"CONFIG CHANGE\"}\n\n    result = diversion.Feature(\"CONFIG_CHANGE\")\n\n    assert result.data() == expected_data\n\n\n@pytest.mark.parametrize(\n    \"feature, data\",\n    [\n        (\n            SupportedFeature.REPROG_CONTROLS_V4,\n            [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],\n        ),\n        (SupportedFeature.GKEY, [0x01, 0x02, 0x03, 0x04]),\n        (SupportedFeature.MKEYS, [0x01, 0x02, 0x03, 0x04]),\n        (SupportedFeature.MR, [0x01, 0x02, 0x03, 0x04]),\n        (SupportedFeature.THUMB_WHEEL, [0x01, 0x02, 0x03, 0x04, 0x05]),\n        (SupportedFeature.DEVICE_UNIT_ID, [0x01, 0x02, 0x03, 0x04, 0x05]),\n    ],\n)\ndef test_process_notification(feature, data):\n    device_mock = mock.Mock()\n    notification = HIDPPNotification(\n        report_id=0x01,\n        devnumber=1,\n        sub_id=0x13,\n        address=0x00,\n        data=bytes(data),\n    )\n\n    diversion.process_notification(device_mock, notification, feature)\n"
  },
  {
    "path": "tests/logitech_receiver/test_hidpp10.py",
    "content": "from dataclasses import dataclass\nfrom dataclasses import field\nfrom typing import Any\nfrom typing import List\nfrom typing import Optional\n\nimport pytest\n\nfrom logitech_receiver import common\nfrom logitech_receiver import hidpp10\nfrom logitech_receiver import hidpp10_constants\nfrom logitech_receiver.hidpp10_constants import PairingError\nfrom logitech_receiver.hidpp10_constants import Registers\n\n_hidpp10 = hidpp10.Hidpp10()\n\n\n@dataclass\nclass Response:\n    response: Optional[str]\n    request_id: int\n    params: Any\n\n\n@dataclass\nclass Device:\n    name: str = \"Device\"\n    online: bool = True\n    kind: str = \"fake\"\n    protocol: float = 1.0\n    isDevice: bool = False  # incorrect, but useful here\n    registers: List[Registers] = field(default_factory=list)\n    responses: List[Response] = field(default_factory=list)\n\n    def request(self, id, params=None, no_reply=False):\n        if params is None:\n            params = []\n        print(\"REQUEST \", self.name, hex(id), params)\n        for r in self.responses:\n            if id == r.request_id and params == r.params:\n                print(\"RESPONSE\", self.name, hex(r.request_id), r.params, r.response)\n                return bytes.fromhex(r.response) if r.response is not None else None\n\n\ndevice_offline = Device(\"OFFLINE\", False)\ndevice_leds = Device(\"LEDS\", True, registers=[Registers.THREE_LEDS, Registers.BATTERY_STATUS])\ndevice_features = Device(\"FEATURES\", True, protocol=4.5)\n\nregisters_standard = [Registers.BATTERY_STATUS, Registers.FIRMWARE]\nresponses_standard = [\n    Response(\"555555\", 0x8100 | Registers.BATTERY_STATUS, 0x00),\n    Response(\"666666\", 0x8100 | Registers.BATTERY_STATUS, 0x10),\n    Response(\"777777\", 0x8000 | Registers.BATTERY_STATUS, 0x00),\n    Response(\"888888\", 0x8000 | Registers.BATTERY_STATUS, 0x10),\n    Response(\"052100\", 0x8100 | Registers.BATTERY_STATUS, []),\n    Response(\"ABCDEF\", 0x8100 | Registers.FIRMWARE, 0x01),\n    Response(\"ABCDEF\", 0x8100 | Registers.FIRMWARE, 0x02),\n    Response(\"ABCDEF\", 0x8100 | Registers.FIRMWARE, 0x03),\n    Response(\"ABCDEF\", 0x8100 | Registers.FIRMWARE, 0x04),\n    Response(\"000900\", 0x8100 | Registers.NOTIFICATIONS, []),\n    Response(\"101010\", 0x8100 | Registers.MOUSE_BUTTON_FLAGS, []),\n    Response(\"010101\", 0x8100 | Registers.KEYBOARD_FN_SWAP, []),\n    Response(\"020202\", 0x8100 | Registers.DEVICES_CONFIGURATION, []),\n    Response(\"030303\", 0x8000 | Registers.DEVICES_CONFIGURATION, 0x00),\n]\ndevice_standard = Device(\"STANDARD\", True, registers=registers_standard, responses=responses_standard)\n\n\n@pytest.mark.parametrize(\n    \"device, register, param, expected_result\",\n    [\n        (device_offline, Registers.THREE_LEDS, 0x00, None),\n        (device_standard, Registers.THREE_LEDS, 0x00, None),\n        (device_standard, Registers.BATTERY_STATUS, 0x00, \"555555\"),\n        (device_standard, Registers.BATTERY_STATUS, 0x10, \"666666\"),\n    ],\n)\ndef test_read_register(device, register, param, expected_result, mocker):\n    spy_request = mocker.spy(device, \"request\")\n\n    result = hidpp10.read_register(device, register, param)\n\n    assert result == (bytes.fromhex(expected_result) if expected_result else None)\n    spy_request.assert_called_once_with(0x8100 | register, param)\n\n\n@pytest.mark.parametrize(\n    \"device, register, param, expected_result\",\n    [\n        (device_offline, Registers.THREE_LEDS, 0x00, None),\n        (device_standard, Registers.THREE_LEDS, 0x00, None),\n        (device_standard, Registers.BATTERY_STATUS, 0x00, \"777777\"),\n        (device_standard, Registers.BATTERY_STATUS, 0x10, \"888888\"),\n    ],\n)\ndef test_write_register(device, register, param, expected_result, mocker):\n    spy_request = mocker.spy(device, \"request\")\n\n    result = hidpp10.write_register(device, register, param)\n\n    assert result == (bytes.fromhex(expected_result) if expected_result else None)\n    spy_request.assert_called_once_with(0x8000 | register, param)\n\n\ndef device_charge(name, response):\n    responses = [Response(response, 0x8100 | Registers.BATTERY_CHARGE, [])]\n    return Device(name, registers=[], responses=responses)\n\n\ndevice_charge1 = device_charge(\"DISCHARGING\", \"550030\")\ndevice_charge2 = device_charge(\"RECHARGING\", \"440050\")\ndevice_charge3 = device_charge(\"FULL\", \"600090\")\ndevice_charge4 = device_charge(\"OTHER\", \"220000\")\n\n\ndef device_status(name, response):\n    responses = [Response(response, 0x8100 | Registers.BATTERY_STATUS, [])]\n    return Device(name, registers=[], responses=responses)\n\n\ndevice_status1 = device_status(\"FULL\", \"072200\")\ndevice_status2 = device_status(\"GOOD\", \"052100\")\ndevice_status3 = device_status(\"LOW\", \"032200\")\ndevice_status4 = device_status(\"CRITICAL\", \"010100\")\ndevice_status5 = device_status(\"EMPTY\", \"000000\")\ndevice_status6 = device_status(\"NOSTATUS\", \"002200\")\n\n\n@pytest.mark.parametrize(\n    \"device, expected_result, expected_register\",\n    [\n        (device_offline, None, None),\n        (device_features, None, None),\n        (device_leds, None, None),\n        (\n            device_standard,\n            common.Battery(common.BatteryLevelApproximation.GOOD, None, common.BatteryStatus.RECHARGING, None),\n            Registers.BATTERY_STATUS,\n        ),\n        (device_charge1, common.Battery(0x55, None, common.BatteryStatus.DISCHARGING, None), Registers.BATTERY_CHARGE),\n        (\n            device_charge2,\n            common.Battery(0x44, None, common.BatteryStatus.RECHARGING, None),\n            Registers.BATTERY_CHARGE,\n        ),\n        (\n            device_charge3,\n            common.Battery(0x60, None, common.BatteryStatus.FULL, None),\n            Registers.BATTERY_CHARGE,\n        ),\n        (device_charge4, common.Battery(0x22, None, None, None), Registers.BATTERY_CHARGE),\n        (\n            device_status1,\n            common.Battery(common.BatteryLevelApproximation.FULL, None, common.BatteryStatus.FULL, None),\n            Registers.BATTERY_STATUS,\n        ),\n        (\n            device_status2,\n            common.Battery(common.BatteryLevelApproximation.GOOD, None, common.BatteryStatus.RECHARGING, None),\n            Registers.BATTERY_STATUS,\n        ),\n        (\n            device_status3,\n            common.Battery(common.BatteryLevelApproximation.LOW, None, common.BatteryStatus.FULL, None),\n            Registers.BATTERY_STATUS,\n        ),\n        (\n            device_status4,\n            common.Battery(common.BatteryLevelApproximation.CRITICAL, None, None, None),\n            Registers.BATTERY_STATUS,\n        ),\n        (\n            device_status5,\n            common.Battery(common.BatteryLevelApproximation.EMPTY, None, common.BatteryStatus.DISCHARGING, None),\n            Registers.BATTERY_STATUS,\n        ),\n        (\n            device_status6,\n            common.Battery(None, None, common.BatteryStatus.FULL, None),\n            Registers.BATTERY_STATUS,\n        ),\n    ],\n)\ndef test_hidpp10_get_battery(device, expected_result, expected_register):\n    result = _hidpp10.get_battery(device)\n\n    assert result == expected_result\n    if expected_register is not None:\n        assert expected_register in device.registers\n\n\n@pytest.mark.parametrize(\n    \"device, expected_firmwares\",\n    [\n        (device_offline, []),\n        (\n            device_standard,\n            [\n                common.FirmwareKind.Firmware,\n                common.FirmwareKind.Bootloader,\n                common.FirmwareKind.Other,\n            ],\n        ),\n    ],\n)\ndef test_hidpp10_get_firmware(device, expected_firmwares):\n    firmwares = _hidpp10.get_firmware(device)\n\n    if not expected_firmwares:\n        assert firmwares is None\n    else:\n        firmware_types = [firmware.kind for firmware in firmwares]\n        assert firmware_types == expected_firmwares\n        assert len(firmwares) == len(expected_firmwares)\n\n\n@pytest.mark.parametrize(\n    \"device, level, charging, warning, p1, p2\",\n    [\n        (device_leds, common.BatteryLevelApproximation.EMPTY, False, False, 0x33, 0x00),\n        (device_leds, common.BatteryLevelApproximation.CRITICAL, False, False, 0x22, 0x00),\n        (device_leds, common.BatteryLevelApproximation.LOW, False, False, 0x20, 0x00),\n        (device_leds, common.BatteryLevelApproximation.GOOD, False, False, 0x20, 0x02),\n        (device_leds, common.BatteryLevelApproximation.FULL, False, False, 0x20, 0x22),\n        (device_leds, None, True, False, 0x30, 0x33),\n        (device_leds, None, False, True, 0x02, 0x00),\n        (device_leds, None, False, False, 0x11, 0x11),\n    ],\n)\ndef test_set_3leds(device, level, charging, warning, p1, p2, mocker):\n    spy_request = mocker.spy(device, \"request\")\n\n    _hidpp10.set_3leds(device, level, charging, warning)\n\n    spy_request.assert_called_once_with(0x8000 | Registers.THREE_LEDS, p1, p2)\n\n\n@pytest.mark.parametrize(\"device\", [device_offline, device_features])\ndef test_set_3leds_missing(device, mocker):\n    spy_request = mocker.spy(device, \"request\")\n\n    _hidpp10.set_3leds(device)\n\n    assert spy_request.call_count == 0\n\n\n@pytest.mark.parametrize(\"device\", [device_standard])\ndef test_get_notification_flags(device):\n    result = _hidpp10.get_notification_flags(device)\n\n    assert result == hidpp10_constants.NotificationFlag(int(\"000900\", 16))\n\n\ndef test_set_notification_flags(mocker):\n    device = device_standard\n    spy_request = mocker.spy(device, \"request\")\n\n    result = _hidpp10.set_notification_flags(\n        device, hidpp10_constants.NotificationFlag.BATTERY_STATUS, hidpp10_constants.NotificationFlag.WIRELESS\n    )\n\n    spy_request.assert_called_once_with(0x8000 | Registers.NOTIFICATIONS, b\"\\x10\\x01\\x00\")\n    assert result is not None\n\n\ndef test_set_notification_flags_bad(mocker):\n    device = device_features\n    spy_request = mocker.spy(device, \"request\")\n\n    result = _hidpp10.set_notification_flags(\n        device, hidpp10_constants.NotificationFlag.BATTERY_STATUS, hidpp10_constants.NotificationFlag.WIRELESS\n    )\n\n    assert spy_request.call_count == 0\n    assert result is None\n\n\n@pytest.mark.parametrize(\n    \"flag_bits, expected_names\",\n    [\n        # doesn't work in Python 3.8 and 3.10 for some reason        (None, \"\"),\n        (hidpp10_constants.NotificationFlag(0x0), \"none\"),\n        (hidpp10_constants.NotificationFlag(0x001000), \"multi touch\"),\n        (hidpp10_constants.NotificationFlag(0x080000), \"mouse extra buttons\"),\n        (\n            hidpp10_constants.NotificationFlag(0x080400),\n            (\"link quality\\n               mouse extra buttons\"),\n        ),\n    ],\n)\ndef test_notification_flag_str(flag_bits, expected_names):\n    flag_names = hidpp10_constants.flags_to_str(\n        hidpp10_constants.NotificationFlag(flag_bits) if flag_bits is not None else None, fallback=\"none\"\n    )\n\n    assert flag_names == expected_names\n\n\ndef test_get_device_features():\n    result = _hidpp10.get_device_features(device_standard)\n\n    assert result == int(\"101010\", 16)\n\n\n@pytest.mark.parametrize(\n    \"device, register, expected_result\",\n    [\n        (device_standard, Registers.BATTERY_STATUS, \"052100\"),\n        (device_standard, Registers.MOUSE_BUTTON_FLAGS, \"101010\"),\n        (device_standard, Registers.KEYBOARD_ILLUMINATION, None),\n        (device_features, Registers.KEYBOARD_ILLUMINATION, None),\n    ],\n)\ndef test_get_register(device, register, expected_result):\n    result = _hidpp10._get_register(device, register)\n\n    assert result == (int(expected_result, 16) if expected_result is not None else None)\n\n\n@pytest.mark.parametrize(\n    \"device, expected_result\",\n    [\n        (device_standard, 2),\n        (device_features, None),\n    ],\n)\ndef test_get_configuration_pending_flags(device, expected_result):\n    result = hidpp10.get_configuration_pending_flags(device)\n\n    assert result == expected_result\n\n\n@pytest.mark.parametrize(\n    \"device, expected_result\",\n    [\n        (device_standard, True),\n        (device_features, False),\n    ],\n)\ndef test_set_configuration_pending_flags(device, expected_result):\n    result = hidpp10.set_configuration_pending_flags(device, 0x00)\n\n    assert result == expected_result\n\n\ndef test_pairing_error():\n    expected_label = \"device not supported\"\n\n    res = PairingError.DEVICE_NOT_SUPPORTED.label\n\n    assert res == expected_label\n"
  },
  {
    "path": "tests/logitech_receiver/test_hidpp20_complex.py",
    "content": "## Copyright (C) 2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport pytest\nimport yaml\n\nfrom logitech_receiver import common\nfrom logitech_receiver import exceptions\nfrom logitech_receiver import hidpp20\nfrom logitech_receiver import hidpp20_constants\nfrom logitech_receiver import special_keys\nfrom logitech_receiver.hidpp20 import KeyFlag\nfrom logitech_receiver.hidpp20 import MappingFlag\nfrom logitech_receiver.hidpp20_constants import GestureId\n\nfrom . import fake_hidpp\n\n_hidpp20 = hidpp20.Hidpp20()\n\ndevice_offline = fake_hidpp.Device(\"REGISTERS\", False)\ndevice_registers = fake_hidpp.Device(\"OFFLINE\", True, 1.0)\ndevice_nofeatures = fake_hidpp.Device(\"NOFEATURES\", True, 4.5)\ndevice_zerofeatures = fake_hidpp.Device(\"ZEROFEATURES\", True, 4.5, [fake_hidpp.Response(\"0000\", 0x0000, \"0001\")])\ndevice_broken = fake_hidpp.Device(\n    \"BROKEN\", True, 4.5, [fake_hidpp.Response(\"0500\", 0x0000, \"0001\"), fake_hidpp.Response(None, 0x0100)]\n)\ndevice_standard = fake_hidpp.Device(\"STANDARD\", True, 4.5, fake_hidpp.r_keyboard_2)\n\n\n@pytest.mark.parametrize(\n    \"device, expected_result, expected_count\",\n    [\n        (device_offline, False, 0),\n        (device_registers, False, 0),\n        (device_nofeatures, False, 0),\n        (device_zerofeatures, False, 0),\n        (device_broken, False, 0),\n        (device_standard, True, 9),\n    ],\n)\ndef test_FeaturesArray_check(device, expected_result, expected_count):\n    featuresarray = hidpp20.FeaturesArray(device)\n\n    result = featuresarray._check()\n    result2 = featuresarray._check()\n\n    assert result == expected_result\n    assert result2 == expected_result\n    assert (hidpp20_constants.SupportedFeature.ROOT in featuresarray) == expected_result\n    assert len(featuresarray) == expected_count\n    assert bool(featuresarray) == expected_result\n\n\n@pytest.mark.parametrize(\n    \"device, expected0, expected1, expected2, expected5, expected5v\",\n    [\n        (device_zerofeatures, None, None, None, None, None),\n        (device_standard, 0x0000, 0x0001, 0x0020, hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, 3),\n    ],\n)\ndef test_FeaturesArray_get_feature(device, expected0, expected1, expected2, expected5, expected5v):\n    featuresarray = hidpp20.FeaturesArray(device)\n    device.features = featuresarray\n\n    result0 = featuresarray.get_feature(0)\n    result1 = featuresarray.get_feature(1)\n    result2 = featuresarray.get_feature(2)\n    result5 = featuresarray.get_feature(5)\n    result2r = featuresarray.get_feature(2)\n    result5v = featuresarray.get_feature_version(hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4)\n\n    assert result0 == expected0\n    assert result1 == expected1\n    assert result2 == expected2\n    assert result2r == expected2\n    assert result5 == expected5\n    assert result5v == expected5v\n\n\n@pytest.mark.parametrize(\n    \"device, expected_result\",\n    [\n        (device_zerofeatures, []),\n        (\n            device_standard,\n            [\n                (hidpp20_constants.SupportedFeature.ROOT, 0),\n                (hidpp20_constants.SupportedFeature.FEATURE_SET, 1),\n                (hidpp20_constants.SupportedFeature.CONFIG_CHANGE, 2),\n                (hidpp20_constants.SupportedFeature.DEVICE_FW_VERSION, 3),\n                (common.NamedInt(256, \"unknown:0100\"), 4),\n                (hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, 5),\n                (None, 6),\n                (None, 7),\n                (hidpp20_constants.SupportedFeature.BATTERY_STATUS, 8),\n            ],\n        ),\n    ],\n)\ndef test_FeaturesArray_enumerate(device, expected_result):\n    featuresarray = hidpp20.FeaturesArray(device)\n\n    result = list(featuresarray.enumerate())\n\n    assert result == expected_result\n\n\ndef test_FeaturesArray_setitem():\n    featuresarray = hidpp20.FeaturesArray(device_standard)\n\n    featuresarray[hidpp20_constants.SupportedFeature.ROOT] = 3\n    featuresarray[hidpp20_constants.SupportedFeature.FEATURE_SET] = 5\n    featuresarray[hidpp20_constants.SupportedFeature.FEATURE_SET] = 4\n\n    assert featuresarray[hidpp20_constants.SupportedFeature.FEATURE_SET] == 4\n    assert featuresarray.inverse[4] == hidpp20_constants.SupportedFeature.FEATURE_SET\n\n\ndef test_FeaturesArray_delitem():\n    featuresarray = hidpp20.FeaturesArray(device_standard)\n\n    with pytest.raises(ValueError):\n        del featuresarray[5]\n\n\n@pytest.mark.parametrize(\n    \"device, expected0, expected1, expected2, expected1v\",\n    [(device_zerofeatures, None, None, None, None), (device_standard, 0, 5, None, 3)],\n)\ndef test_FeaturesArray_getitem(device, expected0, expected1, expected2, expected1v):\n    featuresarray = hidpp20.FeaturesArray(device)\n    device.features = featuresarray\n\n    result_get0 = featuresarray[hidpp20_constants.SupportedFeature.ROOT]\n    result_get1 = featuresarray[hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4]\n    result_get2 = featuresarray[hidpp20_constants.SupportedFeature.GKEY]\n    result_1v = featuresarray.get_feature_version(hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4)\n\n    assert result_get0 == expected0\n    assert result_get1 == expected1\n    assert result_get2 == expected2\n    assert result_1v == expected1v\n\n\n@pytest.mark.parametrize(\n    \"device, index, cid, task_id, flags, default_task, expected_flags\",\n    [\n        (device_standard, 2, 1, 1, 0x30, \"Volume Up\", KeyFlag.REPROGRAMMABLE | KeyFlag.DIVERTABLE),\n        (device_standard, 1, 2, 2, 0x20, \"Volume Down\", KeyFlag.DIVERTABLE),\n    ],\n)\ndef test_reprogrammable_key_key(device, index, cid, task_id, flags, default_task, expected_flags):\n    key = hidpp20.ReprogrammableKey(device, index, cid, task_id, flags)\n\n    assert key._device == device\n    assert key.index == index\n    assert key._cid == cid\n    assert key._tid == task_id\n    assert key._flags == flags\n    assert key.key == special_keys.CONTROL[cid]\n    assert key.default_task == common.NamedInt(cid, default_task)\n    assert key.flags == expected_flags\n\n\n@pytest.mark.parametrize(\n    \"device, index, cid, task_id, flags, pos, group, gmask, default_task, expected_flags, group_names\",\n    [\n        (\n            device_standard,\n            1,\n            0x51,\n            0x39,\n            0x60,\n            0,\n            1,\n            1,\n            \"Right Click\",\n            KeyFlag.DIVERTABLE | KeyFlag.PERSISTENTLY_DIVERTABLE,\n            [\"g1\"],\n        ),\n        (\n            device_standard,\n            2,\n            0x52,\n            0x3A,\n            0x11,\n            1,\n            2,\n            3,\n            \"Mouse Middle Button\",\n            KeyFlag.MSE | KeyFlag.REPROGRAMMABLE,\n            [\"g1\", \"g2\"],\n        ),\n        (\n            device_standard,\n            3,\n            0x53,\n            0x3C,\n            0x110,\n            2,\n            2,\n            7,\n            \"Mouse Back Button\",\n            KeyFlag.REPROGRAMMABLE | KeyFlag.RAW_XY,\n            [\"g1\", \"g2\", \"g3\"],\n        ),\n    ],\n)\ndef test_reprogrammable_key_v4_key(\n    device, index, cid, task_id, flags, pos, group, gmask, default_task, expected_flags, group_names\n):\n    key = hidpp20.ReprogrammableKeyV4(device, index, cid, task_id, flags, pos, group, gmask)\n\n    assert key._device == device\n    assert key.index == index\n    assert key._cid == cid\n    assert key._tid == task_id\n    assert key._flags == flags\n    assert key.pos == pos\n    assert key.group == group\n    assert key._gmask == gmask\n    assert key.key == special_keys.CONTROL[cid]\n    assert key.default_task == common.NamedInt(cid, default_task)\n    assert key.flags == expected_flags\n    assert list(key.group_mask) == group_names\n\n\n@pytest.mark.parametrize(\n    \"responses, index, mapped_to, remappable_to, expected_mapping_flags\",\n    [\n        (fake_hidpp.responses_key, 1, \"Right Click\", common.UnsortedNamedInts(Right_Click=81, Left_Click=80), MappingFlag(0)),\n        (fake_hidpp.responses_key, 2, \"Left Click\", None, MappingFlag.DIVERTED),\n        (fake_hidpp.responses_key, 3, \"Mouse Back Button\", None, MappingFlag.DIVERTED | MappingFlag.PERSISTENTLY_DIVERTED),\n        (fake_hidpp.responses_key, 4, \"Mouse Forward Button\", None, MappingFlag.DIVERTED | MappingFlag.RAW_XY_DIVERTED),\n    ],\n)\n# these fields need access all the key data, so start by setting up a device and its key data\ndef test_reprogrammable_key_v4_query(responses, index, mapped_to, remappable_to, expected_mapping_flags):\n    device = fake_hidpp.Device(\n        \"KEY\", responses=responses, feature=hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, offset=5\n    )\n    device._keys = _hidpp20.get_keys(device)\n\n    key = device.keys[index]\n\n    assert key.mapped_to == mapped_to\n    assert (key.remappable_to == remappable_to) or remappable_to is None\n    assert key.mapping_flags == expected_mapping_flags\n\n\n@pytest.mark.parametrize(\n    \"responses, index, diverted, persistently_diverted, rawXY_reporting, remap, sets\",\n    [\n        (fake_hidpp.responses_key, 1, True, False, True, 0x52, [\"0051080000\"]),\n        (fake_hidpp.responses_key, 2, False, True, False, 0x51, [\"0052020000\", \"0052200000\", \"0052000051\"]),\n        (fake_hidpp.responses_key, 3, False, True, True, 0x50, [\"0053020000\", \"00530C0000\", \"0053300000\", \"0053000050\"]),\n        (fake_hidpp.responses_key, 4, False, False, False, 0x50, [\"0056020000\", \"0056080000\", \"0056200000\", \"0056000050\"]),\n    ],\n)\ndef test_reprogrammable_key_v4_set(responses, index, diverted, persistently_diverted, rawXY_reporting, remap, sets, mocker):\n    responses += [fake_hidpp.Response(r, 0x530, r) for r in sets]\n    device = fake_hidpp.Device(\n        \"KEY\", responses=responses, feature=hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, offset=5\n    )\n    device._keys = _hidpp20.get_keys(device)\n    device._keys._ensure_all_keys_queried()  # do this now so that the last requests are sets\n    spy_request = mocker.spy(device, \"request\")\n\n    key = device.keys[index]\n    _mapping_flags = key.mapping_flags\n\n    if hidpp20.KeyFlag.DIVERTABLE in key.flags or not diverted:\n        key.set_diverted(diverted)\n    else:\n        with pytest.raises(exceptions.FeatureNotSupported):\n            key.set_diverted(diverted)\n    assert (MappingFlag.DIVERTED in key.mapping_flags) == (diverted and hidpp20.KeyFlag.DIVERTABLE in key.flags)\n\n    if hidpp20.KeyFlag.PERSISTENTLY_DIVERTABLE in key.flags or not persistently_diverted:\n        key.set_persistently_diverted(persistently_diverted)\n    else:\n        with pytest.raises(exceptions.FeatureNotSupported):\n            key.set_persistently_diverted(persistently_diverted)\n    assert (hidpp20.MappingFlag.PERSISTENTLY_DIVERTED in key.mapping_flags) == (\n        persistently_diverted and hidpp20.KeyFlag.PERSISTENTLY_DIVERTABLE in key.flags\n    )\n\n    if hidpp20.KeyFlag.RAW_XY in key.flags or not rawXY_reporting:\n        key.set_rawXY_reporting(rawXY_reporting)\n    else:\n        with pytest.raises(exceptions.FeatureNotSupported):\n            key.set_rawXY_reporting(rawXY_reporting)\n    assert (MappingFlag.RAW_XY_DIVERTED in key.mapping_flags) == (rawXY_reporting and hidpp20.KeyFlag.RAW_XY in key.flags)\n\n    if remap in key.remappable_to or remap == 0:\n        key.remap(remap)\n    else:\n        with pytest.raises(exceptions.FeatureNotSupported):\n            key.remap(remap)\n    assert (key.mapped_to == remap) or (remap not in key.remappable_to and remap != 0)\n\n    fake_hidpp.match_requests(len(sets), responses, spy_request.call_args_list)\n\n\n@pytest.mark.parametrize(\n    \"r, index, cid, actionId, remapped, mask, status, action, modifiers, byts, remap\",\n    [\n        (fake_hidpp.responses_key, 1, 0x0051, 0x02, 0x0002, 0x01, 0, \"Mouse Button: 2\", \"Cntrl+\", \"02000201\", \"01000400\"),\n        (fake_hidpp.responses_key, 2, 0x0052, 0x01, 0x0001, 0x00, 1, \"Key: 1\", \"\", \"01000100\", \"02005004\"),\n        (fake_hidpp.responses_key, 3, 0x0053, 0x02, 0x0001, 0x00, 1, \"Mouse Button: 1\", \"\", \"02000100\", \"7FFFFFFF\"),\n    ],\n)\ndef test_remappable_action(r, index, cid, actionId, remapped, mask, status, action, modifiers, byts, remap, mocker):\n    if int(remap, 16) == special_keys.KEYS_Default:\n        responses = r + [\n            fake_hidpp.Response(\"040000\", 0x0000, \"1C00\"),\n            fake_hidpp.Response(\"00\", 0x450, f\"{cid:04X}\" + \"FF\"),\n        ]\n    else:\n        responses = r + [\n            fake_hidpp.Response(\"040000\", 0x0000, \"1C00\"),\n            fake_hidpp.Response(\"00\", 0x440, f\"{cid:04X}\" + \"FF\" + remap),\n        ]\n    device = fake_hidpp.Device(\n        \"KEY\", responses=responses, feature=hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, offset=5\n    )\n    key = hidpp20.PersistentRemappableAction(device, index, cid, actionId, remapped, mask, status)\n    spy_request = mocker.spy(device, \"request\")\n\n    assert key._device == device\n    assert key.index == index\n    assert key._cid == cid\n    assert key.actionId == actionId\n    assert key.remapped == remapped\n    assert key._modifierMask == mask\n    assert key.cidStatus == status\n    assert key.key == special_keys.CONTROL[cid]\n    assert key.actionType == special_keys.ACTIONID[actionId]\n    assert key.action == action\n    assert key.modifiers == modifiers\n    assert key.data_bytes.hex().upper() == byts\n\n    key.remap(bytes.fromhex(remap))\n    assert key.data_bytes.hex().upper() == (byts if int(remap, 16) == special_keys.KEYS_Default else remap)\n\n    if int(remap, 16) != special_keys.KEYS_Default:\n        fake_hidpp.match_requests(1, responses, spy_request.call_args_list)\n\n\n# KeysArray methods tested in KeysArrayV4\n\n# KeysArrayV2 not tested as there is no documentation\n\n\n@pytest.mark.parametrize(\n    \"device, index\", [(device_zerofeatures, -1), (device_zerofeatures, 5), (device_standard, -1), (device_standard, 6)]\n)\ndef test_KeysArrayV4_index_error(device, index):\n    keysarray = hidpp20.KeysArrayV4(device, 5)\n\n    with pytest.raises(IndexError):\n        keysarray[index]\n\n    with pytest.raises(IndexError):\n        keysarray._query_key(index)\n\n\n@pytest.mark.parametrize(\"device, index, top, cid\", [(device_standard, 0, 2, 0x0011), (device_standard, 4, 5, 0x0003)])\ndef test_KeysArrayV4_query_key(device, index, top, cid):\n    keysarray = hidpp20.KeysArrayV4(device, 5)\n\n    keysarray._query_key(index)\n\n    assert keysarray.keys[index]._cid == cid\n    assert len(keysarray[index:top]) == top - index\n    assert len(list(keysarray)) == 5\n\n\n@pytest.mark.parametrize(\n    \"device, count, index, cid, task_id, flags, pos, group, gmask\",\n    [\n        (device_standard, 4, 0, 0x0011, 0x0012, 0xCDAB, 1, 2, 3),\n        (device_standard, 6, 1, 0x0111, 0x0022, 0xCDAB, 1, 2, 3),\n        (device_standard, 8, 3, 0x0311, 0x0032, 0xCDAB, 1, 2, 4),\n    ],\n)\ndef test_KeysArrayV4__getitem(device, count, index, cid, task_id, flags, pos, group, gmask):\n    keysarray = hidpp20.KeysArrayV4(device, count)\n\n    result = keysarray[index]\n\n    assert result._device == device\n    assert result.index == index\n    assert result._cid == cid\n    assert result._tid == task_id\n    assert result._flags == flags\n    assert result.pos == pos\n    assert result.group == group\n    assert result._gmask == gmask\n\n\n@pytest.mark.parametrize(\n    \"key, index\", [(special_keys.CONTROL.Volume_Up_old, 2), (special_keys.CONTROL.Mute, 4), (special_keys.CONTROL.Next, None)]\n)\ndef test_KeysArrayV4_index(key, index):\n    keysarray = hidpp20.KeysArrayV4(device_standard, 7)\n\n    result = keysarray.index(key)\n\n    assert result == index\n\n\ndevice_key = fake_hidpp.Device(\n    \"KEY\", responses=fake_hidpp.responses_key, feature=hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, offset=5\n)\n\n\n@pytest.mark.parametrize(\n    \"key, expected_index, expected_mapped_to, expected_remappable_to\",\n    [\n        (\n            special_keys.CONTROL.Left_Button,\n            0,\n            common.NamedInt(0x50, \"Left Click\"),\n            [common.NamedInt(0x50, \"Left Click\"), common.NamedInt(0x51, \"Right Click\")],\n        ),\n        (\n            special_keys.CONTROL.Right_Button,\n            1,\n            common.NamedInt(0x51, \"Right Click\"),\n            [common.NamedInt(0x51, \"Right Click\"), common.NamedInt(0x50, \"Left Click\")],\n        ),\n        (special_keys.CONTROL.Middle_Button, 2, common.NamedInt(0x50, \"Left Click\"), None),\n        (special_keys.CONTROL.Back_Button, 3, common.NamedInt(0x53, \"Mouse Back Button\"), None),\n        (special_keys.CONTROL.Forward_Button, 4, common.NamedInt(0x56, \"Mouse Forward Button\"), None),\n        (special_keys.CONTROL.Mouse_Gesture_Button, 5, common.NamedInt(0xC3, \"Gesture Button Navigation\"), None),\n        (special_keys.CONTROL.Smart_Shift, 6, common.NamedInt(0x50, \"Left Click\"), None),\n        (special_keys.CONTROL.Virtual_Gesture_Button, 7, common.NamedInt(0x51, \"Right Click\"), None),\n    ],\n)\ndef test_keys_array_v4_key(key, expected_index, expected_mapped_to, expected_remappable_to):\n    device_key._keys = _hidpp20.get_keys(device_key)\n    device_key._keys._ensure_all_keys_queried()\n\n    index = device_key._keys.index(key)\n    mapped_to = device_key._keys[expected_index].mapped_to\n    remappable_to = device_key._keys[expected_index].remappable_to\n\n    assert index == expected_index\n    assert mapped_to == expected_mapped_to\n    if expected_remappable_to is not None:\n        assert list(remappable_to) == expected_remappable_to\n\n\n@pytest.mark.parametrize(\n    \"device, index\", [(device_zerofeatures, -1), (device_zerofeatures, 5), (device_standard, -1), (device_standard, 6)]\n)\ndef test_KeysArrayPersistent_index_error(device, index):\n    keysarray = hidpp20.KeysArrayPersistent(device, 5)\n\n    with pytest.raises(IndexError):\n        keysarray[index]\n\n    with pytest.raises(IndexError):\n        keysarray._query_key(index)\n\n\n@pytest.mark.parametrize(\n    \"responses, key, index, mapped_to, capabilities\",\n    [\n        (fake_hidpp.responses_remap, special_keys.CONTROL.Left_Button, 0, common.NamedInt(0x01, \"Mouse Button Left\"), 0x41),\n        (fake_hidpp.responses_remap, special_keys.CONTROL.Right_Button, 1, common.NamedInt(0x01, \"Mouse Button Left\"), 0x41),\n        (fake_hidpp.responses_remap, special_keys.CONTROL.Middle_Button, 2, common.NamedInt(0x51, \"DOWN\"), 0x41),\n    ],\n)\ndef test_KeysArrayPersistent_key(responses, key, index, mapped_to, capabilities):\n    device = fake_hidpp.Device(\n        \"REMAP\", responses=responses, feature=hidpp20_constants.SupportedFeature.PERSISTENT_REMAPPABLE_ACTION\n    )\n    device._remap_keys = _hidpp20.get_remap_keys(device)\n    device._remap_keys._ensure_all_keys_queried()\n\n    assert device._remap_keys.index(key) == index\n    assert device._remap_keys[index].remapped == mapped_to\n    assert device._remap_keys.capabilities == capabilities\n\n\n@pytest.mark.parametrize(\n    \"id, length, minimum, maximum, widget, min, max, wid, string\",\n    [\n        (\"left\", 1, 5, 8, \"Widget\", 5, 8, \"Widget\", \"left\"),\n        (\"left\", 1, None, None, None, 0, 255, \"Scale\", \"left\"),\n    ],\n)\ndef test_SubParam(id, length, minimum, maximum, widget, min, max, wid, string):\n    subparam = hidpp20.SubParam(id, length, minimum, maximum, widget)\n\n    assert subparam.id == id\n    assert subparam.length == length\n    assert subparam.minimum == min\n    assert subparam.maximum == max\n    assert subparam.widget == wid\n    assert subparam.__str__() == string\n    assert subparam.__repr__() == string\n\n\n@pytest.mark.parametrize(\n    \"device, low, high, next_index, next_diversion_index, name, cbe, si, sdi, eom, dom\",\n    [\n        (device_standard, 0x01, 0x01, 5, 10, GestureId.TAP_1_FINGER, True, 5, None, (0, 0x20), (None, None)),\n        (device_standard, 0x03, 0x02, 6, 11, GestureId.TAP_3_FINGER, False, None, 11, (None, None), (1, 0x08)),\n    ],\n)\ndef test_gesture(device, low, high, next_index, next_diversion_index, name, cbe, si, sdi, eom, dom):\n    gesture = hidpp20.Gesture(device, low, high, next_index, next_diversion_index)\n\n    assert gesture._device == device\n    assert gesture.id == low\n    assert gesture.gesture == name\n    assert gesture.can_be_enabled == cbe\n    assert gesture.can_be_enabled == cbe\n    assert gesture.index == si\n    assert gesture.diversion_index == sdi\n    assert gesture.enable_offset_mask() == eom\n    assert gesture.diversion_offset_mask() == dom\n    assert gesture.as_int() == low\n    assert int(gesture) == low\n\n\n@pytest.mark.parametrize(\n    \"responses, gest, enabled, diverted, set_result, unset_result, divert_result, undivert_result\",\n    [\n        (fake_hidpp.responses_gestures, 20, None, None, None, None, None, None),\n        (fake_hidpp.responses_gestures, 1, True, False, \"01\", \"00\", \"01\", \"00\"),\n        (fake_hidpp.responses_gestures, 45, False, None, \"01\", \"00\", None, None),\n    ],\n)\ndef test_Gesture_set(responses, gest, enabled, diverted, set_result, unset_result, divert_result, undivert_result):\n    device = fake_hidpp.Device(\"GESTURE\", responses=responses, feature=hidpp20_constants.SupportedFeature.GESTURE_2)\n    gestures = _hidpp20.get_gestures(device)\n\n    gesture = gestures.gesture(gest)\n\n    assert gesture.enabled() == enabled\n    assert gesture.diverted() == diverted\n    assert gesture.set(True) == (bytes.fromhex(set_result) if set_result is not None else None)\n    assert gesture.set(False) == (bytes.fromhex(unset_result) if unset_result is not None else None)\n    assert gesture.divert(True) == (bytes.fromhex(divert_result) if divert_result is not None else None)\n    assert gesture.divert(False) == (bytes.fromhex(undivert_result) if undivert_result is not None else None)\n\n\n@pytest.mark.parametrize(\n    \"responses, prm, id, index, size, value, default_value, write1, write2\",\n    [\n        (fake_hidpp.responses_gestures, 4, hidpp20_constants.ParamId.SCALE_FACTOR, 0, 2, 256, 256, \"0080\", \"0180\"),\n    ],\n)\ndef test_param(responses, prm, id, index, size, value, default_value, write1, write2):\n    device = fake_hidpp.Device(\"GESTURE\", responses=responses, feature=hidpp20_constants.SupportedFeature.GESTURE_2)\n    gestures = _hidpp20.get_gestures(device)\n\n    param = gestures.param(prm)\n\n    assert param.id == id\n    assert param.index == index\n    assert param.size == size\n    assert param.value == value\n    assert param.default_value == default_value\n    assert param.param == id\n    assert int(param) == id\n    assert param.write(bytes.fromhex(write1)).hex().upper() == f\"{index:02X}\" + write1 + \"FF\"\n    assert param.write(bytes.fromhex(write2)).hex().upper() == f\"{index:02X}\" + write2 + \"FF\"\n\n\n@pytest.mark.parametrize(\n    \"responses, id, s, byte_count, expected_value, expected_string\",\n    [\n        (fake_hidpp.responses_gestures, 1, hidpp20.SpecGesture.DVI_FIELD_WIDTH, 1, 8, \"[dvi field width=8]\"),\n        (fake_hidpp.responses_gestures, 2, hidpp20.SpecGesture.FIELD_WIDTHS, 1, 8, \"[field widths=8]\"),\n        (fake_hidpp.responses_gestures, 3, hidpp20.SpecGesture.PERIOD_UNIT, 2, 2048, \"[period unit=2048]\"),\n    ],\n)\ndef test_spec(responses, id, s, byte_count, expected_value, expected_string):\n    device = fake_hidpp.Device(\"GESTURE\", responses=responses, feature=hidpp20_constants.SupportedFeature.GESTURE_2)\n    gestures = _hidpp20.get_gestures(device)\n\n    spec = gestures.specs[id]\n\n    assert spec.id == id\n    assert spec.spec == s\n    assert spec.byte_count == byte_count\n    assert spec.value == expected_value\n    assert repr(spec) == expected_string\n\n\ndef test_Gestures():\n    device = fake_hidpp.Device(\n        \"GESTURES\", responses=fake_hidpp.responses_gestures, feature=hidpp20_constants.SupportedFeature.GESTURE_2\n    )\n    gestures = _hidpp20.get_gestures(device)\n\n    assert gestures\n\n    assert len(gestures.gestures) == 17\n    assert gestures.gesture(20) == gestures.gestures[20]\n    assert gestures.gesture_enabled(20) is None\n    assert gestures.gesture_enabled(1) is True\n    assert gestures.gesture_enabled(45) is False\n    assert gestures.enable_gesture(20) is None\n    assert gestures.enable_gesture(45) == bytes.fromhex(\"01\")\n    assert gestures.disable_gesture(20) is None\n    assert gestures.disable_gesture(45) == bytes.fromhex(\"00\")\n\n    assert len(gestures.params) == 1\n    assert gestures.param(4) == gestures.params[4]\n    assert gestures.get_param(4) == 256\n    assert gestures.set_param(4, 128) is None\n\n    assert len(gestures.specs) == 5\n    assert gestures.specs[2].value == 8\n    assert gestures.specs[4].value == 4\n\n\nresponses_backlight = [\n    fake_hidpp.Response(\"010118000001020003000400\", 0x0400),\n    fake_hidpp.Response(\"0101FF00020003000400\", 0x0410, \"0101FF00020003000400\"),\n]\n\ndevice_backlight = fake_hidpp.Device(\n    \"BACKLIGHT\", responses=responses_backlight, feature=hidpp20_constants.SupportedFeature.BACKLIGHT2\n)\n\n\ndef test_Backlight():\n    backlight = _hidpp20.get_backlight(device_backlight)\n    result = backlight.write()\n\n    assert backlight\n    assert backlight.auto_supported\n    assert backlight.temp_supported\n    assert not backlight.perm_supported\n    assert backlight.dho == 0x0002\n    assert backlight.dhi == 0x0003\n    assert backlight.dpow == 0x0004\n    assert result is not None\n\n\n@pytest.mark.parametrize(\n    \"hex, ID, color, speed, period, intensity, ramp, form\",\n    [\n        (\"FFFFFFFFFFFFFFFFFFFFFF\", None, None, None, None, None, None, None),\n        (\"0000000000000000000000\", common.NamedInt(0x0, \"Disabled\"), None, None, None, None, None, None),\n        (\"0120304010000000000000\", common.NamedInt(0x1, \"Static\"), 0x203040, None, None, None, 0x10, None),\n        (\"0220304010000000000000\", common.NamedInt(0x2, \"Pulse\"), 0x203040, 0x10, None, None, None, None),\n        (\"0800000000000000000000\", common.NamedInt(0x8, \"Boot\"), None, None, None, None, None, None),\n        (\"0300000000005000000000\", common.NamedInt(0x3, \"Cycle\"), None, None, 0x5000, 0x00, None, None),\n        (\"0A20304010005020000000\", common.NamedInt(0xA, \"Breathe\"), 0x203040, None, 0x1000, 0x20, None, 0x50),\n        (\"0B20304000100000000000\", common.NamedInt(0xB, \"Ripple\"), 0x203040, None, 0x1000, None, None, None),\n        (\"0A01020300500407000000\", common.NamedInt(0xA, \"Breathe\"), 0x010203, None, 0x0050, 0x07, None, 0x04),\n    ],\n)\ndef test_LEDEffectSetting(hex, ID, color, speed, period, intensity, ramp, form):\n    byt = bytes.fromhex(hex)\n    setting = hidpp20.LEDEffectSetting.from_bytes(byt)\n\n    assert setting.ID == ID\n    if ID is None:\n        assert setting.bytes == byt\n    else:\n        assert getattr(setting, \"color\", None) == color\n        assert getattr(setting, \"speed\", None) == speed\n        assert getattr(setting, \"period\", None) == period\n        assert getattr(setting, \"intensity\", None) == intensity\n        assert getattr(setting, \"ramp\", None) == ramp\n        assert getattr(setting, \"form\", None) == form\n\n    assert setting.to_bytes() == byt\n    assert yaml.safe_load(yaml.dump(setting)) == setting\n    assert yaml.safe_load(str(setting)) == setting\n\n\n@pytest.mark.parametrize(\n    \"feature, function, response, ID, capabilities, period\",\n    [\n        [\n            hidpp20_constants.SupportedFeature.COLOR_LED_EFFECTS,\n            0x20,\n            fake_hidpp.Response(\"0102000300040005\", 0x0420, \"010200\"),\n            3,\n            4,\n            5,\n        ],\n        [\n            hidpp20_constants.SupportedFeature.COLOR_LED_EFFECTS,\n            0x20,\n            fake_hidpp.Response(\"0102000700080009\", 0x0420, \"010200\"),\n            7,\n            8,\n            9,\n        ],\n    ],\n)\ndef test_LEDEffectInfo(feature, function, response, ID, capabilities, period):\n    device = fake_hidpp.Device(feature=feature, responses=[response])\n\n    info = hidpp20.LEDEffectInfo(feature, function, device, 1, 2)\n\n    assert info.zindex == 1\n    assert info.index == 2\n    assert info.ID == ID\n    assert info.capabilities == capabilities\n    assert info.period == period\n\n\n@pytest.mark.parametrize(\n    \"feature, function, offset, effect_function, responses, index, location, count, id_1\",\n    [\n        [hidpp20_constants.SupportedFeature.COLOR_LED_EFFECTS, 0x10, 0, 0x20, fake_hidpp.zone_responses_1, 0, 1, 2, 0xB],\n        [hidpp20_constants.SupportedFeature.RGB_EFFECTS, 0x00, 1, 0x00, fake_hidpp.zone_responses_2, 0, 1, 2, 2],\n    ],\n)\ndef test_LEDZoneInfo(feature, function, offset, effect_function, responses, index, location, count, id_1):\n    device = fake_hidpp.Device(feature=feature, responses=responses, offset=0x07)\n\n    zone = hidpp20.LEDZoneInfo(feature, function, offset, effect_function, device, index)\n\n    assert zone.index == index\n    assert zone.location == location\n    assert zone.count == count\n    assert len(zone.effects) == count\n    assert zone.effects[1].ID == id_1\n\n\n@pytest.mark.parametrize(\n    \"responses, setting, expected_command\",\n    [\n        [fake_hidpp.zone_responses_1, hidpp20.LEDEffectSetting(ID=0), None],\n        [fake_hidpp.zone_responses_1, hidpp20.LEDEffectSetting(ID=3, period=0x20, intensity=0x50), \"000000000000000020500000\"],\n        [\n            fake_hidpp.zone_responses_1,\n            hidpp20.LEDEffectSetting(ID=0xB, color=0x808080, period=0x20),\n            \"000180808000002000000000\",\n        ],\n    ],\n)\ndef test_LEDZoneInfo_to_command(responses, setting, expected_command):\n    device = fake_hidpp.Device(feature=hidpp20_constants.SupportedFeature.COLOR_LED_EFFECTS, responses=responses, offset=0x07)\n    zone = hidpp20.LEDZoneInfo(hidpp20_constants.SupportedFeature.COLOR_LED_EFFECTS, 0x10, 0, 0x20, device, 0)\n\n    command = zone.to_command(setting)\n\n    assert command == (bytes.fromhex(expected_command) if expected_command is not None else None)\n\n\n@pytest.mark.parametrize(\n    \"feature, cls, responses, readable, count, count_0\",\n    [\n        [\n            hidpp20_constants.SupportedFeature.COLOR_LED_EFFECTS,\n            hidpp20.LEDEffectsInfo,\n            fake_hidpp.effects_responses_1,\n            1,\n            1,\n            2,\n        ],\n        [hidpp20_constants.SupportedFeature.RGB_EFFECTS, hidpp20.RGBEffectsInfo, fake_hidpp.effects_responses_2, 1, 1, 2],\n    ],\n)\ndef test_LED_RGB_EffectsInfo(feature, cls, responses, readable, count, count_0):\n    device = fake_hidpp.Device(feature=feature, responses=responses, offset=0x07)\n\n    effects = cls(device)\n\n    assert effects.readable == readable\n    assert effects.count == count\n    assert effects.zones[0].count == count_0\n\n\n@pytest.mark.parametrize(\n    \"hex, expected_behavior, sector, address, typ, val, modifiers, data, byt\",\n    [\n        (\"05010203\", 0x0, 0x501, 0x0203, None, None, None, None, None),\n        (\"15020304\", 0x1, 0x502, 0x0304, None, None, None, None, None),\n        (\"8000FFFF\", 0x8, None, None, 0x00, None, None, None, None),\n        (\"80010102\", 0x8, None, None, 0x01, 0x0102, None, None, None),\n        (\"80020454\", 0x8, None, None, 0x02, 0x54, 0x04, None, None),\n        (\"80030454\", 0x8, None, None, 0x03, 0x0454, None, None, None),\n        (\"900AFF01\", 0x9, None, None, None, 0x0A, None, 0x01, None),\n        (\"709090A0\", 0x7, None, None, None, None, None, None, b\"\\x70\\x90\\x90\\xa0\"),\n    ],\n)\ndef test_button_bytes(hex, expected_behavior, sector, address, typ, val, modifiers, data, byt):\n    button = hidpp20.Button.from_bytes(bytes.fromhex(hex))\n\n    assert getattr(button, \"behavior\", None) == expected_behavior\n    assert getattr(button, \"sector\", None) == sector\n    assert getattr(button, \"address\", None) == address\n    assert getattr(button, \"type\", None) == typ\n    assert getattr(button, \"value\", None) == val\n    assert getattr(button, \"modifiers\", None) == modifiers\n    assert getattr(button, \"data\", None) == data\n    assert getattr(button, \"bytes\", None) == byt\n    assert button.to_bytes().hex().upper() == hex\n    assert yaml.safe_load(yaml.dump(button)).to_bytes().hex().upper() == hex\n\n\nhex1 = (\n    \"01010290018003000700140028FFFFFF\"\n    \"FFFF0000000000000000000000000000\"\n    \"8000FFFF900AFF00800204548000FFFF\"\n    \"900AFF00800204548000FFFF900AFF00\"\n    \"800204548000FFFF900AFF0080020454\"\n    \"8000FFFF900AFF00800204548000FFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"54004500370000000000000000000000\"\n    \"00000000000000000000000000000000\"\n    \"00000000000000000000000000000000\"\n    \"0A01020300500407000000FFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFF7C81\"\n)\nhex2 = (\n    \"01010290018003000700140028FFFFFF\"\n    \"FFFF0000000000000000000000000000\"\n    \"8000FFFF900AFF00800204548000FFFF\"\n    \"900AFF00800204548000FFFF900AFF00\"\n    \"800204548000FFFF900AFF0080020454\"\n    \"8000FFFF900AFF00800204548000FFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"0A01020300500407000000FFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFF27C9\"\n)\nhex3 = (\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n    \"FFFFFFFFFFFFFFFFFFFFFFFFFF2307\"\n)\n\n\n@pytest.mark.parametrize(\n    \"hex, name, sector, enabled, buttons, gbuttons, resolutions, button, lighting\",\n    [\n        (hex1, \"TE7\", 2, 1, 16, 0, [0x0190, 0x0380, 0x0700, 0x1400, 0x2800], \"8000FFFF\", \"0A01020300500407000000\"),\n        (hex2, \"\", 2, 1, 16, 0, [0x0190, 0x0380, 0x0700, 0x1400, 0x2800], \"8000FFFF\", \"0A01020300500407000000\"),\n        (hex3, \"\", 2, 1, 16, 0, [0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF], \"FFFFFFFF\", \"FFFFFFFFFFFFFFFFFFFFFF\"),\n    ],\n)\ndef test_onboard_profile_bytes(hex, name, sector, enabled, buttons, gbuttons, resolutions, button, lighting):\n    profile = hidpp20.OnboardProfile.from_bytes(sector, enabled, buttons, gbuttons, bytes.fromhex(hex))\n\n    assert profile.name == name\n    assert profile.sector == sector\n    assert profile.resolutions == resolutions\n    assert profile.buttons[0].to_bytes().hex().upper() == button\n    assert profile.lighting[0].to_bytes().hex().upper() == lighting\n\n    assert profile.to_bytes(len(hex) // 2).hex().upper() == hex\n    assert yaml.safe_load(yaml.dump(profile)).to_bytes(len(hex) // 2).hex().upper() == hex\n\n\n@pytest.mark.parametrize(\n    \"responses, name, count, buttons, gbuttons, sectors, size\",\n    [\n        (fake_hidpp.responses_profiles, \"ONB\", 1, 2, 2, 1, 254),\n        (fake_hidpp.responses_profiles_rom, \"ONB\", 1, 2, 2, 1, 254),\n        (fake_hidpp.responses_profiles_rom_2, \"ONB\", 1, 2, 2, 1, 254),\n    ],\n)\ndef test_onboard_profiles_device(responses, name, count, buttons, gbuttons, sectors, size):\n    device = fake_hidpp.Device(\n        name, True, 4.5, responses=responses, feature=hidpp20_constants.SupportedFeature.ONBOARD_PROFILES, offset=0x9\n    )\n    device._profiles = None\n    profiles = _hidpp20.get_profiles(device)\n\n    assert profiles\n    assert profiles.version == hidpp20.OnboardProfilesVersion\n    assert profiles.name == name\n    assert profiles.count == count\n    assert profiles.buttons == buttons\n    assert profiles.gbuttons == gbuttons\n    assert profiles.sectors == sectors\n    assert profiles.size == size\n    assert len(profiles.profiles) == count\n\n    yml_dump = yaml.dump(profiles)\n    assert yaml.safe_load(yml_dump).to_bytes().hex() == profiles.to_bytes().hex()\n"
  },
  {
    "path": "tests/logitech_receiver/test_hidpp20_simple.py",
    "content": "## Copyright (C) 2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport pytest\n\nfrom logitech_receiver import common\nfrom logitech_receiver import hidpp20\nfrom logitech_receiver import hidpp20_constants\nfrom logitech_receiver.hidpp20_constants import SupportedFeature\n\nfrom . import fake_hidpp\n\n_hidpp20 = hidpp20.Hidpp20()\n\n\ndef test_get_firmware():\n    responses = [\n        fake_hidpp.Response(\"02FFFF\", 0x0400),\n        fake_hidpp.Response(\"01414243030401000101000102030405\", 0x0410, \"00\"),\n        fake_hidpp.Response(\"02414243030401000101000102030405\", 0x0410, \"01\"),\n    ]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.DEVICE_FW_VERSION)\n\n    result = _hidpp20.get_firmware(device)\n\n    assert len(result) == 2\n    assert isinstance(result[0], common.FirmwareInfo)\n    assert isinstance(result[1], common.FirmwareInfo)\n\n\ndef test_get_ids():\n    responses = [fake_hidpp.Response(\"FF12345678000D123456789ABC\", 0x0400)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.DEVICE_FW_VERSION)\n\n    unitId, modelId, tid_map = _hidpp20.get_ids(device)\n\n    assert unitId == \"12345678\"\n    assert modelId == \"123456789ABC\"\n    assert tid_map == {\"btid\": \"1234\", \"wpid\": \"5678\", \"usbid\": \"9ABC\"}\n\n\ndef test_get_kind():\n    responses = [fake_hidpp.Response(\"00\", 0x0420)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.DEVICE_NAME)\n\n    result = _hidpp20.get_kind(device)\n\n    assert result == \"keyboard\"\n    assert result == 1\n\n\ndef test_get_name():\n    responses = [\n        fake_hidpp.Response(\"12\", 0x0400),\n        fake_hidpp.Response(\"4142434445464748494A4B4C4D4E4F\", 0x0410, \"00\"),\n        fake_hidpp.Response(\"505152530000000000000000000000\", 0x0410, \"0F\"),\n    ]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.DEVICE_NAME)\n\n    result = _hidpp20.get_name(device)\n\n    assert result == \"ABCDEFGHIJKLMNOPQR\"\n\n\ndef test_get_friendly_name():\n    responses = [\n        fake_hidpp.Response(\"12\", 0x0400),\n        fake_hidpp.Response(\"004142434445464748494A4B4C4D4E\", 0x0410, \"00\"),\n        fake_hidpp.Response(\"0E4F50515253000000000000000000\", 0x0410, \"0E\"),\n    ]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.DEVICE_FRIENDLY_NAME)\n\n    result = _hidpp20.get_friendly_name(device)\n\n    assert result == \"ABCDEFGHIJKLMNOPQR\"\n\n\ndef test_get_battery_status():\n    responses = [fake_hidpp.Response(\"502000FFFF\", 0x0400)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.BATTERY_STATUS)\n\n    feature, battery = _hidpp20.get_battery_status(device)\n\n    assert feature == SupportedFeature.BATTERY_STATUS\n    assert battery.level == 80\n    assert battery.next_level == 32\n    assert battery.status == common.BatteryStatus.DISCHARGING\n\n\ndef test_get_battery_voltage():\n    responses = [fake_hidpp.Response(\"1000FFFFFF\", 0x0400)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.BATTERY_VOLTAGE)\n\n    feature, battery = _hidpp20.get_battery_voltage(device)\n\n    assert feature == SupportedFeature.BATTERY_VOLTAGE\n    assert battery.level == 92\n    assert common.BatteryStatus.RECHARGING in battery.status\n    assert battery.voltage == 0x1000\n\n\ndef test_get_battery_unified():\n    responses = [fake_hidpp.Response(\"500100FFFF\", 0x0410)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.UNIFIED_BATTERY)\n\n    feature, battery = _hidpp20.get_battery_unified(device)\n\n    assert feature == SupportedFeature.UNIFIED_BATTERY\n    assert battery.level == 80\n    assert battery.status == common.BatteryStatus.DISCHARGING\n\n\ndef test_get_adc_measurement():\n    responses = [fake_hidpp.Response(\"100003\", 0x0400)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.ADC_MEASUREMENT)\n\n    feature, battery = _hidpp20.get_adc_measurement(device)\n\n    assert feature == SupportedFeature.ADC_MEASUREMENT\n    assert battery.level == 92\n    assert battery.status == common.BatteryStatus.RECHARGING\n    assert battery.voltage == 0x1000\n\n\ndef test_get_battery():\n    responses = [fake_hidpp.Response(\"502000FFFF\", 0x0400)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.BATTERY_STATUS)\n\n    feature, battery = _hidpp20.get_battery(device, SupportedFeature.BATTERY_STATUS)\n\n    assert feature == SupportedFeature.BATTERY_STATUS\n    assert battery.level == 80\n    assert battery.next_level == 32\n    assert battery.status == common.BatteryStatus.DISCHARGING\n\n\ndef test_get_battery_none():\n    responses = [\n        fake_hidpp.Response(None, 0x0000, f\"{int(SupportedFeature.BATTERY_STATUS):0>4X}\"),\n        fake_hidpp.Response(None, 0x0000, f\"{int(SupportedFeature.BATTERY_VOLTAGE):0>4X}\"),\n        fake_hidpp.Response(\"500100ffff\", 0x0410),\n    ]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.UNIFIED_BATTERY)\n\n    feature, battery = _hidpp20.get_battery(device, None)\n\n    assert feature == SupportedFeature.UNIFIED_BATTERY\n    assert battery.level == 80\n    assert battery.status == common.BatteryStatus.DISCHARGING\n\n\n# get_keys is in test_hidpp20_complex\n# get_remap_keys is in test_hidpp20_complex\n# TODO get_gestures is complex\n# get_backlight is in test_hidpp20_complex\n# get_profiles is in test_hidpp20_complex\n\n\ndef test_get_mouse_pointer_info():\n    responses = [fake_hidpp.Response(\"01000A\", 0x0400)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.MOUSE_POINTER)\n\n    result = _hidpp20.get_mouse_pointer_info(device)\n\n    assert result == {\n        \"dpi\": 0x100,\n        \"acceleration\": \"med\",\n        \"suggest_os_ballistics\": False,\n        \"suggest_vertical_orientation\": True,\n    }\n\n\ndef test_get_vertical_scrolling_info():\n    responses = [fake_hidpp.Response(\"01080C\", 0x0400)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.VERTICAL_SCROLLING)\n\n    result = _hidpp20.get_vertical_scrolling_info(device)\n\n    assert result == {\"roller\": \"standard\", \"ratchet\": 8, \"lines\": 12}\n\n\ndef test_get_hi_res_scrolling_info():\n    responses = [fake_hidpp.Response(\"0102\", 0x0400)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.HI_RES_SCROLLING)\n\n    mode, resolution = _hidpp20.get_hi_res_scrolling_info(device)\n\n    assert mode == 1\n    assert resolution == 2\n\n\ndef test_get_pointer_speed_info():\n    responses = [fake_hidpp.Response(\"0102\", 0x0400)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.POINTER_SPEED)\n\n    result = _hidpp20.get_pointer_speed_info(device)\n\n    assert result == 0x0102 / 256\n\n\ndef test_get_lowres_wheel_status():\n    responses = [fake_hidpp.Response(\"01\", 0x0400)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.LOWRES_WHEEL)\n\n    result = _hidpp20.get_lowres_wheel_status(device)\n\n    assert result == \"HID++\"\n\n\ndef test_get_hires_wheel():\n    responses = [\n        fake_hidpp.Response(\"010C\", 0x0400),\n        fake_hidpp.Response(\"05FF\", 0x0410),\n        fake_hidpp.Response(\"03FF\", 0x0430),\n    ]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.HIRES_WHEEL)\n\n    multi, has_invert, has_ratchet, inv, res, target, ratchet = _hidpp20.get_hires_wheel(device)\n\n    assert multi == 1\n    assert has_invert is True\n    assert has_ratchet is True\n    assert inv is True\n    assert res is False\n    assert target is True\n    assert ratchet is True\n\n\ndef test_get_new_fn_inversion():\n    responses = [fake_hidpp.Response(\"0300\", 0x0400)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.NEW_FN_INVERSION)\n\n    result = _hidpp20.get_new_fn_inversion(device)\n\n    assert result == (True, False)\n\n\n@pytest.fixture\ndef mock_gethostname(mocker):\n    mocker.patch(\"socket.gethostname\", return_value=\"ABCDEFG.foo.org\")\n\n\n@pytest.mark.parametrize(\n    \"responses, expected_result\",\n    [\n        ([fake_hidpp.Response(None, 0x0400)], {}),\n        ([fake_hidpp.Response(\"02000000\", 0x0400)], {}),\n        (\n            [\n                fake_hidpp.Response(\"03000200\", 0x0400),\n                fake_hidpp.Response(\"FF01FFFF05FFFF\", 0x0410, \"00\"),\n                fake_hidpp.Response(\"0000414243444500FFFFFFFFFF\", 0x0430, \"0000\"),\n                fake_hidpp.Response(\"FF01FFFF10FFFF\", 0x0410, \"01\"),\n                fake_hidpp.Response(\"01004142434445464748494A4B4C4D\", 0x0430, \"0100\"),\n                fake_hidpp.Response(\"01134E4F5000FFFFFFFFFFFFFFFFFF\", 0x0430, \"010E\"),\n                fake_hidpp.Response(\"000000000008\", 0x0410, \"00\"),\n                fake_hidpp.Response(\"0208\", 0x0440, \"000041424344454647\"),\n            ],\n            {0: (True, \"ABCDEFG\"), 1: (True, \"ABCDEFGHIJKLMNO\")},\n        ),\n    ],\n)\ndef test_get_host_names(responses, expected_result, mock_gethostname):\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.HOSTS_INFO)\n\n    result = _hidpp20.get_host_names(device)\n\n    assert result == expected_result\n\n\n@pytest.mark.parametrize(\n    \"responses, expected_result\",\n    [\n        ([fake_hidpp.Response(None, 0x0400)], None),\n        (\n            [\n                fake_hidpp.Response(\"03000002\", 0x0400),\n                fake_hidpp.Response(\"000000000008\", 0x0410, \"02\"),\n                fake_hidpp.Response(\"020E\", 0x0440, \"02004142434445464748494A4B4C4D4E\"),\n            ],\n            True,\n        ),\n        (\n            [\n                fake_hidpp.Response(\"03000002\", 0x0400),\n                fake_hidpp.Response(\"000000000014\", 0x0410, \"02\"),\n                fake_hidpp.Response(\"020E\", 0x0440, \"02004142434445464748494A4B4C4D4E\"),\n                fake_hidpp.Response(\"0214\", 0x0440, \"020E4F505152535455565758\"),\n            ],\n            True,\n        ),\n    ],\n)\ndef test_set_host_name(responses, expected_result):\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.HOSTS_INFO)\n\n    result = _hidpp20.set_host_name(device, \"ABCDEFGHIJKLMNOPQRSTUVWX\")\n\n    assert result == expected_result\n\n\ndef test_get_onboard_mode():\n    responses = [fake_hidpp.Response(\"03FFFFFFFF\", 0x0420)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.ONBOARD_PROFILES)\n\n    result = _hidpp20.get_onboard_mode(device)\n\n    assert result == 0x3\n\n\ndef test_set_onboard_mode():\n    responses = [fake_hidpp.Response(\"03FFFFFFFF\", 0x0410, \"03\")]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.ONBOARD_PROFILES)\n\n    res = _hidpp20.set_onboard_mode(device, 0x3)\n\n    assert res is not None\n\n\n@pytest.mark.parametrize(\n    \"responses, expected_result\",\n    [\n        ([fake_hidpp.Response(\"03FFFF\", 0x0420)], \"1ms\"),\n        (\n            [\n                fake_hidpp.Response(None, 0x0000, f\"{int(SupportedFeature.REPORT_RATE):04X}\"),\n                fake_hidpp.Response(\"04FFFF\", 0x0420),\n            ],\n            \"500us\",\n        ),\n    ],\n)\ndef test_get_polling_rate(\n    responses,\n    expected_result,\n):\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.EXTENDED_ADJUSTABLE_REPORT_RATE)\n\n    result = _hidpp20.get_polling_rate(device)\n\n    assert result == expected_result\n\n\ndef test_get_remaining_pairing():\n    responses = [fake_hidpp.Response(\"03FFFF\", 0x0400)]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.REMAINING_PAIRING)\n\n    result = _hidpp20.get_remaining_pairing(device)\n\n    assert result == 0x03\n\n\ndef test_config_change():\n    responses = [fake_hidpp.Response(\"03FFFF\", 0x0410, \"02\")]\n    device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.CONFIG_CHANGE)\n\n    result = _hidpp20.config_change(device, 0x2)\n\n    assert result == bytes.fromhex(\"03FFFF\")\n\n\ndef test_decipher_battery_status():\n    report = b\"\\x50\\x20\\x00\\xff\\xff\"\n\n    feature, battery = hidpp20.decipher_battery_status(report)\n\n    assert feature == SupportedFeature.BATTERY_STATUS\n    assert battery.level == 80\n    assert battery.next_level == 32\n    assert battery.status == common.BatteryStatus.DISCHARGING\n\n\ndef test_decipher_battery_voltage():\n    report = b\"\\x10\\x00\\xff\\xff\\xff\"\n\n    feature, battery = hidpp20.decipher_battery_voltage(report)\n\n    assert feature == SupportedFeature.BATTERY_VOLTAGE\n    assert battery.level == 92\n    assert common.BatteryStatus.RECHARGING in battery.status\n    assert battery.voltage == 0x1000\n\n\ndef test_decipher_battery_unified():\n    report = b\"\\x50\\x01\\x00\\xff\\xff\"\n\n    feature, battery = hidpp20.decipher_battery_unified(report)\n\n    assert feature == SupportedFeature.UNIFIED_BATTERY\n    assert battery.level == 80\n    assert battery.status == common.BatteryStatus.DISCHARGING\n\n\ndef test_decipher_adc_measurement():\n    report = b\"\\x10\\x00\\x03\"\n\n    feature, battery = hidpp20.decipher_adc_measurement(report)\n\n    assert feature == SupportedFeature.ADC_MEASUREMENT\n    assert battery.level == 92\n    assert battery.status == common.BatteryStatus.RECHARGING\n    assert battery.voltage == 0x1000\n\n\n@pytest.mark.parametrize(\n    \"code, expected_flags\",\n    [\n        (0x01, [\"unknown:000001\"]),\n        (0x0F, [\"unknown:00000F\"]),\n        (0xF0, [\"internal\", \"hidden\", \"obsolete\", \"unknown:000010\"]),\n        (0x20, [\"internal\"]),\n        (0x33, [\"internal\", \"unknown:000013\"]),\n        (0x3F, [\"internal\", \"unknown:00001F\"]),\n        (0x40, [\"hidden\"]),\n        (0x50, [\"hidden\", \"unknown:000010\"]),\n        (0x5F, [\"hidden\", \"unknown:00001F\"]),\n        (0x7F, [\"internal\", \"hidden\", \"unknown:00001F\"]),\n        (0x80, [\"obsolete\"]),\n        (0xA0, [\"internal\", \"obsolete\"]),\n        (0xE0, [\"internal\", \"hidden\", \"obsolete\"]),\n        (0xFF, [\"internal\", \"hidden\", \"obsolete\", \"unknown:00001F\"]),\n    ],\n)\ndef test_feature_flag_names(code, expected_flags):\n    flags = common.flag_names(hidpp20_constants.FeatureFlag, code)\n\n    assert list(flags) == expected_flags\n\n\n@pytest.mark.parametrize(\n    \"code, expected_name\",\n    [\n        (0x00, \"Unknown Location\"),\n        (0x03, \"Left Side\"),\n    ],\n)\ndef test_led_zone_locations(code, expected_name):\n    assert hidpp20.LEDZoneLocations[code] == expected_name\n\n\n@pytest.mark.parametrize(\n    \"millivolt, expected_percentage\",\n    [\n        (-1234, 0),\n        (500, 0),\n        (2000, 0),\n        (3500, 0),\n        (3519, 0),\n        (3520, 1),\n        (3559, 1),\n        (3579, 2),\n        (3646, 5),\n        (3671, 10),\n        (3717, 20),\n        (3751, 30),\n        (3778, 40),\n        (3811, 50),\n        (3859, 60),\n        (3922, 70),\n        (3989, 80),\n        (4067, 90),\n        (4180, 99),\n        (4181, 100),\n        (4186, 100),\n        (4500, 100),\n    ],\n)\ndef test_estimate_battery_level_percentage(millivolt, expected_percentage):\n    percentage = hidpp20.estimate_battery_level_percentage(millivolt)\n\n    assert percentage == expected_percentage\n"
  },
  {
    "path": "tests/logitech_receiver/test_notifications.py",
    "content": "import pytest\n\nfrom logitech_receiver import notifications\nfrom logitech_receiver.base import HIDPPNotification\nfrom logitech_receiver.common import Notification\nfrom logitech_receiver.hidpp10_constants import BoltPairingError\nfrom logitech_receiver.hidpp10_constants import PairingError\nfrom logitech_receiver.hidpp10_constants import Registers\nfrom logitech_receiver.hidpp20_constants import SupportedFeature\nfrom logitech_receiver.receiver import Receiver\n\nfrom . import fake_hidpp\n\n\nclass MockLowLevelInterface:\n    def open_path(self, path):\n        pass\n\n    def find_paired_node_wpid(self, receiver_path: str, index: int):\n        pass\n\n    def ping(self, handle, number, long_message=False):\n        pass\n\n    def request(self, handle, devnumber, request_id, *params, **kwargs):\n        pass\n\n    def find_paired_node(self, receiver_path: str, index: int, timeout: int):\n        return None\n\n    def close(self, device_handle) -> None:\n        pass\n\n\n@pytest.mark.parametrize(\n    \"sub_id, notification_data, expected_error, expected_new_device\",\n    [\n        (Registers.DISCOVERY_STATUS_NOTIFICATION, b\"\\x01\", BoltPairingError.DEVICE_TIMEOUT, None),\n        (\n            Registers.DEVICE_DISCOVERY_NOTIFICATION,\n            b\"\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\",\n            None,\n            None,\n        ),\n        (Registers.PAIRING_STATUS_NOTIFICATION, b\"\\x02\", BoltPairingError.FAILED, None),\n        (Notification.PAIRING_LOCK, b\"\\x01\", PairingError.DEVICE_TIMEOUT, None),\n        (Notification.PAIRING_LOCK, b\"\\x02\", PairingError.DEVICE_NOT_SUPPORTED, None),\n        (Notification.PAIRING_LOCK, b\"\\x03\", PairingError.TOO_MANY_DEVICES, None),\n        (Notification.PAIRING_LOCK, b\"\\x06\", PairingError.SEQUENCE_TIMEOUT, None),\n        (Registers.PASSKEY_REQUEST_NOTIFICATION, b\"\\x06\", None, None),\n        (Registers.PASSKEY_PRESSED_NOTIFICATION, b\"\\x06\", None, None),\n    ],\n)\ndef test_process_receiver_notification(sub_id, notification_data, expected_error, expected_new_device):\n    receiver: Receiver = Receiver(MockLowLevelInterface(), None, {}, True, None, None)\n    notification = HIDPPNotification(0, 0, sub_id, 0x02, notification_data)\n\n    result = notifications.process_receiver_notification(receiver, notification)\n\n    assert result\n    assert receiver.pairing.error == (None if expected_error is None else expected_error.label)\n    assert receiver.pairing.new_device is expected_new_device\n\n\n@pytest.mark.parametrize(\n    \"hidpp_notification, expected\",\n    [\n        (HIDPPNotification(0, 0, sub_id=Registers.BATTERY_STATUS, address=0, data=b\"0x01\"), False),\n        (HIDPPNotification(0, 0, sub_id=Notification.NO_OPERATION, address=0, data=b\"0x01\"), False),\n        (HIDPPNotification(0, 0, sub_id=0x40, address=0, data=b\"0x01\"), True),\n    ],\n)\ndef test_process_device_notification(hidpp_notification, expected):\n    device = fake_hidpp.Device()\n\n    result = notifications.process_device_notification(device, hidpp_notification)\n\n    assert result == expected\n\n\n@pytest.mark.parametrize(\n    \"hidpp_notification, expected\",\n    [\n        (HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0, data=b\"0x01\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.DJ_PAIRING, address=0, data=b\"0x01\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.CONNECTED, address=0, data=b\"0x01\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.RAW_INPUT, address=0, data=b\"0x01\"), None),\n    ],\n)\ndef test_process_dj_notification(hidpp_notification, expected):\n    device = fake_hidpp.Device()\n\n    result = notifications._process_dj_notification(device, hidpp_notification)\n\n    assert result == expected\n\n\n@pytest.mark.parametrize(\n    \"hidpp_notification, expected\",\n    [\n        (HIDPPNotification(0, 0, sub_id=Registers.BATTERY_STATUS, address=0, data=b\"\\x01\\x00\"), True),\n        (HIDPPNotification(0, 0, sub_id=Registers.BATTERY_CHARGE, address=0, data=b\"0x01\\x00\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.RAW_INPUT, address=0, data=b\"0x01\"), None),\n    ],\n)\ndef test_process_hidpp10_custom_notification(hidpp_notification, expected):\n    device = fake_hidpp.Device()\n\n    result = notifications._process_hidpp10_custom_notification(device, hidpp_notification)\n\n    assert result == expected\n\n\n@pytest.mark.parametrize(\n    \"hidpp_notification, expected\",\n    [\n        (HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b\"0x01\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"0x01\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.DJ_PAIRING, address=0x00, data=b\"0x01\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.DJ_PAIRING, address=0x02, data=b\"0x01\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.DJ_PAIRING, address=0x03, data=b\"0x01\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.DJ_PAIRING, address=0x03, data=b\"0x4040\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.RAW_INPUT, address=0x00, data=b\"0x01\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.POWER, address=0x00, data=b\"0x01\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.POWER, address=0x01, data=b\"0x01\"), True),\n        (HIDPPNotification(0, 0, sub_id=Notification.PAIRING_LOCK, address=0x01, data=b\"0x01\"), None),\n    ],\n)\ndef test_process_hidpp10_notification(hidpp_notification, expected):\n    fake_device = fake_hidpp.Device()\n    fake_device.receiver = [\"rec1\", \"rec2\"]\n\n    result = notifications._process_hidpp10_notification(fake_device, hidpp_notification)\n\n    assert result == expected\n\n\n@pytest.mark.parametrize(\n    \"hidpp_notification, feature\",\n    [\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"0x01\"),\n            SupportedFeature.BATTERY_STATUS,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b\"0x01\"),\n            SupportedFeature.BATTERY_STATUS,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"0x01\"),\n            SupportedFeature.BATTERY_VOLTAGE,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x05, data=b\"0x01\"),\n            SupportedFeature.BATTERY_VOLTAGE,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"0x01\"),\n            SupportedFeature.UNIFIED_BATTERY,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b\"0x01\"),\n            SupportedFeature.UNIFIED_BATTERY,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"0x01\"),\n            SupportedFeature.ADC_MEASUREMENT,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b\"0x01\"),\n            SupportedFeature.ADC_MEASUREMENT,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"01234GOOD\"),\n            SupportedFeature.SOLAR_DASHBOARD,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x10, data=b\"01234GOOD\"),\n            SupportedFeature.SOLAR_DASHBOARD,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x20, data=b\"01234GOOD\"),\n            SupportedFeature.SOLAR_DASHBOARD,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b\"01234GOOD\"),\n            SupportedFeature.SOLAR_DASHBOARD,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b\"CHARGENOTGOOD\"),\n            SupportedFeature.SOLAR_DASHBOARD,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"\\x01\\x01\\x02\"),\n            SupportedFeature.WIRELESS_DEVICE_STATUS,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b\"0x01\"),\n            SupportedFeature.WIRELESS_DEVICE_STATUS,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"0x01\"),\n            SupportedFeature.TOUCHMOUSE_RAW_POINTS,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x10, data=b\"0x01\"),\n            SupportedFeature.TOUCHMOUSE_RAW_POINTS,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x05, data=b\"0x01\"),\n            SupportedFeature.TOUCHMOUSE_RAW_POINTS,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"0x01\"),\n            SupportedFeature.REPROG_CONTROLS,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b\"0x01\"),\n            SupportedFeature.REPROG_CONTROLS,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"0x01\"),\n            SupportedFeature.BACKLIGHT2,\n        ),\n        (\n            HIDPPNotification(\n                0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"\\x01\\x01\\x01\\x01\\x01\\x01\\x01\\x01\"\n            ),\n            SupportedFeature.REPROG_CONTROLS_V4,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x10, data=b\"0x01\"),\n            SupportedFeature.REPROG_CONTROLS_V4,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x20, data=b\"0x01\"),\n            SupportedFeature.REPROG_CONTROLS_V4,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"0x01\"),\n            SupportedFeature.HIRES_WHEEL,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x10, data=b\"0x01\"),\n            SupportedFeature.HIRES_WHEEL,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b\"0x01\"),\n            SupportedFeature.HIRES_WHEEL,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"0x01\"),\n            SupportedFeature.ONBOARD_PROFILES,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x20, data=b\"0x01\"),\n            SupportedFeature.ONBOARD_PROFILES,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b\"0x01\"),\n            SupportedFeature.BRIGHTNESS_CONTROL,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x10, data=b\"0x01\"),\n            SupportedFeature.BRIGHTNESS_CONTROL,\n        ),\n        (\n            HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x20, data=b\"0x01\"),\n            SupportedFeature.BRIGHTNESS_CONTROL,\n        ),\n    ],\n)\ndef test_process_feature_notification(mocker, hidpp_notification, feature):\n    fake_device = fake_hidpp.Device()\n    fake_device.receiver = [\"rec1\", \"rec2\"]\n\n    result = notifications._process_feature_notification(fake_device, hidpp_notification)\n\n    assert result is True\n\n\ndef test_process_receiver_notification_invalid(mocker):\n    invalid_sub_id = 0x30\n    notification_data = b\"\\x02\"\n    notification = HIDPPNotification(0, 0, invalid_sub_id, 0, notification_data)\n    mock_receiver = mocker.Mock()\n\n    with pytest.raises(AssertionError):\n        notifications.process_receiver_notification(mock_receiver, notification)\n\n\n@pytest.mark.parametrize(\n    \"sub_id, notification_data, expected\",\n    [\n        (Notification.NO_OPERATION, b\"\\x00\", False),\n    ],\n)\ndef test_process_device_notification_extended(mocker, sub_id, notification_data, expected):\n    device = mocker.Mock()\n    device.handle_notification.return_value = None\n    device.protocol = 2.0\n    notification = HIDPPNotification(0, 0, sub_id, 0, notification_data)\n\n    result = notifications.process_device_notification(device, notification)\n\n    assert result == expected\n\n\ndef test_handle_device_discovery():\n    receiver: Receiver = Receiver(MockLowLevelInterface(), None, {}, True, None, None)\n    sub_id = Registers.DISCOVERY_STATUS_NOTIFICATION\n    data = b\"\\x01\\x02\\x03\\x04\\x05\\x06\"\n    notification = HIDPPNotification(0, 0, sub_id, 0, data)\n\n    result = notifications.handle_device_discovery(receiver, notification)\n\n    assert result\n\n\ndef test_handle_passkey_request(mocker):\n    receiver_mock = mocker.Mock()\n    data = b\"\\x01\"\n    notification = HIDPPNotification(0, 0, 0, 0, data)\n\n    result = notifications.handle_passkey_request(receiver_mock, notification)\n\n    assert result is True\n\n\ndef test_handle_passkey_pressed(mocker):\n    receiver = mocker.Mock()\n    sub_id = Registers.DISCOVERY_STATUS_NOTIFICATION\n    data = b\"\\x01\\x02\\x03\\x04\\x05\\x06\"\n    notification = HIDPPNotification(0, 0, sub_id, 0, data)\n\n    result = notifications.handle_passkey_pressed(receiver, notification)\n\n    assert result is True\n"
  },
  {
    "path": "tests/logitech_receiver/test_receiver.py",
    "content": "from dataclasses import dataclass\nfrom functools import partial\nfrom unittest import mock\n\nimport pytest\n\nfrom logitech_receiver import base\nfrom logitech_receiver import common\nfrom logitech_receiver import exceptions\nfrom logitech_receiver import receiver\n\nfrom . import fake_hidpp\n\n\n@pytest.fixture\ndef nano_recv():\n    device_info = DeviceInfo(\"12\", product_id=0xC534)\n    mock_low_level = LowLevelInterfaceFake(responses_lacking)\n    yield receiver.create_receiver(mock_low_level, device_info, lambda x: x)\n\n\nclass LowLevelInterfaceFake:\n    def __init__(self, responses=None):\n        self.responses = responses\n\n    def open_path(self, path):\n        return fake_hidpp.open_path(path)\n\n    def product_information(self, usb_id: int) -> dict:\n        return base.product_information(usb_id)\n\n    def find_paired_node(self, receiver_path: str, index: int, timeout: int):\n        return None\n\n    def request(self, response, *args, **kwargs):\n        func = partial(fake_hidpp.request, self.responses)\n        return func(response, *args, **kwargs)\n\n    def ping(self, response, *args, **kwargs):\n        func = partial(fake_hidpp.ping, self.responses)\n        return func(response, *args, **kwargs)\n\n    def close(self, *args, **kwargs):\n        pass\n\n\n@pytest.mark.parametrize(\n    \"index, expected_kind\",\n    [\n        (0, None),\n        (1, 2),  # mouse\n        (2, 2),  # mouse\n        (3, 1),  # keyboard\n        (4, 3),  # numpad\n        (5, None),\n    ],\n)\ndef test_get_kind_from_index(index, expected_kind):\n    mock_receiver = mock.Mock()\n\n    if expected_kind:\n        assert receiver._get_kind_from_index(mock_receiver, index) == expected_kind\n    else:\n        with pytest.raises(exceptions.NoSuchDevice):\n            receiver._get_kind_from_index(mock_receiver, index)\n\n\n@dataclass\nclass DeviceInfo:\n    path: str\n    vendor_id: int = 1133\n    product_id: int = 0xC52B\n\n\nresponses_unifying = [\n    fake_hidpp.Response(\"000000\", 0x8003, \"FF\"),\n    fake_hidpp.Response(\"000300\", 0x8102),\n    fake_hidpp.Response(\"0316CC9CB40506220000000000000000\", 0x83B5, \"03\"),\n    fake_hidpp.Response(\"20200840820402020700000000000000\", 0x83B5, \"20\"),\n    fake_hidpp.Response(\"21211420110400010D1A000000000000\", 0x83B5, \"21\"),\n    fake_hidpp.Response(\"22220840660402010700000000020000\", 0x83B5, \"22\"),\n    fake_hidpp.Response(\"30198E3EB80600000001000000000000\", 0x83B5, \"30\"),\n    fake_hidpp.Response(\"31811119511A40000002000000000000\", 0x83B5, \"31\"),\n    fake_hidpp.Response(\"32112C46EA1E40000003000000000000\", 0x83B5, \"32\"),\n    fake_hidpp.Response(\"400B4D58204D61737465722033000000\", 0x83B5, \"40\"),\n    fake_hidpp.Response(\"41044B35323020202020202020202020\", 0x83B5, \"41\"),\n    fake_hidpp.Response(\"42054372616674000000000000000000\", 0x83B5, \"42\"),\n    fake_hidpp.Response(\"012411\", 0x81F1, \"01\"),\n    fake_hidpp.Response(\"020036\", 0x81F1, \"02\"),\n    fake_hidpp.Response(\"03AAAC\", 0x81F1, \"03\"),\n    fake_hidpp.Response(\"040209\", 0x81F1, \"04\"),\n]\nresponses_c534 = [\n    fake_hidpp.Response(\"000000\", 0x8003, \"FF\", handle=0x12),\n    fake_hidpp.Response(\"000209\", 0x8102, handle=0x12),\n    fake_hidpp.Response(\"0316CC9CB40502220000000000000000\", 0x83B5, \"03\", handle=0x12),\n    fake_hidpp.Response(\"00000445AB\", 0x83B5, \"04\", handle=0x12),\n]\nresponses_unusual = [\n    fake_hidpp.Response(\"000000\", 0x8003, \"FF\", handle=0x13),\n    fake_hidpp.Response(\"000300\", 0x8102, handle=0x13),\n    fake_hidpp.Response(\"00000445AB\", 0x83B5, \"04\", handle=0x13),\n    fake_hidpp.Response(\"0326CC9CB40508220000000000000000\", 0x83B5, \"03\", handle=0x13),\n]\nresponses_lacking = [\n    fake_hidpp.Response(\"000000\", 0x8003, \"FF\", handle=0x14),\n    fake_hidpp.Response(\"000300\", 0x8102, handle=0x14),\n]\n\nmouse_info = {\n    \"kind\": common.NamedInt(2, \"mouse\"),\n    \"polling\": \"8ms\",\n    \"power_switch\": common.NamedInt(1, \"base\"),\n    \"serial\": \"198E3EB8\",\n    \"wpid\": \"4082\",\n}\nc534_info = {\"kind\": common.NamedInt(0, \"unknown\"), \"polling\": \"\", \"power_switch\": \"(unknown)\", \"serial\": None, \"wpid\": \"45AB\"}\n\n\n@pytest.mark.parametrize(\n    \"device_info, responses, handle, serial, max_devices, \",\n    [\n        (DeviceInfo(path=None), [], False, None, None),\n        (DeviceInfo(path=11), [], None, None, None),\n        (DeviceInfo(path=\"11\"), responses_unifying, 0x11, \"16CC9CB4\", 6),\n        (DeviceInfo(path=\"12\", product_id=0xC534), responses_c534, 0x12, \"16CC9CB4\", 2),\n        (DeviceInfo(path=\"12\", product_id=0xC539), responses_c534, 0x12, \"16CC9CB4\", 2),\n        (DeviceInfo(path=\"13\"), responses_unusual, 0x13, \"26CC9CB4\", 1),\n        (DeviceInfo(path=\"14\"), responses_lacking, 0x14, None, 1),\n    ],\n)\ndef test_receiver_factory_create_receiver(device_info, responses, handle, serial, max_devices):\n    mock_low_level = LowLevelInterfaceFake(responses)\n\n    if handle is False:\n        with pytest.raises(Exception):  # noqa: B017\n            receiver.create_receiver(mock_low_level, device_info, lambda x: x)\n    elif handle is None:\n        r = receiver.create_receiver(mock_low_level, device_info, lambda x: x)\n        assert r is None\n    else:\n        r = receiver.create_receiver(mock_low_level, device_info, lambda x: x)\n        assert r.handle == handle\n        assert r.serial == serial\n        assert r.max_devices == max_devices\n\n\n@pytest.mark.parametrize(\n    \"device_info, responses, firmware, codename, remaining_pairings, pairing_info, count\",\n    [\n        (DeviceInfo(\"11\"), responses_unifying, 3, \"K520\", -1, mouse_info, 3),\n        (DeviceInfo(\"12\", product_id=0xC534), responses_c534, None, None, 4, c534_info, 2),\n        (DeviceInfo(\"13\", product_id=0xCCCC), responses_unusual, None, None, -1, c534_info, 3),\n    ],\n)\ndef test_receiver_factory_props(device_info, responses, firmware, codename, remaining_pairings, pairing_info, count):\n    mock_low_level = LowLevelInterfaceFake(responses)\n\n    r = receiver.create_receiver(mock_low_level, device_info, lambda x: x)\n\n    assert len(r.firmware) == firmware if firmware is not None else firmware is None\n    assert r.device_codename(2) == codename\n    assert r.remaining_pairings() == remaining_pairings\n    assert r.device_pairing_information(1) == pairing_info\n    assert r.count() == count\n\n\n@pytest.mark.parametrize(\n    \"device_info, responses, status_str, strng\",\n    [\n        (DeviceInfo(\"11\"), responses_unifying, \"No paired devices.\", \"<UnifyingReceiver(11,17)>\"),\n        (DeviceInfo(\"12\", product_id=0xC534), responses_c534, \"No paired devices.\", \"<NanoReceiver(12,18)>\"),\n        (DeviceInfo(\"13\", product_id=0xCCCC), responses_unusual, \"No paired devices.\", \"<Receiver(13,19)>\"),\n    ],\n)\ndef test_receiver_factory_string(device_info, responses, status_str, strng):\n    mock_low_level = LowLevelInterfaceFake(responses)\n\n    r = receiver.create_receiver(mock_low_level, device_info, lambda x: x)\n\n    assert r.status_string() == status_str\n    assert str(r) == strng\n\n\n@pytest.mark.parametrize(\n    \"device_info, responses\",\n    [\n        (DeviceInfo(\"14\"), responses_lacking),\n        (DeviceInfo(\"14\", product_id=\"C534\"), responses_lacking),\n    ],\n)\ndef test_receiver_factory_no_device(device_info, responses):\n    mock_low_level = LowLevelInterfaceFake(responses)\n\n    r = receiver.create_receiver(mock_low_level, device_info, lambda x: x)\n\n    with pytest.raises(exceptions.NoSuchDevice):\n        r.device_pairing_information(1)\n\n\n@pytest.mark.parametrize(\n    \"address, data, expected_online, expected_encrypted\",\n    [\n        (0x03, b\"\\x01\\x02\\x03\", True, False),\n        (0x10, b\"\\x61\\x02\\x03\", False, True),\n    ],\n)\ndef test_notification_information_nano_receiver(nano_recv, address, data, expected_online, expected_encrypted):\n    _number = 0\n    notification = base.HIDPPNotification(\n        report_id=0x01,\n        devnumber=0x52C,\n        sub_id=0,\n        address=address,\n        data=data,\n    )\n    online, encrypted, wpid, kind = nano_recv.notification_information(_number, notification)\n\n    assert online == expected_online\n    assert encrypted == expected_encrypted\n    assert wpid == \"0302\"\n    assert kind == \"keyboard\"\n\n\ndef test_extract_serial_number():\n    response = b'\\x03\\x16\\xcc\\x9c\\xb4\\x05\\x06\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n\n    serial_number = receiver.extract_serial(response[1:5])\n\n    assert serial_number == \"16CC9CB4\"\n\n\ndef test_extract_max_devices():\n    response = b'\\x03\\x16\\xcc\\x9c\\xb4\\x05\\x06\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n\n    max_devices = receiver.extract_max_devices(response)\n\n    assert max_devices == 6\n\n\n@pytest.mark.parametrize(\n    \"response, expected_remaining_pairings\",\n    [\n        (b\"\\x00\\x03\\x00\", -1),\n        (b\"\\x00\\x02\\t\", 4),\n    ],\n)\ndef test_extract_remaining_pairings(response, expected_remaining_pairings):\n    remaining_pairings = receiver.extract_remaining_pairings(response)\n\n    assert remaining_pairings == expected_remaining_pairings\n\n\ndef test_extract_codename():\n    response = b\"A\\x04K520\"\n\n    codename = receiver.extract_codename(response)\n\n    assert codename == \"K520\"\n\n\n@pytest.mark.parametrize(\n    \"power_switch_byte, expected_location\",\n    [\n        (b\"\\x01\", \"base\"),\n        (b\"\\x09\", \"top_edge\"),\n        (b\"\\x0c\", \"bottom_edge\"),\n        (b\"\\x00\", \"unknown\"),\n        (b\"\\x0f\", \"unknown\"),\n    ],\n)\ndef test_extract_power_switch_location(power_switch_byte, expected_location):\n    response = b\"\\x19\\x8e>\\xb8\\x06\\x00\\x00\\x00\\x00\" + power_switch_byte + b\"\\x00\\x00\\x00\\x00\\x00\"\n\n    ps_location = receiver.extract_power_switch_location(response)\n\n    assert ps_location == expected_location\n\n\ndef test_extract_connection_count():\n    response = b\"\\x00\\x03\\x00\"\n\n    connection_count = receiver.extract_connection_count(response)\n\n    assert connection_count == 3\n\n\ndef test_extract_wpid():\n    response = b\"@\\x82\"\n\n    res = receiver.extract_wpid(response)\n\n    assert res == \"4082\"\n\n\ndef test_extract_polling_rate():\n    response = b\"\\x08@\\x82\\x04\\x02\\x02\\x07\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n\n    polling_rate = receiver.extract_polling_rate(response)\n\n    assert polling_rate == 130\n\n\n@pytest.mark.parametrize(\n    \"data, expected_device_kind\",\n    [\n        (0x00, \"unknown\"),\n        (0x03, \"numpad\"),\n    ],\n)\ndef test_extract_device_kind(data, expected_device_kind):\n    device_kind = receiver.extract_device_kind(data)\n\n    assert str(device_kind) == expected_device_kind\n"
  },
  {
    "path": "tests/logitech_receiver/test_setting_templates.py",
    "content": "## Copyright (C) 2024  Solaar Contributors https://pwr-solaar.github.io/Solaar/\n##\n## This program is free software; you can redistribute it and/or modify\n## it under the terms of the GNU General Public License as published by\n## the Free Software Foundation; either version 2 of the License, or\n## (at your option) any later version.\n##\n## This program is distributed in the hope that it will be useful,\n## but WITHOUT ANY WARRANTY; without even the implied warranty of\n## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n## GNU General Public License for more details.\n##\n## You should have received a copy of the GNU General Public License along\n## with this program; if not, write to the Free Software Foundation, Inc.,\n## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n\"\"\"The tests work by creating a faked device (from the hidpp module) that uses provided data as responses to HID++ commands.\nThe device uses some methods from the real device to set up data structures that are needed for some tests.\n\"\"\"\n\nfrom dataclasses import dataclass\nfrom typing import Any\n\nimport pytest\n\nfrom logitech_receiver import common\nfrom logitech_receiver import hidpp20\nfrom logitech_receiver import hidpp20_constants\nfrom logitech_receiver import settings_templates\nfrom logitech_receiver import special_keys\n\nfrom . import fake_hidpp\n\n# TODO action part of DpiSlidingXY, MouseGesturesXY\n\n\nclass Setup:\n    def __init__(self, test, *params):\n        self.test = test\n        self.responses = [r for r in params if isinstance(r, fake_hidpp.Response)]\n        self.choices = None if isinstance(params[0], fake_hidpp.Response) else params[0]\n\n\n@dataclass\nclass RegisterTest:\n    sclass: Any\n    initial_value: Any = False\n    write_value: Any = True\n    write_params: str = \"01\"\n\n\nregister_tests = [\n    Setup(\n        RegisterTest(settings_templates.RegisterHandDetection, False, True, [b\"\\x00\\x00\\x00\"]),\n        fake_hidpp.Response(\"000030\", 0x8101),  # keyboard_hand_detection\n        fake_hidpp.Response(\"000000\", 0x8001, \"000000\"),\n    ),\n    Setup(\n        RegisterTest(settings_templates.RegisterHandDetection, True, False, [b\"\\x00\\x00\\x30\"]),\n        fake_hidpp.Response(\"000000\", 0x8101),  # keyboard_hand_detection\n        fake_hidpp.Response(\"000030\", 0x8001, \"000030\"),\n    ),\n    Setup(\n        RegisterTest(settings_templates.RegisterSmoothScroll, False, True, [b\"\\x40\"]),\n        fake_hidpp.Response(\"00\", 0x8101),  # mouse_button_flags\n        fake_hidpp.Response(\"40\", 0x8001, \"40\"),\n    ),\n    Setup(\n        RegisterTest(settings_templates.RegisterSideScroll, True, False, [b\"\\x00\"]),\n        fake_hidpp.Response(\"02\", 0x8101),  # mouse_button_flags\n        fake_hidpp.Response(\"00\", 0x8001, \"00\"),\n    ),\n    Setup(\n        RegisterTest(settings_templates.RegisterFnSwap, False, True, [b\"\\x00\\x01\"]),\n        fake_hidpp.Response(\"0000\", 0x8109),  # keyboard_fn_swap\n        fake_hidpp.Response(\"0001\", 0x8009, \"0001\"),\n    ),\n    Setup(\n        RegisterTest(\n            settings_templates._PerformanceMXDpi, common.NamedInt(0x88, \"800\"), common.NamedInt(0x89, \"900\"), [b\"\\x89\"]\n        ),\n        fake_hidpp.Response(\"88\", 0x8163),  # mouse_dpi\n        fake_hidpp.Response(\"89\", 0x8063, \"89\"),\n    ),\n]\n\n\n@pytest.mark.parametrize(\"test\", register_tests)\ndef test_register_template(test, mocker):\n    device = fake_hidpp.Device(protocol=1.0, responses=test.responses)\n    spy_request = mocker.spy(device, \"request\")\n\n    setting = test.test.sclass.build(device)\n    value = setting.read(cached=False)\n    cached_value = setting.read(cached=True)\n    write_value = setting.write(test.test.write_value)\n\n    assert setting is not None\n    assert value == test.test.initial_value\n    assert cached_value == test.test.initial_value\n    assert write_value == test.test.write_value\n    spy_request.assert_called_with(test.test.sclass.register + 0x8000, *test.test.write_params)\n\n\n@dataclass\nclass FeatureTest:\n    sclass: Any\n    initial_value: Any = False\n    write_value: Any = True\n    matched_calls: int = 1\n    offset: int = 0x04\n    version: int = 0x00\n    rewrite: bool = False\n    readable: bool = True\n\n\nsimple_tests = [\n    Setup(\n        FeatureTest(settings_templates.K375sFnSwap, False, True, offset=0x06),\n        fake_hidpp.Response(\"FF0001\", 0x0600, \"FF\"),\n        fake_hidpp.Response(\"FF0101\", 0x0610, \"FF01\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.K375sFnSwap, False, True, offset=0x06),\n        fake_hidpp.Response(\"050001\", 0x0000, \"1815\"),  # HOSTS_INFO\n        fake_hidpp.Response(\"FF0001\", 0x0600, \"FF\"),\n        fake_hidpp.Response(\"FF0101\", 0x0610, \"FF01\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.K375sFnSwap, False, True, offset=0x06),\n        fake_hidpp.Response(\"050001\", 0x0000, \"1815\"),  # HOSTS_INFO\n        fake_hidpp.Response(\"07050301\", 0x0500),  # current host is 0x01, i.e., host 2\n        fake_hidpp.Response(\"010001\", 0x0600, \"01\"),\n        fake_hidpp.Response(\"010101\", 0x0610, \"0101\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.FnSwap, True, False),\n        fake_hidpp.Response(\"01\", 0x0400),\n        fake_hidpp.Response(\"00\", 0x0410, \"00\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.NewFnSwap, True, False),\n        fake_hidpp.Response(\"01\", 0x0400),\n        fake_hidpp.Response(\"00\", 0x0410, \"00\"),\n    ),\n    #    Setup(  # Backlight has caused problems\n    #        FeatureTest(settings_templates.Backlight, 0, 5, offset=0x06),\n    #        fake_hidpp.Response(\"00\", 0x0600),\n    #        fake_hidpp.Response(\"05\", 0x0610, \"05\"),\n    #    ),\n    Setup(\n        FeatureTest(settings_templates.Backlight2DurationHandsOut, 80, 160, version=0x03),\n        fake_hidpp.Response(\"011830000000100040006000\", 0x0400),\n        fake_hidpp.Response(\"0118FF00200040006000\", 0x0410, \"0118FF00200040006000\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.Backlight2DurationHandsIn, 320, 160, version=0x03),\n        fake_hidpp.Response(\"011830000000200040006000\", 0x0400),\n        fake_hidpp.Response(\"0118FF00200020006000\", 0x0410, \"0118FF00200020006000\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.Backlight2DurationPowered, 480, 80, version=0x03),\n        fake_hidpp.Response(\"011830000000200040006000\", 0x0400),\n        fake_hidpp.Response(\"0118FF00200040001000\", 0x0410, \"0118FF00200040001000\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.Backlight3, 0x50, 0x70),\n        fake_hidpp.Response(\"50\", 0x0410),\n        fake_hidpp.Response(\"70\", 0x0420, \"007009\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.HiResScroll, True, False),\n        fake_hidpp.Response(\"01\", 0x0400),\n        fake_hidpp.Response(\"00\", 0x0410, \"00\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.LowresMode, False, True),\n        fake_hidpp.Response(\"00\", 0x0400),\n        fake_hidpp.Response(\"01\", 0x0410, \"01\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.HiresSmoothInvert, True, False),\n        fake_hidpp.Response(\"06\", 0x0410),\n        fake_hidpp.Response(\"02\", 0x0420, \"02\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.HiresSmoothResolution, True, False),\n        fake_hidpp.Response(\"06\", 0x0410),\n        fake_hidpp.Response(\"04\", 0x0420, \"04\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.HiresMode, False, True),\n        fake_hidpp.Response(\"06\", 0x0410),\n        fake_hidpp.Response(\"07\", 0x0420, \"07\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.PointerSpeed, 0x0100, 0x0120),\n        fake_hidpp.Response(\"0100\", 0x0400),\n        fake_hidpp.Response(\"0120\", 0x0410, \"0120\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.ThumbMode, True, False),\n        fake_hidpp.Response(\"0100\", 0x0410),\n        fake_hidpp.Response(\"0000\", 0x0420, \"0000\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.ThumbInvert, False, True),\n        fake_hidpp.Response(\"0100\", 0x0410),\n        fake_hidpp.Response(\"0101\", 0x0420, \"0101\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.DivertCrown, False, True),\n        fake_hidpp.Response(\"01\", 0x0410),\n        fake_hidpp.Response(\"02\", 0x0420, \"02\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.CrownSmooth, True, False),\n        fake_hidpp.Response(\"0001\", 0x0410),\n        fake_hidpp.Response(\"0002\", 0x0420, \"0002\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.DivertGkeys, False, True),\n        fake_hidpp.Response(\"01\", 0x0420, \"01\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.ScrollRatchet, 2, 1),\n        fake_hidpp.Response(\"02\", 0x0400),\n        fake_hidpp.Response(\"01\", 0x0410, \"01\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.SmartShift, 1, 10),\n        fake_hidpp.Response(\"0100\", 0x0400),\n        fake_hidpp.Response(\"000A\", 0x0410, \"000A\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.SmartShift, 5, 50),\n        fake_hidpp.Response(\"0005\", 0x0400),\n        fake_hidpp.Response(\"00FF\", 0x0410, \"00FF\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.SmartShiftEnhanced, 5, 50),\n        fake_hidpp.Response(\"0005\", 0x0410),\n        fake_hidpp.Response(\"00FF\", 0x0420, \"00FF\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.DisableKeyboardKeys, {1: True, 8: True}, {1: False, 8: True}),\n        fake_hidpp.Response(\"09\", 0x0400),\n        fake_hidpp.Response(\"09\", 0x0410),\n        fake_hidpp.Response(\"08\", 0x0420, \"08\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.DualPlatform, 0, 1),\n        fake_hidpp.Response(\"00\", 0x0400),\n        fake_hidpp.Response(\"01\", 0x0420, \"01\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.MKeyLEDs, {1: False, 2: False, 4: False}, {1: False, 2: True, 4: True}),\n        fake_hidpp.Response(\"03\", 0x0400),\n        fake_hidpp.Response(\"06\", 0x0410, \"06\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.MRKeyLED, False, True),\n        fake_hidpp.Response(\"01\", 0x0400, \"01\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.Sidetone, 5, 0xA),\n        fake_hidpp.Response(\"05\", 0x0400),\n        fake_hidpp.Response(\"0A\", 0x0410, \"0A\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.ADCPower, 5, 0xA, version=0x03),\n        fake_hidpp.Response(\"05\", 0x0410),\n        fake_hidpp.Response(\"0A\", 0x0420, \"0A\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.LEDControl, 0, 1),\n        fake_hidpp.Response(\"00\", 0x0470),\n        fake_hidpp.Response(\"01\", 0x0480, \"01\"),\n    ),\n    Setup(\n        FeatureTest(\n            settings_templates.LEDZoneSetting,\n            hidpp20.LEDEffectSetting(ID=3, intensity=0x50, period=0x100),\n            hidpp20.LEDEffectSetting(ID=3, intensity=0x50, period=0x101),\n        ),\n        fake_hidpp.Response(\"0100000001\", 0x0400),\n        fake_hidpp.Response(\"00000102\", 0x0410, \"00FF00\"),\n        fake_hidpp.Response(\"0000000300040005\", 0x0420, \"000000\"),\n        fake_hidpp.Response(\"0001000B00080009\", 0x0420, \"000100\"),\n        fake_hidpp.Response(\"000000000000010050\", 0x04E0, \"00\"),\n        fake_hidpp.Response(\"000000000000000101500000\", 0x0430, \"000000000000000101500000\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.RGBControl, 0, 1),\n        fake_hidpp.Response(\"0000\", 0x0450),\n        fake_hidpp.Response(\"010100\", 0x0450, \"0101\"),\n    ),\n    Setup(\n        FeatureTest(\n            settings_templates.RGBEffectSetting,\n            hidpp20.LEDEffectSetting(ID=3, intensity=0x50, period=0x100),\n            hidpp20.LEDEffectSetting(ID=2, color=0x505050, speed=0x50),\n            readable=False,\n        ),\n        fake_hidpp.Response(\"FFFF0100000001\", 0x0400, \"FFFF00\"),\n        fake_hidpp.Response(\"0000000102\", 0x0400, \"00FF00\"),\n        fake_hidpp.Response(\"0000000300040005\", 0x0400, \"000000\"),\n        fake_hidpp.Response(\"0001000200080009\", 0x0400, \"000100\"),\n        fake_hidpp.Response(\"000000000000010050\", 0x04E0, \"00\"),\n        fake_hidpp.Response(\"00015050505000000000000001\", 0x0410, \"00015050505000000000000001\"),\n    ),\n    Setup(\n        FeatureTest(\n            settings_templates.RGBEffectSetting,\n            None,\n            hidpp20.LEDEffectSetting(ID=3, intensity=0x60, period=0x101),\n            readable=False,\n        ),\n        fake_hidpp.Response(\"FFFF0100000001\", 0x0400, \"FFFF00\"),\n        fake_hidpp.Response(\"0000000102\", 0x0400, \"00FF00\"),\n        fake_hidpp.Response(\"0000000300040005\", 0x0400, \"000000\"),\n        fake_hidpp.Response(\"0001000200080009\", 0x0400, \"000100\"),\n        fake_hidpp.Response(\"00000000000000010160000001\", 0x0410, \"00000000000000010160000001\"),\n    ),\n    Setup(\n        FeatureTest(\n            settings_templates.RGBEffectSetting,\n            None,\n            hidpp20.LEDEffectSetting(ID=3, intensity=0x60, period=0x101),\n            readable=False,\n        ),\n        fake_hidpp.Response(\"FF000200020004000000000000000000\", 0x0400, \"FFFF00\"),\n        fake_hidpp.Response(\"00000002040000000000000000000000\", 0x0400, \"00FF00\"),\n        fake_hidpp.Response(\"00000000000000000000000000000000\", 0x0400, \"000000\"),\n        fake_hidpp.Response(\"00010001000000000000000000000000\", 0x0400, \"000100\"),\n        fake_hidpp.Response(\"00020003C00503E00000000000000000\", 0x0400, \"000200\"),\n        fake_hidpp.Response(\"0003000AC0011E0B0000000000000000\", 0x0400, \"000300\"),\n        fake_hidpp.Response(\"01000001070000000000000000000000\", 0x0400, \"01FF00\"),\n        fake_hidpp.Response(\"01000000000000000000000000000000\", 0x0400, \"010000\"),\n        fake_hidpp.Response(\"01010001000000000000000000000000\", 0x0400, \"010100\"),\n        fake_hidpp.Response(\"0102000AC0011E0B0000000000000000\", 0x0400, \"010200\"),\n        fake_hidpp.Response(\"01030003C00503E00000000000000000\", 0x0400, \"010300\"),\n        fake_hidpp.Response(\"01040004DCE1001E0000000000000000\", 0x0400, \"010400\"),\n        fake_hidpp.Response(\"0105000B000000320000000000000000\", 0x0400, \"010500\"),\n        fake_hidpp.Response(\"0106000C001B02340000000000000000\", 0x0400, \"010600\"),\n        fake_hidpp.Response(\"00020000000000010160000001\", 0x0410, \"00020000000000010160000001\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.Backlight2, 0xFF, 0x00),\n        common.NamedInts(Disabled=0xFF, Enabled=0x00),\n        fake_hidpp.Response(\"000201000000000000000000\", 0x0400),\n        fake_hidpp.Response(\"010201\", 0x0410, \"0102FF00000000000000\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.Backlight2, 0x03, 0xFF),\n        common.NamedInts(Disabled=0xFF, Automatic=0x01, Manual=0x03),\n        fake_hidpp.Response(\"011838000000000000000000\", 0x0400),\n        fake_hidpp.Response(\"001801\", 0x0410, \"0018FF00000000000000\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.Backlight2Level, 0, 3, version=0x03),\n        [0, 4],\n        fake_hidpp.Response(\"011830000000000000000000\", 0x0400),\n        fake_hidpp.Response(\"05\", 0x0420),\n        fake_hidpp.Response(\"01180103000000000000\", 0x0410, \"0118FF03000000000000\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.Backlight2Level, 0, 2, version=0x03),\n        [0, 4],\n        fake_hidpp.Response(\"011830000000000000000000\", 0x0400),\n        fake_hidpp.Response(\"05\", 0x0420),\n        fake_hidpp.Response(\"01180102000000000000\", 0x0410, \"0118FF02000000000000\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.OnboardProfiles, 0, 1, offset=0x0C),\n        common.NamedInts(**{\"Disabled\": 0, \"Profile 1\": 1, \"Profile 2\": 2}),\n        fake_hidpp.Response(\"01030001010101000101\", 0x0C00),\n        fake_hidpp.Response(\"00010100000201FFFFFFFFFFFFFFFFFF\", 0x0C50, \"00000000\"),\n        fake_hidpp.Response(\"000201FFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0C50, \"00000004\"),\n        fake_hidpp.Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0C50, \"00000008\"),\n        fake_hidpp.Response(\"02\", 0x0C20),\n        fake_hidpp.Response(\"01\", 0x0C10, \"01\"),\n        fake_hidpp.Response(\"0001\", 0x0C30, \"0001\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.OnboardProfiles, 1, 0, offset=0x0C),\n        common.NamedInts(**{\"Disabled\": 0, \"Profile 1\": 1, \"Profile 2\": 2}),\n        fake_hidpp.Response(\"01030001010101000101\", 0x0C00),\n        fake_hidpp.Response(\"00010100000201FFFFFFFFFFFFFFFFFF\", 0x0C50, \"00000000\"),\n        fake_hidpp.Response(\"000201FFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0C50, \"00000004\"),\n        fake_hidpp.Response(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\", 0x0C50, \"00000008\"),\n        fake_hidpp.Response(\"01\", 0x0C20),\n        fake_hidpp.Response(\"0001\", 0x0C40),\n        fake_hidpp.Response(\"02\", 0x0C10, \"02\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.ReportRate, 1, 5, offset=0x0C),\n        common.NamedInts(**{\"1ms\": 1, \"2ms\": 2, \"5ms\": 5, \"6ms\": 6}),\n        fake_hidpp.Response(\"33\", 0x0C00),\n        fake_hidpp.Response(\"01\", 0x0C10),\n        fake_hidpp.Response(\"05\", 0x0C20, \"05\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.ExtendedReportRate, 1, 5, offset=0x0C),\n        common.NamedInts(**{\"8ms\": 0, \"4ms\": 1, \"500us\": 4, \"250us\": 5}),\n        fake_hidpp.Response(\"33\", 0x0C10),\n        fake_hidpp.Response(\"01\", 0x0C20),\n        fake_hidpp.Response(\"05\", 0x0C30, \"05\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.AdjustableDpi, 800, 400, version=0x03),\n        common.NamedInts.list([400, 800, 1600]),\n        fake_hidpp.Response(\"000190032006400000\", 0x0410, \"000000\"),\n        fake_hidpp.Response(\"000320\", 0x0420),\n        fake_hidpp.Response(\"000190\", 0x0430, \"000190\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.AdjustableDpi, 256, 512, version=0x03),\n        common.NamedInts.list([256, 512]),\n        fake_hidpp.Response(\"000100e10002000000\", 0x0410, \"000000\"),\n        fake_hidpp.Response(\"000100\", 0x0420),\n        fake_hidpp.Response(\"000200\", 0x0430, \"000200\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.AdjustableDpi, 400, 800, version=0x03),\n        common.NamedInts.list([400, 800, 1200, 1600]),\n        fake_hidpp.Response(\"000190E19006400000000000000000\", 0x0410, \"000000\"),\n        fake_hidpp.Response(\"000190\", 0x0420),\n        fake_hidpp.Response(\"000320\", 0x0430, \"000320\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.Multiplatform, 0, 1),\n        common.NamedInts(**{\"MacOS 0.1-0.5\": 0, \"iOS 0.1-0.7\": 1, \"Linux 0.2-0.9\": 2, \"Windows 0.3-0.9\": 3}),\n        fake_hidpp.Response(\"020004000001\", 0x0400),\n        fake_hidpp.Response(\"00FF200000010005\", 0x0410, \"00\"),\n        fake_hidpp.Response(\"01FF400000010007\", 0x0410, \"01\"),\n        fake_hidpp.Response(\"02FF040000020009\", 0x0410, \"02\"),\n        fake_hidpp.Response(\"03FF010000030009\", 0x0410, \"03\"),\n        fake_hidpp.Response(\"FF01\", 0x0430, \"FF01\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.ChangeHost, 1, 0),\n        common.NamedInts(**{\"1:ABCDEF\": 0, \"2:GHIJKL\": 1}),\n        fake_hidpp.Response(\"050003\", 0x0000, \"1815\"),  # HOSTS_INFO\n        fake_hidpp.Response(\"01000200\", 0x0500),\n        fake_hidpp.Response(\"000100000600\", 0x0510, \"00\"),\n        fake_hidpp.Response(\"000041424344454600\", 0x0530, \"0000\"),\n        fake_hidpp.Response(\"000100000600\", 0x0510, \"01\"),\n        fake_hidpp.Response(\"00004748494A4B4C00\", 0x0530, \"0100\"),\n        fake_hidpp.Response(\"0201\", 0x0400),\n        fake_hidpp.Response(True, 0x0410, \"00\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.BrightnessControl, 0x10, 0x20),\n        [0, 80],\n        fake_hidpp.Response(\"00505100000000\", 0x0400),  # 0 to 80, all acceptable, no separate on/off\n        fake_hidpp.Response(\"10\", 0x0410),  # brightness 16\n        fake_hidpp.Response(\"0020\", 0x0420, \"0020\"),  # set brightness 32\n    ),\n    Setup(\n        FeatureTest(settings_templates.BrightnessControl, 0x10, 0x00),\n        [0, 80],\n        fake_hidpp.Response(\"00505104000000\", 0x0400),  # 0 to 80, all acceptable, separate on/off\n        fake_hidpp.Response(\"10\", 0x0410),  # brightness 16\n        fake_hidpp.Response(\"01\", 0x0430),  # on\n        fake_hidpp.Response(\"00\", 0x0440),  # set off\n        fake_hidpp.Response(\"0000\", 0x0420, \"0000\"),  # set brightness 0\n    ),\n    Setup(\n        FeatureTest(settings_templates.BrightnessControl, 0x00, 0x20),\n        [0, 80],\n        fake_hidpp.Response(\"00505104000000\", 0x0400),  # 0 to 80, all acceptable, separate on/off\n        fake_hidpp.Response(\"10\", 0x0410),  # brightness 16\n        fake_hidpp.Response(\"00\", 0x0430),  # off\n        fake_hidpp.Response(\"01\", 0x0440),  # set on\n        fake_hidpp.Response(\"0020\", 0x0420, \"0020\"),  # set brightness 32\n    ),\n    Setup(\n        FeatureTest(settings_templates.BrightnessControl, 0x20, 0x08),\n        [0, 80],\n        fake_hidpp.Response(\"00504104001000\", 0x0400),  # 16 to 80, all acceptable, separate on/off\n        fake_hidpp.Response(\"20\", 0x0410),  # brightness 32\n        fake_hidpp.Response(\"01\", 0x0430),  # on\n        fake_hidpp.Response(\"00\", 0x0440, \"00\"),  # set off\n    ),\n    Setup(\n        FeatureTest(settings_templates.SpeedChange, 0, None, 0),  # need to set up all settings to successfully write\n        common.NamedInts(**{\"Off\": 0, \"DPI Change\": 0xED}),\n        *fake_hidpp.responses_speedchange,\n    ),\n]\n\n\n@pytest.fixture\ndef mock_gethostname(mocker):\n    mocker.patch(\"socket.gethostname\", return_value=\"ABCDEF.foo.org\")\n\n\n@pytest.mark.parametrize(\"test\", simple_tests)\ndef test_simple_template(test, mocker, mock_gethostname):\n    tst = test.test\n    print(\"TEST\", tst.sclass, tst.sclass.feature)\n    device = fake_hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version)\n    spy_request = mocker.spy(device, \"request\")\n\n    setting = settings_templates.check_feature(device, tst.sclass)\n    assert setting is not None\n    if isinstance(setting, list):\n        setting = setting[0]\n    if isinstance(test.choices, list):\n        assert setting._validator.min_value == test.choices[0]\n        assert setting._validator.max_value == test.choices[1]\n    elif test.choices is not None:\n        assert setting.choices == test.choices\n\n    if tst.readable:\n        value = setting.read(cached=False)\n        assert value == tst.initial_value\n\n        cached_value = setting.read(cached=True)\n        assert cached_value == tst.initial_value\n\n    write_value = setting.write(tst.write_value) if tst.write_value is not None else None\n    assert write_value == tst.write_value\n\n    fake_hidpp.match_requests(tst.matched_calls, test.responses, spy_request.call_args_list)\n\n\nresponses_reprog_controls = [\n    fake_hidpp.Response(\"03\", 0x0500),\n    fake_hidpp.Response(\"00500038010001010400000000000000\", 0x0510, \"00\"),  # left button\n    fake_hidpp.Response(\"00510039010001010400000000000000\", 0x0510, \"01\"),  # right button\n    fake_hidpp.Response(\"00C4009D310003070500000000000000\", 0x0510, \"02\"),  # smart shift\n    fake_hidpp.Response(\"00500000000000000000000000000000\", 0x0520, \"0050\"),  # left button current\n    fake_hidpp.Response(\"00510000500000000000000000000000\", 0x0520, \"0051\"),  # right button current\n    fake_hidpp.Response(\"00C40000000000000000000000000000\", 0x0520, \"00C4\"),  # smart shift current\n    fake_hidpp.Response(\"00500005000000000000000000000000\", 0x0530, \"0050000050\"),  # left button write\n    fake_hidpp.Response(\"00510005000000000000000000000000\", 0x0530, \"0051000050\"),  # right button write\n    fake_hidpp.Response(\"00C4000C400000000000000000000000\", 0x0530, \"00C40000C4\"),  # smart shift write\n]\n\nkey_tests = [\n    Setup(\n        FeatureTest(settings_templates.ReprogrammableKeys, {0x50: 0x50, 0x51: 0x50, 0xC4: 0xC4}, {0x51: 0x51}, 4, offset=0x05),\n        {\n            common.NamedInt(0x50, \"Left Button\"): common.UnsortedNamedInts(Left_Click=0x50, Right_Click=0x51),\n            common.NamedInt(0x51, \"Right Button\"): common.UnsortedNamedInts(Right_Click=0x51, Left_Click=0x50),\n            common.NamedInt(0xC4, \"Smart Shift\"): common.UnsortedNamedInts(Smart_Shift=0xC4, Left_Click=80, Right_Click=81),\n        },\n        *responses_reprog_controls,\n        fake_hidpp.Response(\"0051000051\", 0x0530, \"0051000051\"),  # right button set write\n    ),\n    Setup(\n        FeatureTest(settings_templates.DivertKeys, {0xC4: 0}, {0xC4: 1}, 2, offset=0x05),\n        {common.NamedInt(0xC4, \"Smart Shift\"): common.NamedInts(Regular=0, Diverted=1, Mouse_Gestures=2)},\n        *responses_reprog_controls,\n        fake_hidpp.Response(\"00C4020000\", 0x0530, \"00C4020000\"),  # Smart Shift write\n        fake_hidpp.Response(\"00C4030000\", 0x0530, \"00C4030000\"),  # Smart Shift divert write\n    ),\n    Setup(\n        FeatureTest(settings_templates.DivertKeys, {0xC4: 0}, {0xC4: 2}, 2, offset=0x05),\n        {common.NamedInt(0xC4, \"Smart Shift\"): common.NamedInts(Regular=0, Diverted=1, Mouse_Gestures=2, Sliding_DPI=3)},\n        *responses_reprog_controls,\n        fake_hidpp.Response(\"0A0001\", 0x0000, \"2201\"),  # ADJUSTABLE_DPI\n        fake_hidpp.Response(\"00C4300000\", 0x0530, \"00C4300000\"),  # Smart Shift write\n        fake_hidpp.Response(\"00C4030000\", 0x0530, \"00C4030000\"),  # Smart Shift divert write\n    ),\n    Setup(\n        FeatureTest(settings_templates.PersistentRemappableAction, {80: 16797696, 81: 16797696}, {0x51: 16797952}, 3),\n        {\n            common.NamedInt(80, \"Left Button\"): special_keys.KEYS_KEYS_CONSUMER,\n            common.NamedInt(81, \"Right Button\"): special_keys.KEYS_KEYS_CONSUMER,\n        },\n        fake_hidpp.Response(\"050001\", 0x0000, \"1B04\"),  # REPROG_CONTROLS_V4\n        *responses_reprog_controls,\n        fake_hidpp.Response(\"0041\", 0x0400),\n        fake_hidpp.Response(\"0201\", 0x0410),\n        fake_hidpp.Response(\"02\", 0x0400),\n        fake_hidpp.Response(\"0050\", 0x0420, \"00FF\"),  # left button\n        fake_hidpp.Response(\"0051\", 0x0420, \"01FF\"),  # right button\n        fake_hidpp.Response(\"0050000100500000\", 0x0430, \"0050FF\"),  # left button current\n        fake_hidpp.Response(\"0051000100500001\", 0x0430, \"0051FF\"),  # right button current\n        fake_hidpp.Response(\"0050FF01005000\", 0x0440, \"0050FF01005000\"),  # left button write\n        fake_hidpp.Response(\"0051FF01005000\", 0x0440, \"0051FF01005000\"),  # right button write\n        fake_hidpp.Response(\"0051FF01005100\", 0x0440, \"0051FF01005100\"),  # right button set write\n    ),\n    Setup(\n        FeatureTest(\n            settings_templates.Gesture2Gestures,\n            {\n                1: True,\n                2: True,\n                30: True,\n                10: True,\n                45: False,\n                42: True,\n                43: True,\n                64: False,\n                65: False,\n                67: False,\n                84: True,\n                34: False,\n            },\n            {45: True},\n            4,\n        ),\n        *fake_hidpp.responses_gestures,\n        fake_hidpp.Response(\"0001FF6F\", 0x0420, \"0001FF6F\"),  # write\n        fake_hidpp.Response(\"01010F04\", 0x0420, \"01010F04\"),\n        fake_hidpp.Response(\"0001FF7F\", 0x0420, \"0001FF7F\"),  # write 45\n        fake_hidpp.Response(\"01010F04\", 0x0420, \"01010F04\"),\n    ),\n    Setup(\n        FeatureTest(\n            settings_templates.Gesture2Divert,\n            {1: False, 2: False, 10: False, 44: False, 64: False, 65: False, 67: False, 84: False, 85: False, 100: False},\n            {44: True},\n            4,\n        ),\n        *fake_hidpp.responses_gestures,\n        fake_hidpp.Response(\"0001FF00\", 0x0440, \"0001FF00\"),  # write\n        fake_hidpp.Response(\"01010300\", 0x0440, \"01010300\"),\n        fake_hidpp.Response(\"0001FF08\", 0x0440, \"0001FF08\"),  # write 44\n        fake_hidpp.Response(\"01010300\", 0x0440, \"01010300\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.Gesture2Params, {4: {\"scale\": 256}}, {4: {\"scale\": 128}}, 2),\n        *fake_hidpp.responses_gestures,\n        fake_hidpp.Response(\"000100FF000000000000000000000000\", 0x0480, \"000100FF\"),\n        fake_hidpp.Response(\"000080FF000000000000000000000000\", 0x0480, \"000080FF\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.Equalizer, {0: -0x20, 1: 0x10}, {1: 0x18}, 2),\n        [-32, 32],\n        fake_hidpp.Response(\"0220000000\", 0x0400),\n        fake_hidpp.Response(\"0000800100000000000000\", 0x0410, \"00\"),\n        fake_hidpp.Response(\"E010\", 0x0420, \"00\"),\n        fake_hidpp.Response(\"E010\", 0x0430, \"02E010\"),\n        fake_hidpp.Response(\"E018\", 0x0430, \"02E018\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.PerKeyLighting, {1: -1, 2: -1, 9: -1, 10: -1, 113: -1}, {2: 0xFF0000}, 4, 4, 0, 1),\n        {\n            common.NamedInt(1, \"A\"): special_keys.COLORSPLUS,\n            common.NamedInt(2, \"B\"): special_keys.COLORSPLUS,\n            common.NamedInt(9, \"I\"): special_keys.COLORSPLUS,\n            common.NamedInt(10, \"J\"): special_keys.COLORSPLUS,\n            common.NamedInt(113, \"KEY 113\"): special_keys.COLORSPLUS,\n        },\n        fake_hidpp.Response(\"00000606000000000000000000000000\", 0x0400, \"0000\"),  # first group of keys\n        fake_hidpp.Response(\"00000200000000000000000000000000\", 0x0400, \"0001\"),  # second group of keys\n        fake_hidpp.Response(\"00000000000000000000000000000000\", 0x0400, \"0002\"),  # last group of keys\n        fake_hidpp.Response(\"02FF0000\", 0x0410, \"02FF0000\"),  # write one value\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n        fake_hidpp.Response(\"02FF0000\", 0x0410, \"02FF0000\"),  # write one value\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n    ),\n    Setup(\n        FeatureTest(\n            settings_templates.PerKeyLighting,\n            {1: -1, 2: -1, 9: -1, 10: -1, 113: -1},\n            {2: 0xFF0000, 9: 0xFF0000, 10: 0xFF0000},\n            8,\n            4,\n            0,\n            1,\n        ),\n        {\n            common.NamedInt(1, \"A\"): special_keys.COLORSPLUS,\n            common.NamedInt(2, \"B\"): special_keys.COLORSPLUS,\n            common.NamedInt(9, \"I\"): special_keys.COLORSPLUS,\n            common.NamedInt(10, \"J\"): special_keys.COLORSPLUS,\n            common.NamedInt(113, \"KEY 113\"): special_keys.COLORSPLUS,\n        },\n        fake_hidpp.Response(\"00000606000000000000000000000000\", 0x0400, \"0000\"),  # first group of keys\n        fake_hidpp.Response(\"00000200000000000000000000000000\", 0x0400, \"0001\"),  # second group of keys\n        fake_hidpp.Response(\"00000000000000000000000000000000\", 0x0400, \"0002\"),  # last group of keys\n        fake_hidpp.Response(\"02FF0000\", 0x0410, \"02FF0000\"),  # write one value\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n        fake_hidpp.Response(\"09FF0000\", 0x0410, \"09FF0000\"),  # write one value\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n        fake_hidpp.Response(\"0AFF0000\", 0x0410, \"0AFF0000\"),  # write one value\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n        fake_hidpp.Response(\"02FF000009FF00000AFF0000\", 0x0410, \"02FF000009FF00000AFF0000\"),  # write three values\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n    ),\n    Setup(\n        FeatureTest(\n            settings_templates.PerKeyLighting,\n            {1: -1, 2: -1, 9: -1, 10: -1, 113: -1, 114: -1},\n            {1: 0xFF0000, 2: 0xFF0000, 9: 0xFF0000, 10: 0xFF0000, 113: 0x00FF00, 114: 0xFF0000},\n            15,\n            4,\n            0,\n            1,\n        ),\n        {\n            common.NamedInt(1, \"A\"): special_keys.COLORSPLUS,\n            common.NamedInt(2, \"B\"): special_keys.COLORSPLUS,\n            common.NamedInt(9, \"I\"): special_keys.COLORSPLUS,\n            common.NamedInt(10, \"J\"): special_keys.COLORSPLUS,\n            common.NamedInt(113, \"KEY 113\"): special_keys.COLORSPLUS,\n            common.NamedInt(114, \"KEY 114\"): special_keys.COLORSPLUS,\n        },\n        fake_hidpp.Response(\"00000606000000000000000000000000\", 0x0400, \"0000\"),  # first group of keys\n        fake_hidpp.Response(\"00000600000000000000000000000000\", 0x0400, \"0001\"),  # second group of keys\n        fake_hidpp.Response(\"00000000000000000000000000000000\", 0x0400, \"0002\"),  # last group of keys\n        fake_hidpp.Response(\"01FF0000\", 0x0410, \"01FF0000\"),  # write one value\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n        fake_hidpp.Response(\"02FF0000\", 0x0410, \"02FF0000\"),  # write one value\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n        fake_hidpp.Response(\"09FF0000\", 0x0410, \"09FF0000\"),  # write one value\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n        fake_hidpp.Response(\"0AFF0000\", 0x0410, \"0AFF0000\"),  # write one value\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n        fake_hidpp.Response(\"7100FF00\", 0x0410, \"7100FF00\"),  # write one value\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n        fake_hidpp.Response(\"72FF0000\", 0x0410, \"72FF0000\"),  # write one value\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n        fake_hidpp.Response(\"FF00000102090A72\", 0x460, \"FF00000102090A72\"),  # write one value for five keys\n        fake_hidpp.Response(\"7100FF00\", 0x0410, \"7100FF00\"),  # write one value\n        fake_hidpp.Response(\"00\", 0x0470, \"00\"),  # finish\n    ),\n    Setup(\n        FeatureTest(settings_templates.ExtendedAdjustableDpi, {0: 256}, {0: 512}, 2, offset=0x9),\n        {common.NamedInt(0, \"X\"): common.NamedInts.list([256, 512])},\n        fake_hidpp.Response(\"000000\", 0x0910, \"00\"),  # no y direction, no lod\n        fake_hidpp.Response(\"0000000100e10002000000\", 0x0920, \"000000\"),\n        fake_hidpp.Response(\"00010000000000000000\", 0x0950),\n        fake_hidpp.Response(\"000100000000\", 0x0960, \"000100000000\"),\n        fake_hidpp.Response(\"000200000000\", 0x0960, \"000200000000\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.ExtendedAdjustableDpi, {0: 0x64, 1: 0xE4}, {0: 0x164}, 2, offset=0x9),\n        {\n            common.NamedInt(0, \"X\"): common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164, 0x01C4]),\n            common.NamedInt(1, \"Y\"): common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164]),\n        },\n        fake_hidpp.Response(\"000001\", 0x0910, \"00\"),  # supports y direction, no lod\n        fake_hidpp.Response(\"0000000064E0100084E02000C4E02000\", 0x0920, \"000000\"),\n        fake_hidpp.Response(\"000001E4E0400124E0400164E06001C4\", 0x0920, \"000001\"),\n        fake_hidpp.Response(\"00000000000000000000000000000000\", 0x0920, \"000002\"),\n        fake_hidpp.Response(\"0000000064E0100084E02000C4E02000\", 0x0920, \"000100\"),\n        fake_hidpp.Response(\"000001E4E0400124E040016400000000\", 0x0920, \"000101\"),\n        fake_hidpp.Response(\"000064007400E4007400\", 0x0950),\n        fake_hidpp.Response(\"00006400E400\", 0x0960, \"00006400E400\"),\n        fake_hidpp.Response(\"00016400E400\", 0x0960, \"00016400E400\"),\n    ),\n    Setup(\n        FeatureTest(settings_templates.ExtendedAdjustableDpi, {0: 0x64, 1: 0xE4, 2: 1}, {1: 0x164}, 2, offset=0x9),\n        {\n            common.NamedInt(0, \"X\"): common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164, 0x01C4]),\n            common.NamedInt(1, \"Y\"): common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164]),\n            common.NamedInt(2, \"LOD\"): common.NamedInts(LOW=0, MEDIUM=1, HIGH=2),\n        },\n        fake_hidpp.Response(\"000003\", 0x0910, \"00\"),  # supports y direction and lod\n        fake_hidpp.Response(\"0000000064E0100084E02000C4E02000\", 0x0920, \"000000\"),\n        fake_hidpp.Response(\"000001E4E0400124E0400164E06001C4\", 0x0920, \"000001\"),\n        fake_hidpp.Response(\"00000000000000000000000000000000\", 0x0920, \"000002\"),\n        fake_hidpp.Response(\"0000000064E0100084E02000C4E02000\", 0x0920, \"000100\"),\n        fake_hidpp.Response(\"000001E4E0400124E040016400000000\", 0x0920, \"000101\"),\n        fake_hidpp.Response(\"000064007400E4007401\", 0x0950),\n        fake_hidpp.Response(\"00006400E401\", 0x0960, \"00006400E401\"),\n        fake_hidpp.Response(\"000064016401\", 0x0960, \"000064016401\"),\n    ),\n]\n\n\n@pytest.mark.parametrize(\"test\", key_tests)\ndef test_key_template(test, mocker):\n    tst = test.test\n    device = fake_hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version)\n    spy_request = mocker.spy(device, \"request\")\n\n    print(\"FEATURE\", tst.sclass.feature)\n    setting = settings_templates.check_feature(device, tst.sclass)\n    assert setting is not None\n    if isinstance(setting, list):\n        setting = setting[0]\n    if isinstance(test.choices, list):\n        assert setting._validator.min_value == test.choices[0]\n        assert setting._validator.max_value == test.choices[1]\n    elif test.choices is not None:\n        assert setting.choices == test.choices\n\n    value = setting.read(cached=False)\n    assert value == tst.initial_value\n\n    write_value = setting.write(value)\n    assert write_value == tst.initial_value\n\n    for key, val in tst.write_value.items():\n        write_value = setting.write_key_value(key, val)\n        assert write_value == val\n        value[key] = val\n\n    if tst.rewrite:\n        write_value = setting.write(value)\n\n    fake_hidpp.match_requests(tst.matched_calls, test.responses, spy_request.call_args_list)\n\n\n@pytest.mark.parametrize(\n    \"responses, currentSpeed, newSpeed\",\n    [\n        (fake_hidpp.responses_speedchange, 100, 200),\n        (fake_hidpp.responses_speedchange, None, 250),\n    ],\n)\ndef test_SpeedChange_action(responses, currentSpeed, newSpeed, mocker):\n    device = fake_hidpp.Device(responses=responses, feature=hidpp20_constants.SupportedFeature.POINTER_SPEED)\n    spy_setting_callback = mocker.spy(device, \"setting_callback\")\n    settings_templates.check_feature_settings(device, device.settings)  # need to set up all the settings\n    device.persister = {\"pointer_speed\": currentSpeed, \"_speed-change\": newSpeed}\n    speed_setting = next(filter(lambda s: s.name == \"speed-change\", device.settings), None)\n    pointer_setting = next(filter(lambda s: s.name == \"pointer_speed\", device.settings), None)\n\n    speed_setting.write(237)\n    speed_setting._rw.press_action()\n\n    if newSpeed is not None and speed_setting is not None:\n        spy_setting_callback.assert_any_call(device, type(pointer_setting), [newSpeed])\n    assert device.persister[\"_speed-change\"] == currentSpeed\n    assert device.persister[\"pointer_speed\"] == newSpeed\n\n\n@pytest.mark.parametrize(\"test\", simple_tests + key_tests)\ndef test_check_feature_settings(test, mocker):\n    tst = test.test\n    device = fake_hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version)\n\n    already_known = []\n    setting = settings_templates.check_feature_settings(device, already_known)\n\n    assert setting is True\n    assert already_known\n\n\n@pytest.mark.parametrize(\n    \"test\",\n    [\n        Setup(\n            FeatureTest(settings_templates.K375sFnSwap, False, True, offset=0x06),\n            fake_hidpp.Response(\"FF0001\", 0x0600, \"FF\"),\n            fake_hidpp.Response(\"FF0101\", 0x0610, \"FF01\"),\n        )\n    ],\n)\ndef test_check_feature_setting(test, mocker):\n    tst = test.test\n    device = fake_hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version)\n\n    setting = settings_templates.check_feature_setting(device, tst.sclass.name)\n\n    assert setting\n"
  },
  {
    "path": "tests/logitech_receiver/test_settings_validator.py",
    "content": "import pytest\n\nfrom logitech_receiver import settings_validator\n\n\n@pytest.mark.parametrize(\n    \"current, new, expected\",\n    [\n        (False, \"toggle\", True),\n        (True, \"~\", False),\n        (\"don't care\", True, True),\n        (\"don't care\", \"true\", True),\n        (\"don't care\", \"false\", False),\n        (\"don't care\", \"no\", False),\n        (\"don't care\", \"off\", False),\n        (\"don't care\", \"True\", True),\n        (\"don't care\", \"yes\", True),\n        (\"don't care\", \"on\", True),\n        (\"anything\", \"anything\", None),\n    ],\n)\ndef test_bool_or_toggle(current, new, expected):\n    result = settings_validator.bool_or_toggle(current=current, new=new)\n\n    assert result == expected\n"
  },
  {
    "path": "tests/solaar/test_gtk.py",
    "content": "from solaar.gtk import create_parser\n\n\ndef test_arg_parse():\n    parser = create_parser()\n    res = parser.parse_args([])\n\n    assert res.debug == 0\n    assert res.hidraw_path is None\n    assert res.restart_on_wake_up is False\n    assert res.window is None\n    assert res.battery_icons is None\n    assert res.tray_icon_size is None\n\n\ndef test_arg_parse_debug():\n    parser = create_parser()\n    res = parser.parse_args([\"--debug\"])\n\n    assert res.debug == 1\n\n\ndef test_arg_parse_version():\n    parser = create_parser()\n    res = parser.parse_args([\"version\"])\n\n    assert res\n"
  },
  {
    "path": "tests/solaar/ui/test_about_dialog.py",
    "content": "from solaar.ui.about import about\nfrom solaar.ui.about.model import AboutModel\n\n\ndef test_about_model():\n    expected_name = \"Daniel Pavel\"\n    model = AboutModel()\n\n    authors = model.get_authors()\n\n    assert expected_name in authors[0]\n\n\ndef test_about_dialog(mocker):\n    view_mock = mocker.Mock()\n\n    about.show(view=view_mock)\n\n    assert view_mock.init_ui.call_count == 1\n    assert view_mock.update_version_info.call_count == 1\n    assert view_mock.update_description.call_count == 1\n    assert view_mock.update_authors.call_count == 1\n    assert view_mock.update_credits.call_count == 1\n    assert view_mock.update_copyright.call_count == 1\n    assert view_mock.update_translators.call_count == 1\n    assert view_mock.update_website.call_count == 1\n    assert view_mock.show.call_count == 1\n"
  },
  {
    "path": "tests/solaar/ui/test_common.py",
    "content": "from unittest import mock\nfrom unittest.mock import PropertyMock\n\nimport pytest\n\nfrom solaar.ui import common\n\n\n@pytest.mark.parametrize(\n    \"reason, expected_in_title, expected_in_text\",\n    [\n        (\n            common.ErrorReason.PERMISSIONS,\n            \"Permissions error\",\n            \"not have permission to open\",\n        ),\n        (common.ErrorReason.NO_DEVICE, \"connect to device error\", \"error connecting\"),\n        (common.ErrorReason.UNPAIR, \"Unpairing failed\", \"receiver returned an error\"),\n    ],\n)\ndef test_create_error_text(reason, expected_in_title, expected_in_text):\n    obj = mock.Mock()\n    obj.name = PropertyMock(return_value=\"test\")\n\n    title, text = common._create_error_text(reason, obj)\n\n    assert expected_in_title in title\n    assert expected_in_text in text\n"
  },
  {
    "path": "tests/solaar/ui/test_desktop_notifications.py",
    "content": "from unittest import mock\n\nfrom solaar.ui import desktop_notifications\n\n# depends on external environment, so make some tests dependent on availability\n\n\ndef test_init():\n    result = desktop_notifications.init()\n\n    assert result == desktop_notifications.available\n\n\ndef test_uninit():\n    assert desktop_notifications.uninit() is None\n\n\ndef test_alert():\n    reason = \"unknown\"\n    assert desktop_notifications.alert(reason) is None\n\n\nclass MockDevice(mock.Mock):\n    name = \"MockDevice\"\n\n    def close():\n        return True\n\n\ndef test_show():\n    dev = MockDevice()\n    reason = \"unknown\"\n    available = desktop_notifications.init()\n\n    result = desktop_notifications.show(dev, reason)\n    if available:\n        assert result is not None\n    else:\n        assert result is None\n"
  },
  {
    "path": "tests/solaar/ui/test_i18n.py",
    "content": "import locale\nimport os\nimport platform\n\nimport pytest\n\nfrom solaar import i18n\n\n\n@pytest.fixture\ndef set_locale_de():\n    backup_lang = os.environ.get(\"LC_ALL\", \"\")\n    try:\n        yield\n    finally:\n        os.environ[\"LC_ALL\"] = backup_lang\n        i18n.set_locale_to_system_default()\n\n\n@pytest.mark.skipif(platform.system() == \"Linux\", reason=\"Adapt test for Linux\")\ndef test_set_locale_to_system_default(set_locale_de):\n    os.environ[\"LC_ALL\"] = \"de_DE.UTF-8\"\n    i18n.set_locale_to_system_default()\n\n    language, encoding = locale.getlocale()\n\n    assert language == \"de_DE\"\n    assert encoding == \"UTF-8\"\n"
  },
  {
    "path": "tests/solaar/ui/test_pair_window.py",
    "content": "from dataclasses import dataclass\nfrom dataclasses import field\nfrom typing import Any\nfrom typing import List\nfrom typing import Optional\n\nimport gi\nimport pytest\n\nfrom logitech_receiver import receiver\nfrom solaar.ui import pair_window\n\ngi.require_version(\"Gtk\", \"3.0\")\nfrom gi.repository import Gtk  # NOQA: E402\n\ngtk_init = Gtk.init_check()[0]\n\n\n@dataclass\nclass Device:\n    name: str = \"test device\"\n    kind: str = \"test kind\"\n\n\n@dataclass\nclass Receiver:\n    name: str\n    receiver_kind: str\n    _set_lock: bool = True\n    pairing: receiver.Pairing = field(default_factory=receiver.Pairing)\n    pairable: bool = True\n    _remaining_pairings: Optional[int] = None\n\n    def reset_pairing(self):\n        self.receiver = receiver.Pairing()\n\n    def remaining_pairings(self, cache=True):\n        return self._remaining_pairings\n\n    def set_lock(self, value=False, timeout=0):\n        self.pairing.lock_open = self._set_lock\n        return self._set_lock\n\n    def discover(self, cancel=False, timeout=30):\n        self.pairing.discovering = self._set_lock\n        return self._set_lock\n\n    def pair_device(self, pair=True, slot=0, address=b\"\\0\\0\\0\\0\\0\\0\", authentication=0x00, entropy=20, force=False):\n        print(\"PD\", self.pairable)\n        return self.pairable\n\n\n@dataclass\nclass Assistant:\n    drawable: bool = True\n    pages: List[Any] = field(default_factory=list)\n\n    def is_drawable(self):\n        return self.drawable\n\n    def next_page(self):\n        return True\n\n    def set_page_complete(self, page, b):\n        return True\n\n    def commit(self):\n        return True\n\n    def append_page(self, page):\n        self.pages.append(page)\n\n    def remove_page(self, page):\n        return True\n\n    def set_page_type(self, page, type):\n        return True\n\n    def destroy(self):\n        pass\n\n\n@pytest.mark.skipif(not gtk_init, reason=\"requires Gtk\")\n@pytest.mark.parametrize(\n    \"receiver, lock_open, discovering, page_type\",\n    [\n        (Receiver(\"unifying\", \"unifying\", True), True, False, Gtk.AssistantPageType.PROGRESS),\n        (Receiver(\"unifying\", \"unifying\", False), False, False, Gtk.AssistantPageType.SUMMARY),\n        (Receiver(\"nano\", \"nano\", True, _remaining_pairings=5), True, False, Gtk.AssistantPageType.PROGRESS),\n        (Receiver(\"nano\", \"nano\", False), False, False, Gtk.AssistantPageType.SUMMARY),\n        (Receiver(\"bolt\", \"bolt\", True), False, True, Gtk.AssistantPageType.PROGRESS),\n        (Receiver(\"bolt\", \"bolt\", False), False, False, Gtk.AssistantPageType.SUMMARY),\n    ],\n)\ndef test_create(receiver, lock_open, discovering, page_type):\n    assistant = pair_window.create(receiver)\n\n    assert assistant is not None\n    assert assistant.get_page_type(assistant.get_nth_page(0)) == page_type\n\n    assert receiver.pairing.lock_open == lock_open\n    assert receiver.pairing.discovering == discovering\n\n\n@pytest.mark.parametrize(\n    \"receiver, expected_result, expected_error\",\n    [\n        (Receiver(\"unifying\", \"unifying\", True), True, False),\n        (Receiver(\"unifying\", \"unifying\", False), False, True),\n        (Receiver(\"bolt\", \"bolt\", True), True, False),\n        (Receiver(\"bolt\", \"bolt\", False), False, True),\n    ],\n)\ndef test_prepare(receiver, expected_result, expected_error):\n    result = pair_window.prepare(receiver)\n\n    assert result == expected_result\n    assert bool(receiver.pairing.error) == expected_error\n\n\n@pytest.mark.parametrize(\"assistant, expected_result\", [(Assistant(True), True), (Assistant(False), False)])\ndef test_check_lock_state_drawable(assistant, expected_result):\n    r = Receiver(\"succeed\", \"unifying\", True, receiver.Pairing(lock_open=True))\n\n    result = pair_window.check_lock_state(assistant, r, 2)\n\n    assert result == expected_result\n\n\n@pytest.mark.skipif(not gtk_init, reason=\"requires Gtk\")\n@pytest.mark.parametrize(\n    \"receiver, count, expected_result\",\n    [\n        (Receiver(\"fail\", \"unifying\", False, receiver.Pairing(lock_open=False)), 2, False),\n        (Receiver(\"succeed\", \"unifying\", True, receiver.Pairing(lock_open=True)), 1, True),\n        (Receiver(\"error\", \"unifying\", True, receiver.Pairing(error=\"error\")), 0, False),\n        (Receiver(\"new device\", \"unifying\", True, receiver.Pairing(new_device=Device())), 2, False),\n        (Receiver(\"closed\", \"unifying\", True, receiver.Pairing()), 2, False),\n        (Receiver(\"closed\", \"unifying\", True, receiver.Pairing()), 1, False),\n        (Receiver(\"closed\", \"unifying\", True, receiver.Pairing()), 0, False),\n        (Receiver(\"fail bolt\", \"bolt\", False), 1, False),\n        (Receiver(\"succeed bolt\", \"bolt\", True, receiver.Pairing(lock_open=True)), 0, True),\n        (Receiver(\"error bolt\", \"bolt\", True, receiver.Pairing(error=\"error\")), 2, False),\n        (Receiver(\"new device\", \"bolt\", True, receiver.Pairing(lock_open=True, new_device=Device())), 1, False),\n        (Receiver(\"discovering\", \"bolt\", True, receiver.Pairing(lock_open=True)), 1, True),\n        (Receiver(\"closed\", \"bolt\", True, receiver.Pairing()), 2, False),\n        (Receiver(\"closed\", \"bolt\", True, receiver.Pairing()), 1, False),\n        (Receiver(\"closed\", \"bolt\", True, receiver.Pairing()), 0, False),\n        (\n            Receiver(\n                \"pass1\",\n                \"bolt\",\n                True,\n                receiver.Pairing(lock_open=True, device_passkey=50, device_authentication=0x01),\n            ),\n            0,\n            True,\n        ),\n        (\n            Receiver(\n                \"pass2\",\n                \"bolt\",\n                True,\n                receiver.Pairing(lock_open=True, device_passkey=50, device_authentication=0x02),\n            ),\n            0,\n            True,\n        ),\n        (\n            Receiver(\n                \"adt\",\n                \"bolt\",\n                True,\n                receiver.Pairing(discovering=True, device_address=2, device_name=5),\n                pairable=True,\n            ),\n            2,\n            True,\n        ),\n        (\n            Receiver(\n                \"adf\",\n                \"bolt\",\n                True,\n                receiver.Pairing(discovering=True, device_address=2, device_name=5),\n                pairable=False,\n            ),\n            2,\n            False,\n        ),\n        (Receiver(\"add fail\", \"bolt\", False, receiver.Pairing(device_address=2, device_passkey=5)), 2, False),\n    ],\n)\ndef test_check_lock_state(receiver, count, expected_result):\n    assistant = Assistant(True)\n\n    check_state = pair_window._check_lock_state(assistant, receiver, count)\n\n    assert check_state == expected_result\n\n\n@pytest.mark.parametrize(\n    \"receiver, pair_device, set_lock, discover, error\",\n    [\n        (\n            Receiver(\"unifying\", \"unifying\", pairing=receiver.Pairing(lock_open=False, error=\"error\")),\n            0,\n            0,\n            0,\n            None,\n        ),\n        (\n            Receiver(\"unifying\", \"unifying\", pairing=receiver.Pairing(lock_open=True, error=\"error\")),\n            0,\n            1,\n            0,\n            \"error\",\n        ),\n        (Receiver(\"bolt\", \"bolt\", pairing=receiver.Pairing(lock_open=False, error=\"error\")), 0, 0, 0, None),\n        (Receiver(\"bolt\", \"bolt\", pairing=receiver.Pairing(lock_open=True, error=\"error\")), 1, 0, 0, \"error\"),\n        (Receiver(\"bolt\", \"bolt\", pairing=receiver.Pairing(discovering=True, error=\"error\")), 0, 0, 1, \"error\"),\n    ],\n)\ndef test_finish(receiver, pair_device, set_lock, discover, error, mocker):\n    spy_pair_device = mocker.spy(receiver, \"pair_device\")\n    spy_set_lock = mocker.spy(receiver, \"set_lock\")\n    spy_discover = mocker.spy(receiver, \"discover\")\n    assistant = Assistant(True)\n\n    pair_window._finish(assistant, receiver)\n\n    assert spy_pair_device.call_count == pair_device\n    assert spy_set_lock.call_count == set_lock\n    assert spy_discover.call_count == discover\n    assert receiver.pairing.error == error\n\n\n@pytest.mark.skipif(not gtk_init, reason=\"requires Gtk\")\n@pytest.mark.parametrize(\"error\", [\"timeout\", \"device not supported\", \"too many devices\"])\ndef test_create_failure_page(error, mocker):\n    spy_create = mocker.spy(pair_window, \"_create_page\")\n\n    pair_window._pairing_failed(Assistant(True), Receiver(\"nano\", \"nano\"), error)\n\n    assert spy_create.call_count == 1\n"
  },
  {
    "path": "tests/solaar/ui/test_probe.py",
    "content": "from unittest import mock\n\nfrom logitech_receiver.hidpp10_constants import ErrorCode\nfrom logitech_receiver.hidpp10_constants import Registers\nfrom solaar.cli.probe import run\n\n\n# Mock receiver class\nclass MockReceiver:\n    handle = 1\n    isDevice = False\n\n    def read_register(self, register, *args):\n        return 0 if register == Registers.RECEIVER_INFO else b\"\\x01\\x03\"\n\n\ndef test_run_register_errors():\n    mock_args = mock.Mock()\n    mock_args.receiver = False\n\n    mock_receiver = MockReceiver()\n\n    # Define expected addresses to be called in order\n    expected_addresses = []\n\n    for reg in range(0, 0xFF):\n        expected_addresses.append((0x8100 | reg, 0))  # First short call, returns invalid_value (continue)\n        expected_addresses.append((0x8100 | reg, 1))  # Second short call, returns invalid_address (stop here)\n\n        expected_addresses.append((0x8100 | (0x200 + reg), 0))  # First long call, returns invalid_value (continue)\n        expected_addresses.append((0x8100 | (0x200 + reg), 1))  # Second long call, returns invalid_address (stop here)\n\n    # To record the actual addresses called\n    called_addresses = []\n\n    def mock_base_request(handle, devnumber, reg, sub, return_error=False):\n        called_addresses.append((reg, sub))\n        if sub == 0:\n            return ErrorCode.INVALID_VALUE\n        elif sub == 1:\n            return ErrorCode.INVALID_ADDRESS\n        return b\"\\x01\\x02\"\n\n    with mock.patch(\"logitech_receiver.base.request\", side_effect=mock_base_request), mock.patch(\n        \"solaar.cli.probe._print_receiver\", return_value=None\n    ):\n        # Call the run function with mocked receivers and args (passing real find_receiver function)\n        run([mock_receiver], mock_args, None, None)\n\n        # Evaluate that the addresses called match the expected addresses\n        assert (\n            called_addresses == expected_addresses\n        ), f\"Called addresses {called_addresses} do not match expected {expected_addresses}\"\n"
  },
  {
    "path": "tests/test_keysyms/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_keysyms/test_keysymdef.py",
    "content": "from keysyms import keysymdef\n\n\ndef test_keysymdef():\n    key_mapping = keysymdef.key_symbols\n\n    assert key_mapping[\"0\"] == 48\n    assert key_mapping[\"A\"] == 65\n    assert key_mapping[\"a\"] == 97\n"
  },
  {
    "path": "tools/clean.sh",
    "content": "#!/usr/bin/env sh\n\ncd \"$(dirname \"$0\")/..\"\n\nfind . -type f -name '*.py[co]' -delete\nfind . -type d -name '__pycache__' -delete\n\nrm --force po/*~\nrm --force --recursive share/locale/\n"
  },
  {
    "path": "tools/create-macos-app.sh",
    "content": "#!/usr/bin/env bash\n# Helper to build a minimal macOS .app wrapper for Solaar.\nset -euo pipefail\n\nAPP_ROOT=${1:-/Applications/Solaar.app}\nSOLAAR_PATH=${SOLAAR_PATH:-solaar}\nSOLAAR_RESOLVED_PATH=$(command -v \"${SOLAAR_PATH}\" 2>/dev/null || echo \"\")\nif [ -z \"${SOLAAR_RESOLVED_PATH}\" ]; then\n    echo \"Error: '${SOLAAR_PATH}' not found\" >&2\n    exit 1\nfi\nICON_SOURCE=${ICON_SOURCE:-share/solaar/icons/solaar.svg}\n\ncase \"${APP_ROOT}\" in\n    \"\"|\"/\"|\".\")\n        echo \"Error: Refusing to create app bundle at unsafe location: \\\"${APP_ROOT}\\\"\" >&2\n        exit 1\n        ;;\nesac\n\necho \"Creating Solaar app bundle at ${APP_ROOT}\"\nrm -rf \"${APP_ROOT}\"\n\nAPP_CONTENTS=\"${APP_ROOT}/Contents\"\nMACOS_DIR=\"${APP_CONTENTS}/MacOS\"\nRESOURCES_DIR=\"${APP_CONTENTS}/Resources\"\n\nmkdir -p \"${MACOS_DIR}\" \"${RESOURCES_DIR}\"\n\nWRAPPER=\"${MACOS_DIR}/solaar-wrapper\"\ncat > \"${WRAPPER}\" <<EOF\n#!/usr/bin/env bash\nset -euo pipefail\n\n# When launched via 'Solaar.app', macOS applies .app bundle restrictions\n# that may prevent GTK from creating a tray icon properly.\n# Workaround: Launch solaar in a detached background process\n\n# NOTE: macOS Python always uses Python.app which shows a Dock icon\n# LSUIElement=true in Info.plist would have hidden it, but Python.app has its own Info.plist\n# that overrides ours. This is a limitation of Python on macOS.\n\nif [[ \"\\${SOLAAR_RELAUNCHED:-}\" != \"1\" ]]; then\n    # First invocation from .app bundle - relaunch detached\n    export SOLAAR_RELAUNCHED=1\n    nohup \"\\$0\" \"\\$@\" >/dev/null 2>&1 &\n    exit 0\nfi\n\n# Second invocation - now detached, exec solaar normally\nexec \"${SOLAAR_RESOLVED_PATH}\" \"\\$@\"\nEOF\nchmod +x \"${WRAPPER}\"\n\nHAVE_ICON=0\nif command -v sips >/dev/null 2>&1 && command -v iconutil >/dev/null 2>&1 && [[ -f \"${ICON_SOURCE}\" ]]; then\n    TMP_DIR=$(mktemp -d /tmp/solaar-icon.XXXXXX)\n    TMP_ICONSET=\"${TMP_DIR}/solaar.iconset\"\n    mkdir -p \"${TMP_ICONSET}\"\n    trap 'rm -rf \"${TMP_DIR}\"' EXIT\n    for SIZE in 16 32 64 128 256 512; do\n        sips -s format png -z \"${SIZE}\" \"${SIZE}\" \"${ICON_SOURCE}\" --out \"${TMP_ICONSET}/icon_${SIZE}x${SIZE}.png\" >/dev/null\n        DOUBLE=$((SIZE * 2))\n        sips -s format png -z \"${DOUBLE}\" \"${DOUBLE}\" \"${ICON_SOURCE}\" --out \"${TMP_ICONSET}/icon_${SIZE}x${SIZE}@2x.png\" >/dev/null\n    done\n    if iconutil -c icns \"${TMP_ICONSET}\" -o \"${RESOURCES_DIR}/solaar.icns\" >/dev/null 2>&1; then\n        HAVE_ICON=1\n        echo \"Added icon from ${ICON_SOURCE}\"\n    else\n        echo \"Warning: Failed to create solaar.icns – continuing without custom icon\" >&2\n    fi\n    rm -rf \"${TMP_DIR}\"\n    trap - EXIT\nelse\n    echo \"Skipping icon generation (requires sips, iconutil, and ${ICON_SOURCE})\"\nfi\n\n{\ncat <<EOF\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n    <key>CFBundleExecutable</key>\n    <string>solaar-wrapper</string>\n    <key>CFBundleIdentifier</key>\n    <string>io.github.pwr-solaar.solaar</string>\n    <key>CFBundleName</key>\n    <string>Solaar</string>\n    <key>CFBundlePackageType</key>\n    <string>APPL</string>\n    <key>CFBundleShortVersionString</key>\n    <string>1.0</string>\n    <key>LSMinimumSystemVersion</key>\n    <string>11.0</string>\n    <key>NSInputMonitoringUsageDescription</key>\n    <string>Solaar needs to access input devices to configure and monitor your Logitech keyboards, mice, and other peripherals.</string>\n    <key>LSUIElement</key>\n    <false/>\nEOF\nif [[ ${HAVE_ICON} -eq 1 ]]; then\ncat <<'EOF'\n    <key>CFBundleIconFile</key>\n    <string>solaar.icns</string>\nEOF\nfi\ncat <<'EOF'\n</dict>\n</plist>\nEOF\n} > \"${APP_CONTENTS}/Info.plist\"\n\necho \"Solaar app bundle created at ${APP_ROOT}\"\necho \"\"\necho \"To install the LaunchAgent for automatic startup and keep-alive execute:\"\necho \"  bash tools/create-macos-launchagent.sh\"\n"
  },
  {
    "path": "tools/create-macos-launchagent.sh",
    "content": "#!/usr/bin/env bash\n# Helper to install a LaunchAgent for Solaar to keep it running in the background.\nset -euo pipefail\n\nSOLAAR_PATH=${SOLAAR_PATH:-solaar}\nSOLAAR_RESOLVED_PATH=$(command -v \"${SOLAAR_PATH}\" 2>/dev/null || echo \"\")\nif [ -z \"${SOLAAR_RESOLVED_PATH}\" ]; then\n    echo \"Error: '${SOLAAR_PATH}' not found\" >&2\n    exit 1\nfi\n\nLAUNCH_AGENT_DIR=\"${HOME}/Library/LaunchAgents\"\nLAUNCH_AGENT_PLIST=\"${LAUNCH_AGENT_DIR}/io.github.pwr-solaar.solaar.plist\"\n\nmkdir -p \"${LAUNCH_AGENT_DIR}\"\n\necho \"Creating LaunchAgent to keep Solaar running...\"\n\n# Unload if already loaded (suppress errors)\nlaunchctl unload \"${LAUNCH_AGENT_PLIST}\" 2>/dev/null || true\n\ncat > \"${LAUNCH_AGENT_PLIST}\" <<EOF\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n    <key>Label</key>\n    <string>io.github.pwr-solaar.solaar</string>\n    <key>ProgramArguments</key>\n    <array>\n        <string>${SOLAAR_RESOLVED_PATH}</string>\n        <string>--window=hide</string>\n    </array>\n    <key>RunAtLoad</key>\n    <true/>\n    <key>KeepAlive</key>\n    <true/>\n    <key>StandardOutPath</key>\n    <string>${HOME}/Library/Logs/solaar.log</string>\n    <key>StandardErrorPath</key>\n    <string>${HOME}/Library/Logs/solaar.error.log</string>\n    <key>ProcessType</key>\n    <string>Background</string>\n</dict>\n</plist>\nEOF\n\nlaunchctl load \"${LAUNCH_AGENT_PLIST}\"\n\necho \"LaunchAgent created at ${LAUNCH_AGENT_PLIST}\"\necho \"\"\necho \"To disable automatic startup:\"\necho \"  launchctl unload \\\"${LAUNCH_AGENT_PLIST}\\\"\"\necho \"\"\necho \"To re-enable automatic startup:\"\necho \"  launchctl load \\\"${LAUNCH_AGENT_PLIST}\\\"\"\necho \"\"\necho \"To start Solaar:\"\necho \"  launchctl start io.github.pwr-solaar.solaar\"\necho \"\"\necho \"To stop Solaar:\"\necho \"  launchctl stop io.github.pwr-solaar.solaar\"\necho \"\"\necho \"Logs will be written to:\"\necho \"  ${HOME}/Library/Logs/solaar.log\"\necho \"  ${HOME}/Library/Logs/solaar.error.log\"\n"
  },
  {
    "path": "tools/hidconsole",
    "content": "#!/usr/bin/env python3\n# -*- python-mode -*-\n\"\"\"Takes care of starting the main function.\"\"\"\n\nfrom __future__ import absolute_import\n\n\ndef init_paths():\n    \"\"\"Make the app work in the source tree.\"\"\"\n    import os.path as _path\n    import sys\n\n    src_lib = _path.normpath(_path.join(_path.realpath(sys.path[0]), \"..\", \"lib\"))\n    init_py = _path.join(src_lib, \"hidapi\", \"__init__.py\")\n    if _path.exists(init_py):\n        sys.path[0] = src_lib\n\n\nif __name__ == \"__main__\":\n    init_paths()\n    from hidapi import hidconsole\n\n    hidconsole.main()\n"
  },
  {
    "path": "tools/install-rhel.sh",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_NAME=\"$(basename \"$0\")\"\nLOG_DIR=\"${XDG_STATE_HOME:-$HOME/.local/state}/solaar\"\nLOG_FILE=\"$LOG_DIR/rhel-install-$(date +%Y%m%d-%H%M%S).log\"\n\nmkdir -p \"$LOG_DIR\"\nexec > >(tee -a \"$LOG_FILE\") 2>&1\n\nsay() {\n    printf '\\n[%s] %s\\n' \"$SCRIPT_NAME\" \"$*\"\n}\n\nwarn() {\n    printf '\\n[%s] WARNING: %s\\n' \"$SCRIPT_NAME\" \"$*\"\n}\n\nfail() {\n    printf '\\n[%s] ERROR: %s\\n' \"$SCRIPT_NAME\" \"$*\"\n    exit 1\n}\n\nask_yes_no() {\n    local prompt=\"$1\"\n    local default=\"${2:-y}\"\n    local answer\n\n    while true; do\n        if [[ \"$default\" == \"y\" ]]; then\n            read -r -p \"$prompt [Y/n]: \" answer || true\n            answer=\"${answer:-y}\"\n        else\n            read -r -p \"$prompt [y/N]: \" answer || true\n            answer=\"${answer:-n}\"\n        fi\n\n        case \"${answer,,}\" in\n            y|yes) return 0 ;;\n            n|no) return 1 ;;\n            *) echo \"Please answer y or n.\" ;;\n        esac\n    done\n}\n\nask_value() {\n    local prompt=\"$1\"\n    local default=\"$2\"\n    local answer\n\n    read -r -p \"$prompt [$default]: \" answer || true\n    printf '%s\\n' \"${answer:-$default}\"\n}\n\nrun_cmd() {\n    say \"Running: $*\"\n    \"$@\"\n}\n\nrun_sudo() {\n    say \"Running with sudo: $*\"\n    sudo \"$@\"\n}\n\nif [[ \"${EUID}\" -eq 0 ]]; then\n    fail \"Do not run as root. Run as your normal user; this script uses sudo when needed.\"\nfi\n\nsay \"Log file: $LOG_FILE\"\nsay \"This installer follows RHEL.md for RHEL 10-like systems.\"\n\nif ask_yes_no \"Update dnf metadata first?\" y; then\n    run_sudo dnf makecache\nfi\n\nif ask_yes_no \"Check for Logitech USB receiver with lsusb now?\" y; then\n    if lsusb | grep -i logitech; then\n        say \"Logitech device detected.\"\n    else\n        warn \"No Logitech USB receiver detected via lsusb right now. You can continue anyway.\"\n        ask_yes_no \"Continue without receiver detection?\" y || fail \"Aborted by user.\"\n    fi\nfi\n\nBASE_PACKAGES=(python3 python3-pip git libinput evemu)\nDEV_PACKAGES=(python3-devel gcc pkgconf-pkg-config gtk3 python3-gobject)\n\nsay \"Base packages: ${BASE_PACKAGES[*]}\"\nsay \"Build/runtime packages: ${DEV_PACKAGES[*]}\"\n\nif ask_yes_no \"Install required packages with dnf?\" y; then\n    run_sudo dnf install -y \"${BASE_PACKAGES[@]}\" \"${DEV_PACKAGES[@]}\"\nfi\n\nREPO_PARENT_DEFAULT=\"$HOME/dev-repos\"\nREPO_PARENT=\"$(ask_value \"Repository parent directory\" \"$REPO_PARENT_DEFAULT\")\"\nREPO_URL_DEFAULT=\"https://github.com/pwr-Solaar/Solaar.git\"\nREPO_URL=\"$(ask_value \"Git URL for Solaar\" \"$REPO_URL_DEFAULT\")\"\nREPO_DIR_DEFAULT=\"$REPO_PARENT/Solaar\"\nREPO_DIR=\"$(ask_value \"Local checkout directory\" \"$REPO_DIR_DEFAULT\")\"\n\nrun_cmd mkdir -p \"$REPO_PARENT\"\n\nif [[ -d \"$REPO_DIR/.git\" ]]; then\n    say \"Existing git checkout found at $REPO_DIR\"\n    if ask_yes_no \"Pull latest changes in this repository?\" y; then\n        run_cmd git -C \"$REPO_DIR\" pull --ff-only\n    fi\nelse\n    run_cmd git clone \"$REPO_URL\" \"$REPO_DIR\"\nfi\n\nsay \"Installing Solaar into user site-packages\"\nif ask_yes_no \"Use upgrade mode for pip install?\" n; then\n    run_cmd python3 -m pip install --user --upgrade \"$REPO_DIR\"\nelse\n    run_cmd python3 -m pip install --user \"$REPO_DIR\"\nfi\n\nSOLAAR_BIN=\"$HOME/.local/bin/solaar\"\nif [[ ! -x \"$SOLAAR_BIN\" ]]; then\n    fail \"Expected executable not found: $SOLAAR_BIN\"\nfi\n\nsay \"Installed binary: $SOLAAR_BIN\"\nrun_cmd \"$SOLAAR_BIN\" --help >/dev/null\n\nif ask_yes_no \"Add alias 'solaar=$SOLAAR_BIN' to ~/.bashrc if missing?\" y; then\n    if grep -Fqx \"alias solaar=\\\"$SOLAAR_BIN\\\"\" \"$HOME/.bashrc\" 2>/dev/null; then\n        say \"Alias already exists in ~/.bashrc\"\n    else\n        printf '\\n# Solaar user-local install\\nalias solaar=\"%s\"\\n' \"$SOLAAR_BIN\" >> \"$HOME/.bashrc\"\n        say \"Alias appended to ~/.bashrc\"\n    fi\nfi\n\nif ask_yes_no \"Run 'solaar show' now for validation?\" y; then\n    run_cmd \"$SOLAAR_BIN\" show || warn \"'solaar show' returned a non-zero status.\"\nfi\n\nif ask_yes_no \"Run 'solaar config <device name>' now?\" n; then\n    DEVICE_NAME_DEFAULT=\"M720 Triathlon Multi-Device Mouse\"\n    DEVICE_NAME=\"$(ask_value \"Device name\" \"$DEVICE_NAME_DEFAULT\")\"\n    run_cmd \"$SOLAAR_BIN\" config \"$DEVICE_NAME\" || warn \"'solaar config' returned a non-zero status.\"\nfi\n\nif ask_yes_no \"Run libinput debug-events for a specific /dev/input/eventX device?\" n; then\n    EVENT_NODE=\"$(ask_value \"Input event node\" \"/dev/input/eventX\")\"\n    warn \"This is a live monitor and may run until interrupted (Ctrl+C).\"\n    run_sudo libinput debug-events --device \"$EVENT_NODE\"\nfi\n\nif ask_yes_no \"Run keyd monitor (/usr/local/bin/keyd) if present?\" n; then\n    if [[ -x /usr/local/bin/keyd ]]; then\n        warn \"This is a live monitor and may run until interrupted (Ctrl+C).\"\n        run_sudo /usr/local/bin/keyd monitor\n    else\n        warn \"/usr/local/bin/keyd not found; skipping.\"\n    fi\nfi\n\nsay \"Install workflow completed.\"\nsay \"To use alias in current shell: source ~/.bashrc\"\nsay \"Evidence log saved at: $LOG_FILE\"\n"
  },
  {
    "path": "tools/po-compile.sh",
    "content": "#!/usr/bin/env sh\n\nset -e\n\ncd \"$(readlink -f \"$(dirname \"$0\")/..\")\"\n\nfind \"$PWD/po\" -type f -name '*.po' | \\\nwhile read po_file; do\n\tlanguage=\"$(basename \"$po_file\")\"\n\tlanguage=\"${language%.po}\"\n\ttarget=\"$PWD/share/locale/$language/LC_MESSAGES/solaar.mo\"\n\tmkdir --parents \"$(dirname \"$target\")\"\n\tmsgfmt \\\n\t\t--check \\\n\t\t--output-file=\"$target\" \\\n\t\t\"$po_file\"\ndone\n"
  },
  {
    "path": "tools/po-update.sh",
    "content": "#!/usr/bin/env sh\n\nset -e\n\nif test \"$1\" = \"-h\" -o \"$1\" = \"--help\"; then\n\techo \"Use: $0 [<language>]\"\n\techo \"Run without arguments to update all translation files.\"\n\texit 0\nfi\n\ncd \"$(readlink -f \"$(dirname \"$0\")/..\")\"\n\nVERSION=$(python setup.py --version)\nDOMAIN=$(python setup.py --name)\n\nSOURCE_FILES=$(mktemp --tmpdir $DOMAIN-po-update-XXXXXX)\nfind \"lib\" -name '*.py' >\"$SOURCE_FILES\"\n\nPOT_DIR=\"$PWD/po\"\ntest -d \"$POT_DIR\"\n\nPOT_FILE=\"$POT_DIR/$DOMAIN.pot\"\n\nxgettext \\\n\t--package-name \"$DOMAIN\" \\\n\t--package-version \"$VERSION\" \\\n\t--default-domain=\"$L_NAME\" \\\n\t--language=Python --from-code=UTF-8 --files-from=\"$SOURCE_FILES\" \\\n\t--no-escape --indent --add-location --sort-by-file \\\n\t--add-comments=I18N \\\n\t--output=\"$POT_FILE\"\n\nsed --in-place --expression=\"s/charset=CHARSET/charset=UTF-8/\" \"$POT_FILE\"\n\n\nunfmt() {\n\tlocal SOURCE=\"/usr/share/locale/$LL_CC/LC_MESSAGES/$1.mo\"\n\tif test ! -f \"$SOURCE\"; then\n\t\tSOURCE=\"/usr/share/locale-langpack/$LL_CC/LC_MESSAGES/$1.mo\"\n\tfi\n\tlocal TARGET=\"$(mktemp --tmpdir $1-$LL_CC-XXXXXX.po)\"\n\tmsgunfmt \\\n\t\t--no-escape --indent \\\n\t\t--output-file=\"$TARGET\" \\\n\t\t\"$SOURCE\"\n\techo \"$TARGET\"\n}\n\nupdate_po() {\n\tlocal LL_CC=\"$1\"\n\tlocal PO_FILE=\"$POT_DIR/$LL_CC.po\"\n\n\ttest -r \"$PO_FILE\" || msginit \\\n\t\t\t--no-translator --locale=\"$LL_CC\" \\\n\t\t\t--input=\"$POT_FILE\" \\\n\t\t\t--output-file=\"$PO_FILE\"\n\n\tmsgmerge \\\n\t\t--update --no-fuzzy-matching \\\n\t\t--no-escape --indent --add-location --sort-by-file \\\n\t\t--lang=\"$LL_CC\" \\\n\t\t--compendium=\"$(unfmt gtk30)\" \\\n\t\t--compendium=\"$(unfmt gtk30-properties)\" \\\n\t\t\"$PO_FILE\" \"$POT_FILE\"\n\n\t# sed --in-place --expression=\"s/Language: \\\\\\\\n/Language: $L_NAME\\\\\\\\n/\" \"$PO_FILE\"\n\techo \"Updated $PO_FILE\"\n}\n\nif test \"$1\"; then\n\tupdate_po \"$1\"\nelse\n\tfor l in $(ls -1 \"$POT_DIR\"/??.po); do\n\t\tl=\"$(basename \"$l\")\"\n\t\tupdate_po \"${l%.po}\"\n\tdone\nfi\n"
  },
  {
    "path": "tools/scan-registers.sh",
    "content": "#!/usr/bin/env sh\n\nif test -z \"$1\"; then\n\techo \"Use: $0 <device number 1..6> [<receiver device>]\"\n\texit 2\nfi\n\nHC=\"$(dirname \"$(readlink -f \"$0\")\")/hidconsole\"\nif test \"$1\" = \"FF\" -o \"$1\" = \"ff\"; then\n\tDEVNUMBER=FF\nelse\n\tDEVNUMBER=0$1\nfi\nHIDRAW=$2\n\ndo_req() {\n\t\"$HC\" --hidpp $HIDRAW | grep \"^>> \" | grep -v \"\\[1. .. 8F.. \"\n}\n\nreq00=\"$(mktemp --tmpdir req00-XXXXXX)\"\necho \"10 ${DEVNUMBER} 8100 000000\" | do_req >\"$req00\"\noldflags=$(grep -Po \"^>> \\([0-9. ]*\\) \\[10 ${DEVNUMBER} 8100 \\K[0-9a-f]{6}(?=\\])\" \"$req00\")\nif [ -n \"$oldflags\" ]; then\n\techo \"# Old notification flags: $oldflags\"\n\tcat >\"$req00-flags\" <<-_CHECK_NOTIFICATIONS\n\t\t10 ${DEVNUMBER} 8000 ffffff\n\t\t10 ${DEVNUMBER} 8100 000000\n\t\t10 ${DEVNUMBER} 8000 ${oldflags}\n\t_CHECK_NOTIFICATIONS\n\t# set all possible flags, read the new value, then restore the old value\n\t# this will show all supported notification flags by this device\n\tcat \"$req00-flags\" | do_req | grep \"^>>.* ${DEVNUMBER} 8100 \"\nelse\n\techo \"# Warning: hidconsole API got changed - unrecognized output\"\n\tcat \"$req00\"\nfi\nrm --force \"$req00\" \"$req00-flags\" &\n\necho SHORT REGISTERS\n# read all short registers, skipping 00\nfor n in $(seq 1 255); do\n\tprintf \"10 ${DEVNUMBER} 81%02x 000000\\n\" $n\ndone | do_req\n\necho LONG REGISTERS\n# read all long registers\nfor n in $(seq 0 255); do\n\tprintf \"10 ${DEVNUMBER} 83%02x 000000\\n\" $n\ndone | do_req\n\necho PAIRING INFORMAITON # read all pairing information\nfor n in $(seq 0 255); do\n\tprintf \"10 ${DEVNUMBER} 83B5 %02x0000\\n\" $n\ndone | do_req\n"
  }
]