Showing preview only (3,784K chars total). Download the full file or copy to clipboard to get everything.
Repository: pwr-Solaar/Solaar
Branch: master
Commit: b9e0cf823543
Files: 309
Total size: 3.6 MB
Directory structure:
gitextract_9uiytb4r/
├── .coveragerc
├── .git-blame-ignore-revs
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ ├── checks.yml
│ ├── gh-pages.yml
│ └── tests.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .python-version
├── CHANGELOG.md
├── COPYRIGHT
├── LICENSE.txt
├── MANIFEST.in
├── Makefile
├── README.md
├── RELEASE.md
├── RHEL.md
├── Release_Notes.md
├── bin/
│ └── solaar
├── docs/
│ ├── .gitignore
│ ├── LICENSE.txt
│ ├── README.text
│ ├── capabilities.md
│ ├── debian.md
│ ├── devices/
│ │ ├── 00README.txt
│ │ ├── Bluetooth Multi-Device Keyboard K380 B342.txt
│ │ ├── Bolt Receiver C548.txt
│ │ ├── Candy companion chip 405F.txt
│ │ ├── Couch Mouse M515 4007.txt
│ │ ├── Craft Advanced Keyboard 4066.txt
│ │ ├── Craft Advanced Keyboard B350.txt
│ │ ├── ERGO M575 Trackball 4096.txt
│ │ ├── EX100 Receiver 27 Mhz C517.text
│ │ ├── G Pro Wireless Gaming Mouse 4079.txt
│ │ ├── G213 Prodigy Gaming Keyboard C366.txt
│ │ ├── G304 Lightspeed Wireless Gaming Mouse 4074.txt
│ │ ├── G305 Lightspeed Wireless Gaming Mouse 4074.text
│ │ ├── G502 Gaming Mouse C07D.text
│ │ ├── G502 Lightspeed Wireless Gaming Mouse 407F.txt
│ │ ├── G502 Proteus Spectrum Optical Mouse C332.txt
│ │ ├── G502 SE Hero Gaming Mouse C08B.txt
│ │ ├── G502 X C099.txt
│ │ ├── G502 X PLUS 4099.txt
│ │ ├── G515 LS TKL 40B4.text
│ │ ├── G535 Wireless Gaming Headset 0AC4.txt
│ │ ├── G600 Gaming Mouse C24A.txt
│ │ ├── G604 Wireless Gaming Mouse 4085.txt
│ │ ├── G613 Wireless Mechanical Gaming Keyboard 4065.txt
│ │ ├── G703 Wired-Wireless Gaming Mouse 4070.txt
│ │ ├── G733 Gaming Headset 0AB5.text
│ │ ├── G733 Gaming Headset 0AFE.text
│ │ ├── G815 Mechanical Keyboard C33F.txt
│ │ ├── G903 LIGHTSPEED Wireless Gaming Mouse 4087.txt
│ │ ├── G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard 408E.txt
│ │ ├── G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD 407C.text
│ │ ├── G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD C33E.text
│ │ ├── G915 WIRELESS RGB Mechanical Gaming Keyboard 407E.txt
│ │ ├── G935 Gaming Headset 0A87.txt
│ │ ├── Illuminated Keyboard C318.txt
│ │ ├── Illuminated Living-Room Keyboard K830 4032.txt
│ │ ├── K850 Performance Wireless Keyboard 4062.txt
│ │ ├── K850 Performance Wireless Keyboard B34D.txt
│ │ ├── Keyboard K600 TV 4078.txt
│ │ ├── LIFT For Business B033.txt
│ │ ├── LIFT VERTICAL ERGONOMIC MOUSE B031.txt
│ │ ├── Lightspeed Receiver C539.txt
│ │ ├── Lightspeed Receiver C53A.txt
│ │ ├── Lightspeed Receiver C53D.txt
│ │ ├── Lightspeed Receiver C53F.txt
│ │ ├── Lightspeed Receiver C541.txt
│ │ ├── Lightspeed Receiver C545.txt
│ │ ├── Lightspeed Receiver C547.txt
│ │ ├── Logi Pop Keys B365.txt
│ │ ├── Logitech G933 Gaming Wireless Headset 0A5B.txt
│ │ ├── Logitech PRO X Wireless Gaming Headset 0ABA.txt
│ │ ├── M720 Triathlon Multi-Device Mouse 405E.txt
│ │ ├── M720 Triathlon Multi-Device Mouse B015.txt
│ │ ├── MX Anywhere 3 4090.txt
│ │ ├── MX Anywhere 3 B025.txt
│ │ ├── MX Anywhere 3 for Business B02D.txt
│ │ ├── MX Ergo Multi-Device Trackball 406F.txt
│ │ ├── MX Keys Keyboard 408A.txt
│ │ ├── MX Keys Keyboard B35B.txt
│ │ ├── MX Keys Mini B369.txt
│ │ ├── MX Keys S B378.text
│ │ ├── MX Keys for Business B363.text
│ │ ├── MX Master 3 Wireless Mouse 4082.txt
│ │ ├── MX Master 3 Wireless Mouse B023.txt
│ │ ├── MX Master 3 for Business B028.text
│ │ ├── MX Master 3S B034.txt
│ │ ├── MX Master 4.text
│ │ ├── MX Mechanical B366.txt
│ │ ├── MX Mechanical Mini B367.txt
│ │ ├── MX Vertical Wireless Mouse 407B.txt
│ │ ├── MX Vertical Wireless Mouse B020.txt
│ │ ├── Marathon Mouse M705 101B.txt
│ │ ├── Marathon Mouse M705 406D.txt
│ │ ├── Multi Device Silent Mouse M585-M590 406B.txt
│ │ ├── Nano Receiver C52F.txt
│ │ ├── Nano Receiver C534.txt
│ │ ├── Nano Receiver C535.txt
│ │ ├── Number Pad N545 2006.txt
│ │ ├── PRO X 2 40A9.text
│ │ ├── PRO X Wireless 4093.txt
│ │ ├── Rechargeable Trackpad T651 B00C.txt
│ │ ├── Signature M550.text
│ │ ├── Signature M650 L Mouse B02A.txt
│ │ ├── Unifying Receiver C52B.txt
│ │ ├── Wireless All-in-One Keyboard TK820 4102.txt
│ │ ├── Wireless Illuminated Keyboard K800 2010.txt
│ │ ├── Wireless Illuminated Keyboard K800 new 406E.txt
│ │ ├── Wireless Keyboard 4075.txt
│ │ ├── Wireless Keyboard Dell KB714 4015.txt
│ │ ├── Wireless Keyboard K220 4005.txt
│ │ ├── Wireless Keyboard K230 400D.txt
│ │ ├── Wireless Keyboard K270(unifying) 4003.txt
│ │ ├── Wireless Keyboard K360 4004.txt
│ │ ├── Wireless Keyboard K470 4075.txt
│ │ ├── Wireless Keyboard K520 2011.txt
│ │ ├── Wireless Keyboard MK270 4023.txt
│ │ ├── Wireless Mobile Mouse MX Anywhere 2 4072.txt
│ │ ├── Wireless Mobile Mouse MX Anywhere 2S 406A.txt
│ │ ├── Wireless Mobile Mouse MX Anywhere 2S B01A.txt
│ │ ├── Wireless Mouse 4022.txt
│ │ ├── Wireless Mouse Dell WM514 4029.txt
│ │ ├── Wireless Mouse M185 new 4054.txt
│ │ ├── Wireless Mouse M185,M235,M310 4055.txt
│ │ ├── Wireless Mouse M185.text
│ │ ├── Wireless Mouse M215 2nd Gen 401B.txt
│ │ ├── Wireless Mouse M310 M310t 4031.txt
│ │ ├── Wireless Mouse M325 400A.txt
│ │ ├── Wireless Mouse M345 4017.txt
│ │ ├── Wireless Mouse M510 1025.txt
│ │ ├── Wireless Mouse M510 4051.txt
│ │ ├── Wireless Mouse M525 4013.txt
│ │ ├── Wireless Mouse M560 402D.txt
│ │ ├── Wireless Mouse MX Anywhere 2 404A.txt
│ │ ├── Wireless Mouse MX Master 2S 4069.txt
│ │ ├── Wireless Mouse MX Master 2S B019.txt
│ │ ├── Wireless Mouse MX Master 4041.txt
│ │ ├── Wireless Mouse MX Master 4071.txt
│ │ ├── Wireless Mouse MX Master B012.txt
│ │ ├── Wireless Mouse Pebble M350 4080.txt
│ │ ├── Wireless Multi-Device Keyboard K780 405B.txt
│ │ ├── Wireless Rechargeable Touchpad T650 4101.txt
│ │ ├── Wireless Solar Keyboard K750 4002.txt
│ │ ├── Wireless Touch Keyboard K400 4024.txt
│ │ ├── Wireless Touch Keyboard K400 Plus 404D.txt
│ │ ├── Wireless Trackball M570 1028.txt
│ │ ├── Zone Touch Mouse T400 4026.txt
│ │ ├── anywhere-mx.txt
│ │ ├── mk700.txt
│ │ └── performance-mx.txt
│ ├── devices.md
│ ├── features.md
│ ├── hidpp-documentation.txt
│ ├── i18n.md
│ ├── implementation.md
│ ├── index.md
│ ├── installation.md
│ ├── issues.md
│ ├── rules.md
│ ├── uninstallation.md
│ ├── usage.md
│ └── usb.ids.txt
├── lib/
│ ├── hid_parser/
│ │ ├── __init__.py
│ │ └── data.py
│ ├── hidapi/
│ │ ├── __init__.py
│ │ ├── common.py
│ │ ├── hidapi_impl.py
│ │ ├── hidconsole.py
│ │ └── udev_impl.py
│ ├── keysyms/
│ │ ├── __init__.py
│ │ ├── generate.py
│ │ └── keysymdef.py
│ ├── logitech_receiver/
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── base_usb.py
│ │ ├── common.py
│ │ ├── descriptors.py
│ │ ├── desktop_notifications.py
│ │ ├── device.py
│ │ ├── diversion.py
│ │ ├── exceptions.py
│ │ ├── hidpp10.py
│ │ ├── hidpp10_constants.py
│ │ ├── hidpp20.py
│ │ ├── hidpp20_constants.py
│ │ ├── i18n.py
│ │ ├── listener.py
│ │ ├── notifications.py
│ │ ├── receiver.py
│ │ ├── settings.py
│ │ ├── settings_new.py
│ │ ├── settings_templates.py
│ │ ├── settings_validator.py
│ │ └── special_keys.py
│ └── solaar/
│ ├── __init__.py
│ ├── cli/
│ │ ├── __init__.py
│ │ ├── config.py
│ │ ├── pair.py
│ │ ├── probe.py
│ │ ├── profiles.py
│ │ ├── show.py
│ │ └── unpair.py
│ ├── configuration.py
│ ├── custom_logger.py
│ ├── dbus.py
│ ├── gtk.py
│ ├── i18n.py
│ ├── listener.py
│ ├── tasks.py
│ ├── ui/
│ │ ├── __init__.py
│ │ ├── about/
│ │ │ ├── __init__.py
│ │ │ ├── about.py
│ │ │ ├── model.py
│ │ │ ├── presenter.py
│ │ │ └── view.py
│ │ ├── action.py
│ │ ├── common.py
│ │ ├── config_panel.py
│ │ ├── desktop_notifications.py
│ │ ├── diversion_rules.py
│ │ ├── icons.py
│ │ ├── pair_window.py
│ │ ├── rule_actions.py
│ │ ├── rule_base.py
│ │ ├── rule_conditions.py
│ │ ├── tray.py
│ │ └── window.py
│ └── version
├── mkdocs.yml
├── po/
│ ├── README
│ ├── ca.po
│ ├── cs.po
│ ├── da.po
│ ├── de.po
│ ├── el.po
│ ├── es.po
│ ├── fi.po
│ ├── fr.po
│ ├── hr.po
│ ├── id.po
│ ├── it.po
│ ├── ja.po
│ ├── ka.po
│ ├── nb.po
│ ├── nl.po
│ ├── nn.po
│ ├── pl.po
│ ├── pt.po
│ ├── pt_BR.po
│ ├── ro.po
│ ├── ru.po
│ ├── sk.po
│ ├── solaar.pot
│ ├── sr.po
│ ├── sv.po
│ ├── tr.po
│ ├── uk.po
│ ├── zh_CN.po
│ └── zh_TW.po
├── pyproject.toml
├── release.sh
├── rules.d/
│ └── 42-logitech-unify-permissions.rules
├── rules.d-uinput/
│ └── 42-logitech-unify-permissions.rules
├── setup.py
├── share/
│ ├── README
│ ├── applications/
│ │ └── solaar.desktop
│ ├── autostart/
│ │ └── solaar.desktop
│ └── solaar/
│ └── io.github.pwr_solaar.solaar.metainfo.xml
├── tests/
│ ├── __init__.py
│ ├── hid_parser/
│ │ ├── __init__.py
│ │ └── test_data.py
│ ├── hidapi/
│ │ ├── __init__.py
│ │ └── test_hidapi.py
│ ├── logitech_receiver/
│ │ ├── __init__.py
│ │ ├── fake_hidpp.py
│ │ ├── test_base.py
│ │ ├── test_base_usb.py
│ │ ├── test_common.py
│ │ ├── test_desktop_notifications.py
│ │ ├── test_device.py
│ │ ├── test_diversion.py
│ │ ├── test_hidpp10.py
│ │ ├── test_hidpp20_complex.py
│ │ ├── test_hidpp20_simple.py
│ │ ├── test_notifications.py
│ │ ├── test_receiver.py
│ │ ├── test_setting_templates.py
│ │ └── test_settings_validator.py
│ ├── solaar/
│ │ ├── test_gtk.py
│ │ └── ui/
│ │ ├── test_about_dialog.py
│ │ ├── test_common.py
│ │ ├── test_desktop_notifications.py
│ │ ├── test_i18n.py
│ │ ├── test_pair_window.py
│ │ └── test_probe.py
│ └── test_keysyms/
│ ├── __init__.py
│ └── test_keysymdef.py
└── tools/
├── clean.sh
├── create-macos-app.sh
├── create-macos-launchagent.sh
├── hidconsole
├── install-rhel.sh
├── po-compile.sh
├── po-update.sh
└── scan-registers.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .coveragerc
================================================
[run]
branch = True
source =
hid_parser
hidapi
keysyms
logitech_receiver
solaar
omit =
*/tests/*
*/setup.py
*/__main__.py
[report]
exclude_lines =
pragma: no cover
if __name__ == '__main__':
if typing.TYPE_CHECKING
fail_under = 40
================================================
FILE: .git-blame-ignore-revs
================================================
# yapf bulk change
72a8d311bce64b1536c08e754d22bb91efb66460
# isort bulk change
e6369e0c3c240715a0a2daede6c3b225ed63cf60
# pre-commit bulk change
33521558ed7007c24b24127f1448c2c23ecbfb35
# flake8 bulk change
627185079f65c9cc471194b7927c833682e4a7a3
# yapf style update
27c90fa736d8a7a1ef6acda4345d3599862e185c
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Information**
<!-- Make sure that your issue is not one of the known issues in the
Solaar documentation at https://pwr-solaar.github.io/Solaar/ -->
<!-- Make sure that Solaar's udev rule is running by executing
`ls -l /dev/hidraw*` and looking for + as the last character of the permissions. -->
<!-- Do not bother opening an issue for a version older than 1.1.14.
Upgrade to the current version and see if your issue persists. -->
<!-- If you are not running the current version of Solaar,
strongly consider upgrading to the current version. -->
<!-- Note that some distributions have very old versions of Solaar
as their default version. -->
- Solaar version (`solaar --version` or `git describe --tags` if cloned from this repository):
- Distribution:
- Kernel version (ex. `uname -srmo`):
- Output of `solaar show`:
<!-- To run `solaar show` in 1.1.18 you have to clone Solaar from this repository
and `run bin/solaar show` from the download directory. -->
<details>
```
SOLAAR SHOW OUTPUT HERE
```
</details>
- Contents of `~/.config/solaar/config.yaml` (or `~/.config/solaar/config.json` if `~/.config/solaar/config.yaml` not present):
<details>
```
CONTENTS HERE
```
</details>
- Errors or warrnings from Solaar:
<!-- Under normal operation Solaar keeps a log of warning and error messages
in ~/.tmp while it is running, as a file starting with 'Solaar'.
If this file is not available or does not have useful information you can
run Solaar as `solaar -ddd`, after killing any running Solaar processes to
have Solaar log debug, informational, warning, and error messages to stdout. -->
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Information**
<!-- The version of Solaar in this repository has more features than released vesions. Update to this version before asking for a new feature. -->
- Solaar version (`solaar --version` and `git describe --tags`):
- Distribution:
- Kernel version (ex. `uname -srmo`):
- Output of `solaar show` for the target device (if applicable):
<details>
```
OUTPUT HERE
```
</details>
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/workflows/checks.yml
================================================
name: checks
on: [push, pull_request]
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
- name: Run pre-commit
uses: pre-commit/action@v3.0.0
================================================
FILE: .github/workflows/gh-pages.yml
================================================
name: Deploy to GitHub Pages
on:
push:
branches:
- master
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: 'pages'
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
pip install mkdocs mkdocs-rtd-dropdown mkdocs-mermaid2-plugin mkdocstrings[python]
- name: Build and deploy
run: |
mkdocs build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: 'site'
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
================================================
FILE: .github/workflows/tests.yml
================================================
name: tests
on: [push, pull_request]
jobs:
ubuntu-tests:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.13]
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Ubuntu dependencies for python 3.8
if: matrix.python-version == '3.8'
run: |
make install_apt
- name: Install Ubuntu dependencies for python 3.13
if: matrix.python-version == '3.13'
run: |
make install_apt_python3.13
- name: Install Python dependencies
run: |
make install_pip PIP_ARGS='.["test"]'
- name: Run tests on Ubuntu
run: |
make test
- name: Upload coverage to Codecov
if: github.ref == 'refs/heads/master'
uses: codecov/codecov-action@v4.5.0
with:
directory: ./coverage/reports/
env_vars: OS, PYTHON
files: ./coverage.xml
flags: unittests
name: codecov-umbrella
token: ${{ secrets.CODECOV_TOKEN }}
macos-tests:
runs-on: macos-latest
strategy:
matrix:
python-version: [3.13]
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Set up macOS dependencies
run: |
make install_brew
- name: Add Homebrew's library directory to dyld search path
run: |
echo "DYLD_FALLBACK_LIBRARY_PATH=$(brew --prefix)/lib:$DYLD_FALLBACK_LIBRARY_PATH" >> $GITHUB_ENV
- name: Install Python dependencies
run: |
make install_pip PIP_ARGS='.["test"]'
- name: Run tests on macOS
run: |
pytest --cov --cov-report=xml
- name: Upload coverage to Codecov
if: github.ref == 'refs/heads/master'
uses: codecov/codecov-action@v4.5.0
with:
directory: ./coverage/reports/
env_vars: OS, PYTHON
files: ./coverage.xml
flags: unittests
name: codecov-umbrella
token: ${{ secrets.CODECOV_TOKEN }}
================================================
FILE: .gitignore
================================================
*.pyc
*.pyo
__pycache__/
*.log
*.mo
/lib/Solaar.egg-info/
/lib/solaar.egg-info/
/lib/solaar/commit
/build/
/sdist/
/dist/
/deb_dist/
/MANIFEST
.coverage
/htmlcov/
/docs/captures/
/share/logitech_icons/
/share/locale/
/po/*.po~
/.idea/
.DS_Store
._*
Pipfile
Pipfile.lock
================================================
FILE: .pre-commit-config.yaml
================================================
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: check-ast
- id: check-builtin-literals
- id: check-merge-conflict
- id: check-yaml
- id: check-toml
- id: debug-statements
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.2
hooks:
- id: ruff
name: ruff lint
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
name: ruff format
================================================
FILE: .python-version
================================================
3.11
================================================
FILE: CHANGELOG.md
================================================
# 1.1.19
* New Georgian translation
* Remove test that doesn't work in older Pythons
* Update help messages for CLI commands
* Allow solaar config to change LED settings
* Add python3-devel to install-dnf in Makefile
* hidconsole can send an HID command non-interactively
* Add info about new lightspeed receiver
* Update Swedish and zh_TW translation
* Fix bug when showing details about direct-connected device
* Drop testing of Python before 3.13
* Fix crash in solaar show when showing notification flags. (#3070)
# 1.1.18
* Fix crash when showing notification flags
# 1.1.17
* Add dark icons
* Permit onboard profiles version 5
* Update Russian and Polish translations
* Add onboard profiles warning to sensitivity tooltip
* Better error messages for solaar profile
* Remove Solaar name for mice with WPID 4008
* Prevent lock failure when showing debug messages
* Replace color picker (#3028)
* Add setting for HAPTIC feature
* Add setting to adjust force needed for force-sensing buttons
* Expand new settings type
* Add new settings type for structure-backed setting
* Use PATH instead of hardcoded absolute paths (#3014)
* Add scroll ratchet force setting
* Fix debug messages for MouseClick rule
* Improve debug message for rule evaluation
* App wrapper and launch agent scripts for MacOS
* Ignore hidden features
* Don't pop up window in response to ADC changes
* Update bug report template
* Fixed malformed doc file by adding closing tag
* Fix error in low-level request for device with no recevier
* Update documentation files
# 1.1.16
* Add new flags for reprogrammable keys feature
* Correctly handle missing battery feature
# 1.1.15
* Correctly re-raise permissions exception
* Add several new special keys and tasks
* Update several translations
* Center labels and remove buggy entry resizing logic
* Add shape keys from Key POP Icon
* Device and Action rule conditions match on codename and name
* Fix listing hidpp10 devices - bytes vs string concatenation (#2856)
* Add present flag, unset when internal error occurs, set when notification appears
* Pause setting up features when error occurs; use ADC message to signal connection and disconnection
* Fix listing of hidpp10 peripherals
* Complete DEVICE_FEATURES to DeviceFeature transition for hidpp10 devices
* Fix NOTIFICATION_FLAG to NotificationFlag transition leftovers
* Fix github workflow stopping all matrix jobs when one of them fails
* Fix ubuntu github CI
* Update index.md
* Python documentation appears to be broken so don't set it up
* Improve documentation on onboard profiles
* Use correct LOD values for extended adjustable dpi
* Better support RGB Effects - not readable
* Fix crash when asking for help about config
* Fix error when updating ChoiceControlBig box
* Add uninstallation docs
* Handle unknown power switch locations again
* Correctly handle selection of [empty] in rule editor
* Handle `HIDError` in `hidapi.hidapi_impl._match()` (#2804)
* Give ghost devices a path
* Guard against typeerror when setting the value of a control box
* Recover from errors in ping
* Replace spaces by underscores when looking up features
* Rewrote string concatenation/format with f strings
* Fix logo not showing in about dialog box
* Make typing-extensions dependency mandatory
* Properly ignore unsupported locale
* hidapi: skip unsupported devices and handle exception on open
* Ignore macOS junk files and pipenv config
* Fix ui desktop notifications test
* hidpp20: Remove dependency to NamedInts
* Estimate accurate battery level for some rechargable devices (#2745)
* Upgrade desktop notifications tests to take notifications availability into account
* Update tests to run on Python 3.13
* Remove outdated logger enabled checks
* Introduce GTK signal types
* Introduce error types
* Remove alias for SupportedFeature
* Refactor process_device_notification
* Refactor process_receiver_notification
* Refactor receiver event handling
* Introduce custom logger
* Refactor notifications
* Rename variable to full name notification
* Test notifications
* Test extraction of serial and max. devices
* Refactor extraction of serial and max. devices
* macOS: Fix int.from_bytes, int.to_bytes for show.py
* macOS: Remove udev rule warning
* macOS: Add support for Bluetooth devices
* Add back and forward mouseclick actions
* Speedup lookup of known receivers
* Refactor device filtering
* Reorder private functions and variable definitions
* Turn filter_products_of_interest into a public function
* Improve tests of known receivers
* Refactor: Remove NamedInts and move enums where used
* Add docstrings and type hints
* Enforce rules on RuleComponentUI subclasses
* Simplify settings UI class
* Remove diversion alias
* Refactor: Convert Kind to IntEnum
* Split up huge settings module
* Remove Python 2 specific path handling
* Delete logging temp file on exit
* Update Swedish translation
# 1.1.14
* Handle fake feature enums in show
* Fix battery entries in config.yaml
* Add ratchet setting for smart shift enhanced devices
* Refactor Gesture into enum
* Replace ERROR NamedInts by IntEnum (#2645)
* Refactor hidpp20 to use enum
* Update Polish, Swedish, Norwegian Nynorsk (nn), and Norwegian Bokmål (nb) translations
* Use IntEnum for firmware and cidgroup constances
* Change pairing error values to intenums
* Fix initialization bug for PackedRangeControl
* Add tests for feature class, process_notification, and key_is_down
* Check all bits for extended report rate
* Add type hints
* Improve about dialog
* Reduce dependencies
* Refactor code
* Improve testing
* Allow unknown keys in Key rule conditions
* Improve documentation for cli actions
* Cycle sw_id to better guard against duplication of messages
* Handle error return on root feature
* Clean up documentation
* Improve github interactions
* Add information about Onboard Profiles overriding some settings
* Add wording to README.md that Solaar is not a device driver
* Clean up imports
* Handle unknown device kinds
* Fix broken links to Solaar logo
* Use mkdocs for public documentation
* Clean up setup.py
* Remove Dead links in the AppStream file
* Update about.py
* Remove check on driver
* Improve base module
* Remove unnecessary receiver info 'hid_driver'
* Convert HIDPPNotification to dataclass
* Be defensive when converting battery status to string
* Automatically detect packages in /lib
* Clean up locale code
* Improve rules documentation
* Refactor creation of devices
* Add headings to structure rules.md
* Unify imports in logitech package
* Don't ping device when getting name or codename
* Use dataclasses and enums where useful
* Introduce Device protocol and type hints
* Add typing_extensions dependency
* Move hidpp10 independent functions to module level
* Fix macOS compatibility and reenable CI tests
* Unify imports in hidapi package
* Move screenshots into dedicated folder and add high-level graph of components
* Update French and Chinese translations
* Drop support for end-of-life Python 3.7
# 1.1.13
* Update Polish and Russian translations.
* Fix bug in suspend and resume callback
* Add choices universe for backlight setting
* Add simplify diversion.py and add unit tests
* Get and use current host number for K375sFnSwap because of bug in firmware of MX Keys S
* Fix bug with logo in about window
* Don't ping device just to get logging information
* Optimize write for per-key lighting
* Add and initialize per-key lighting to a special no-change value
* Remove some Python 2 compatibility code
* Update French translation
* Refactor rule loading for testability
# 1.1.12
* Check for existence of keys file before opening
* Perform translation for all translatable strings.
* Add included hid_parser to packages installed
* Improve label and description for LED zone settings
* Add message about Onboard Profiles to LED Zone settings
* Initialize device registers to empty list
* Use bluez dbus signals to disconnect and connect bluetooth devices
* Handle a different signal for onboard profiles directory in ROM
* Introduce small delay in getting pairing information to let receiver settle after pairing
* Improve testing for settings_templates, settings, hidpp20, and device and fix small bugs found
* Add extended adjustable DPI setting
* Improve and extend infrastructure for testing setting_templates
* Update Greek, Polish, Russian, and Traditional Chinese translations
* Implement and test per-key lighting
* Refactor and test pair_window in GUI
* Handle situation when read of a setting fails in GUI
* Permit continuing when a read during pushing fails
* Fix bug in LEDZoneSetting when effect is not implemented
* Add tests for LEDEffect structures in hidpp20
* Handle BRIGHTNESS_CONTROL notifications
* Add settings for BRIGHTNESS_CONTROL and RGB_EFFECTS features
* Fix small bugs found from testing in settings
* Use f-strings for more exceptions and log message
* Tests for setting_templates
* Simple change in settings to improve testability
* Use feature_request from the device everywhere in hidpp20
* Fix bug in backlight 2 durations
* Replace deprecated code constructs
* Set up test data and classes to help test HID++ interactions
* Use pytest to test code for logitech_receiver modules
* Align init methods for all receiver classes
* Start refactoring of code base
* Allow sub-second delays in Later
* Fix bug in setting configuration cookie due to bad documentation
* Use ruff for code styling and linting
* Upgrade string formating to f-string
* Document battery-icons=solaar option
* Tell devices to delay device sending first messages until configuration is done
* Optimize some functions in FeaturesArray
* Fix bug in creating features array
* Fix bug in building battery line in show
* Refactor diversion_rules
* Fix bug in determining tray icon
* Fix bug in getting friendly name
* Move status information to Device and Receiver objects
* Add tests for get_kind_from_index and base product information
* Update EX100 documentation
* Use object attributes instead of dictionary in status objects
* Create subclasses of receiver for different variants
* Add requirement for CONFIG_HIDRAW to documentation
* Add some low-level tests for some hidpp20 functions, profiles, and lighting and some hidpp10 tests
* Fix app name casing in UI
* Add missing receiver type for Lightspeed receivers
* Add new device types
* Refactor device and receiver instantiation
* Simplify naming of distribution files
* Clean up some logging code
* Remove duplicated code to read register
* Introduce Hidpp20 and Hidpp10 class
* Remove unnecessary calls of del
* Fix bug when reading BACKLIGHT setting from device
* Replace invalid hidpp10 and hidpp20 usages
* Use only timer thread to save config.yaml
* Improve README
* Copy newer version of hid_parser
* Reorder code in settings
* Update installation documentation
* Add missing license blocks
* Clean up listener and notifications code
* Add locks to prevent multiple persisters for device
* Clean up configuration, device, and receiver code
* Move battery constants common to HID++ 1.0 and 2.0 to common
* Move mapping of device kind into hidpp20
* Move pairing information gathering to receiver
* update contributors
* Expand allowable profile numbers
* Clean up __init__ in logitech_receiver
* Modify pre-commit args to make ruff change files
* Fix bug in hidpp20 get host names
* Use ruff for formatting and linting
* Fix bug in rule Set action
* Add notify module to logitech_receiver
* Implement setting_changed callback and pass in to new devices and receivers
* Add callback to call when changing a setting
* Move exceptions, hidpp20 and hidpp10 constants into new modules
* Streamline status code
* Upgrade debugging in udev
* Fix deprecated GitHub actions
* Extend makefile and tests
* Improve features array
* Move ui_async to common.py
* Improve module imports
* Add tests of common module
# 1.1.11
* Rename light icons and install them in correct place
* Setup macOS tests using GitHub action (#2284)
* Better checking for setting in record_setting
* Fix invalid func name set logo name
* Simplify installation of udev rules
* Add document on implementation
* Tidy up scrolling appearance in configuration panel
* Correctly handle profile button with no action
* Don't unlock setting when changed by external means
* Refactor code to record change to setting
* Add GitHub action for tests
* Introduce tests with pytest
* Simplify logger instantiation
* Update label and tooltip for divert-gkeys setting
* Don't lock setting when an error occurs
* Catch assertion errors when reading setting values from devices
* Support LED Zone control feature
* Dump and load device profiles
* Select among profiles.
* Support backlight levels and duration
* Use "Report Rate" instead of "Polling" for movement report rate
* Support extended report rate setting
* Add stable branch to release.sh (#2236)
* Fix changelog parsing in release.sh
* Update installation.md with new udev rules location
* Downgrade assertion on missing notification flag to warning
* Write empty file if there are no rules to save
* Be defensive in device error messages
* Add descriptions of M650, PRO X 2, G915, MX Anywhere 2S, G305, and MX Keys S
* Report hidraw node in debugging messages
* Add names for new Logitech features
* Update Spanish, French, and Polish translations
* Defend against lightspeed receivers that contact devices for basic information
* Remove incorrect feature for M325 mice
* Add K845 keyboard
* Add partial support for macOS and minimal support for Windows
* Correctly enumerate devices on receiver
* Add wording in documentation about Logitech reusing model numbers
* Better handling and installation of icons
* Catch errors when pinging to try to put device online
* Be more cautious when creating log messages to avoid exceptions
* Correctly handle NoSuchDevice exception when pinging device
* Fix test in rules for device equality
* Add installation instructions for pipx and add not about other GTK system packages
* Fix bug in NamedInt
* Add support for MK550
* Install udev rule files to correct placces
* Expand expected ping responses
* Update codename when device status changes
# 1.1.10
* Add information about NixOS flake package
* Permit bluetooth devices in hidconsole
* Add descriptor for Logitech MX Revolution Mouse M-RCL 124
* Improve determination for short and long messages
* Add descriptor for G500s
* Fix bug in scan-registers
* Add single depress and release options for rule mouse click action
* Add rule condition for hostname
* Update keysym generation to current list of keysyms
* Allow device 0 in hidconsole
* Upgrade messages when no supported device found
* Documentation update for the gnome extension for better Solaar rule support
* Remove udev-acl tag from udev rules
* Add support for process condition in Wayland
* Update French, Chinese, and German translations
* Add G733 Headset
* Restore tools/clean.sh
* Add Bluetooth Keyboard C714
* Update several device descriptions
* Update scan-registers.sh
* Remove assertion on last byte of ping responses
* Add symbolic version of solaar icon
* Fix bug when finding name or codename
* Update documentation
* Put version in initial INFO logging message
# 1.1.9
* Add descriptors for G535 wireless gaming headset and wireless keyboard EX110
* Update Greek translation
* Fix minor issues in documentation
* Remove some deprecated GTK code
* Use zero exit code for kill interrupts
* Add rule Test condition for battery charging
* Get wpid for 28Mz devices from udev when enumerating
* Add Device condition to rules
* Don't show wireless link or battery information when unknown or not present
* Add desccriptor for G9x and LX7 mice
* Fix bug in determining kind of devices for 27Mz receivers
* Set initial lock status of smooth scrolling features to ignore
* Fix glitch in configuration file update when changing versions
* Add more debugging output for rules
* Clean up pinging code
* Put initial ping of direct-connected devices inside listener thread
* Read and check before write of range settings
* Improve pairing determination
* Cut off determination of receiver devices when all have been found
* Remove derived configuration fields when Solaar version changes
* Allow device descriptors without name and codename
* Filter and escape technical detail fields
* Add setting for ADC power managemen
* Correctly determine whether to ping with a long HID++ message
* Add description for K470 keyboard from the MK470 combo (#1945)
* Add setting value for mouse gestures
* Update German and French translations
* Remove old clean.sh and monitor.py tools
* Retry opening device if permissions error encountered
* Better handlling of IO errors at device creation
* Add KeyIsDown rule condition to check whether a diverted key is down
* Clean up device and receiver creation
# 1.1.8
* Add parameter to thumb wheel rule conditions
* Rename Serbian translation file
* Update Polish translation
* Improve handling of wheel notifications
* Only record changes of scroll wheel ratchet
* Don't mark setting as absent if there are device errors
* More robust access to keyword exception fields
* Add support for config change feature
* Clean up GTK code
* Update documentation on mouse gestures and known issues
* Get commit information from git describe and dpkg-parsechangelog
* Update pre-commit tools to current versions
* Update installation instructions
* Add 8-character commit hash to version information
* Update solaar.desktop (#1857)
* Get release in setup.py by reading lib/solaar/__init__.py
* Remove version number from docs/_config.yml
* Update solaar.desktop
* Update es.po
* Clarify status of C542 receiver
* Update devices directory
* Add description of several devices
* Show name of disconnecting receiver or device in disconnect warning
* Reduce standard size of rule editor window
* Remove unnecessary dependency on typing_extensions
# 1.1.7
* Add dependency on typing_extension to setup.py
* Don't defer saves in CLI and don't require Gtk in CLI
* Be more permissive in recognizing HID++ report descriptors
* Update Polish and Croatian translations
* Switch scroll ratcheting in response to scroll ratchet button notification
* Add setting to turn scroll ratchet on and off
* Eliminate visual glitch when updating range setting
* Make hid-parser an optional dependency
# 1.1.6
* Only update remaining pairings after successful pairing
* Check for presence of status attribute when resuming
* Update Polish and Croation translations
* Don't add non-existant key in raw xy processing
* Add special keys from MX Mechanical Mini
* Fix processing of HID++ 1.0 battery reports
* Use report descriptors to determine suitable devices
* Handle exceptions when processing configuration file
* Add Logitech PRO Gaming Keyboard
* Fix bad entries in divert-keys when found
* Correctly convert old-style diversions to new style and remove old ones
* Add optional save argument to write_key_value methods
* Use device name in configuration entries if device modelId is zeroes
* Don't show normal DJ messages in debug log
* Add Later rule action
* Correctly record battery feature when ADC produces error
* Print feature call errors in solaar show instead of terminating
* Use ADC notifications to set device inactive and active
* Add one to feature count to count ROOT feature
* Don't check modifiers for KeyPress actions that are not clicks
* Augment comments on what Solaar cannot do
* Fix bug in printing closed handle
* Use only product records to determine which receivers unpair
* Add conditional delay to get around race with Linux HID++ driver
# 1.1.5
* Add G213 Prodigy Gaming Keyboard
* Update Turkish, Croation, and zh_CN translations
* Move old device descriptions to new locations and clean up
* Increase minimum stopped time between mouse movements
* Fix bug with non-recognized empty mouse movement
* Allow config panel to scroll
* Add descriptions for K360 4004, MX Master 4017, Lightspeed C541, and G915 407D
* Change security tooltip for unencrypted wireless connections
* Add Norwegian Bokmal translation
* Update documentation on continuously running GUI, diverted keys, and changing hosts
* Solaar config no longer applies settings
* Add description of rule components to rule editor
* Ignore first movement for mouse gestures when reprog controls version is 5 or more
* Add Active rule condition to test whether a device is active
* Terminate iteration over receiver devices when all have been found
* Downgrade Set prolem messages from error to warning
* Log informational messages and above to a temporary file
* Don't produce warnings when editing rules in rule editor
* Fix bug that didn't save rules file if there were no rules
* Allow devices with connection number larger than max_devices
* Show more registers in solaar probe
* Show feature versions in solaar show
* Fix problems with deleting devices on exit
* Update German translation
* Update device documentation directory
* Add descriptors for G502 Proteus Spectrum Optical Mouse and G935 headset
* Record feature versions
* Add Serbian translation
* Fix circular import in rules
* Keep track of devices and use in rules
* Update zh_CN and zh_TW translations
* Convert old-style mouse gestures and sliding dpi settings to new style
* Allow multiple keys for mouse gestures and sliding dpi
* Defer saving configuration file for a while to cut down on the number if times it is saved
* Use correct functions for unified battery and battery voltage features.
* Add defensive check for missing keys array in mouse gestures setting
* Better presentation of battery information
* Add support for ADC MEASUREMENT battery feature
* Add information on how to find divertable key names in solaar show output
* Better warnings for feature call errors with reprogrammable key and gesture settings
* Increase entry size for ChoiceControlBig
# 1.1.4
* Update Croatian translation
* Handle unanticipated values for persistent remappable action as default
* Improve system tray interface documentation
* Remove blank lines from system tray popup
* Update Polish translation
* Add depress and release options to KeyPress rule action
* Only close existing devices for receiver
* Differentiate debug messages for different setting types
* Implement packed range setting in config panel
* Only produce warning for unimplemented display of setting
* Add sidetone and equalizer settings for headsets
* Add packed ranges setting
* Use built-ins for conversions between int and byte string
* Don't add HI_RES wheel ecodes to evdev device codes
* Handle null key in persistent remappable actions when device does not respond
* Consult polling rate feature for polling rate
* Eliminate extra file handles
* Close file handles for receiver-connected devices
* Access to more keys in KeyPress rule action when in other keyboard groups
* Update Turkish translation
* Put battery levels in tray menu labels
* Reduce warnings for inaccessible keys in KeyPress rule action
* Better determination of keycodes and insert needed shifts in KeyPress actions.
* Be careful when processing notifications for partly set up devices.
* Clear out fields for empty persistent remappable action.
* Fix message generation when device is offline.
* Fix bug in feature lookup.
* Add support for G533 Headset and G502 Gaming Mouse
* Improve device features handling.
* Keep trying settings that have worked in the past.
* Store None in persisters for non-persisting settings.
* Only create configuration entries for off-line devices if they have a serial number.
# 1.1.3
* Update documentation files
* Lower remove python 3.7 constructs and lower python dependency to 3.6
* Fix bug in xtest mouse scrolling
* Allow mouse gesture setting for non-mice, e.g., trackballs
* Print message when there is another Solaar process running
* Fix determination of whether to force read before writing boolean setting
* Add recent diversion features to default list in rules UI
* Add setting to divert hires scroll wheel
* Don't use device kind to determine how to handle notifications
* Update Polish, Russian, and zh_CN translations
* Remove pggettext so as to not require Python 3.8
* Remove Python 2 unicode support
* Store keys in configuration file as int instead of str
* Use yaml for configuration file instead of json.
* Remove process-dependent rules from built-in rules.
* Handle situation where GTK application cannot be set up in CLI.
* Remove obsolete upower signals.
* Appinfo/metadata fixes including using correct APP_ID.
* Fix bugs in solaar config.
* Add full set of mouse buttons in persistent remappable actions setting.
* Improve rule behaviour under Wayland and when Xtest or X11 not available.
* Fix up and document dependencies (evdev, Python, ...).
# 1.1.2
* Update documentation on supported devices and translations
* Include evdev as a dependency
* Try to use uinput for fake input if XTest extension not available
* Add Nano receiver C542 for M190 mice
* Broaden range of HID++ Bluetooth devices
* Add setting to divert gestures
* Rule editor can edit all rule components
* Configuration via solaar config takes effect in Solaar UI if it is running
* Add setting to disable Onboard Profiles and decouple from Polling Rate setting
* Add setting for PERSISTENT_REMAPPABLE_ACTION, common keyboard and mouse cases only
* Split Test rule condition into Test and TestBytes and support in rule editor
* Fix bug in speed-change setting
* Support Backlight3 feature
* Ensure that settings are pushed in resume
* Update German, Polish, and zh_CN translations
* Determine device number for direct-connected devices from protocol
* fix bug in add and delete button actions in rule editor
* dispose of no-op notifications quickly
* add rule condition for checking device settings
* use local file for conversion from key names to keysyms
* get keyboard group and use to get correct keycodes (X11 only)
* improve how rules work under Wayland
* add settings for M-Key LEDs and MR-Key LED
* fix bug in unpacking M and MR key notification
* add G815 keyboard and MX518 mouse
* add new special keys for recent keyboards
* track M and MR keys for use in rules
* make sure that device is online when searching for devices in solaar show
* don't check for device kind in dpi sliding setting
* fix problem with devices that report 0 DPI
* handle missing divert-setting in action RW for settings
* add id property (unitId or serial) and don't use ? for unknown serial
* fix contains for NamedInts and eliminate use of has_element
* check for xtest and disable modifier checking if not available
* improve determination of gesture information
* add Set rules to rule GUI
* add gesture params to Set rules
* hide system tray when there are no devices to control
* add G733 headset, G9 mouse, G502 Hero mouse
* Use greyscale solaar icon in tray when using symbolic icons
* Fix bugs in solaar config
* Use classes for settings to hep with modularity
* Accept '~' and Toggle for toggling boolean settings in cli and rules
* handle errors when writing to devices
* refactor config_panel.py to use classes for widgets
* add rules action to set Solaar settings
* decrease amount of logging at each debug level
* don't stretch toggles in settings
* use key structure for key remapping setting
* optimize ReprogrammableKey implementation
* keep track of settings that are absent from device
* add G512 keyboard and G402 mouse
* reformat descriptors.py
* use feature numbers for reprogrammable key versions
* don't use new_from_icon_set in menu as it is deprecated
# 1.1.1
* Keep left pane in Solaar main window the same size
* Fix crash when checking a process condition when X11 not running
* Add version number to output of solaar show
* Fix crash when pinging a device with unknown protocol
* Display battery percentage estimates from battery voltage
* Add minimal support for Logitech PRO X Wireless Gaming Headset
* Push settings when device requests software reconfiguration
* Fix read for key/button diversion setting
* Add modalias information to Solaar metainfo
* Don't do on-screen notifications when devices are powered on
* Add setting to switch crown between smooth and ratchet scrolling
* Add write_prefix_bytes argument to Boolean validator
* Update Russian and Spanish translations
* New shell script tools to help determine capabilities of receivers
* Add special keys for MX Keys for Business and MX Keys Mini
* Improve tray menu ordering
* Add --tray-icon-size option to get around bugs in some tray implementations
# 1.1.0
* Fix bug when adding receiver to tray menu
* Add Catalan translation.
* Add toggle command to solaar config to toggle boolean settings
* Don't select windows with no PID when looking for focus window
* Catch errors when applying settings so that other settings are not affected
* Add support for Bolt receivers and devices, including pairing
* Revise method for creating system tray menu
* Remove obsolete code (mostly Python 2 compatibility code)
* Add support for PRO X Wireless Mouse, G914 TKL keyboard
* Ignore more notifications that come to a device listener
* Handle more device connection protocols
* Update usage and rules documentation
* Change emojis to text in documentation
* Pare down device documentation so as not to require frequent updates
* Add information about M500S mouse
* Reimplement MOUSE GESTURE and DPI SLIDING settings
* Add setting for DPI CHANGE button to switch sensitivity
* Use file name instead of icon name for tray to avoid XFCE bug
* Update documentation on implemented features and mouse gestures
* Update Polish, Japanese, and Spanish translations
* Make Quit and About strings more translatable
# 1.0.7
* Don't use time_ns so as not to require Python 3.7
* Correctly determine setting box in change_click method
* Handle fake Nano connection notifications
* Lock on actual handle, not just on handle number
* Mark Nano receiver C52F as not unpairing
* Upgrade pairing/unpairing documentation
* Don't signal status change when battery changes from None to None.
* Add Japanese translation
* Use first word of name for code name if no other code name available.
* Better determination of when to add SW ID.
* Check for more HID++ feature request failing.
* Fix bug with new_fn_inversion setting.
* Use correct device number for directly connected devices
* Add debug message when candidate device found
* Update Polish, Taiwanese, and Brazilian Portuguese translations
* Add MouseProcess a rule condition like Process but for the window under the mouse
* Add parameters for binary settings to support prefixes
* Add locks to serialize requests to devices
* Fix bug when reprog key requests returns None
* Fix bug for empty process name and class
* Rules can now trigger on both pressing and releasing a diverted key
* Upgrade mouse gestures to allow sequences of movements
* Fix gkeys diversion faked read
* Add support for Logitech g pro x superlight receiver
* Convert HID++ 2.0 device kinds to enhanced HID++ 1.0 device kinds
* Update about window, bug report templates, and supported kernels.
# 1.0.6
* Update sliding DPI to look for suitable keys
* Add mouse gestures that can trigger rules
* Complain if receivers do not support connection notification
* In polling rate setting, only modify onboard profiles when actually writing polling rate
* Add ability to ignore settings.
* Use symbols for receiver sub-registers
* Add support for wired G700
* Do not set attention icon
* Replace deprecated GTK stock menu icons
* Better handling of icons in tray and tray menus
* Receiver c52e does not unpair
* Match active WM_CLASS as well as active process name in rules
* Correctly set icon theme value when regular battery icons are not available
* Handle exception when device is not available when device is being added
* Perform initial activation of devices in listener threads
* Keep track of serial numbers in the configuration file
* Don't update settings for non-active devices
* Set the current host name if not stored on the device
* Add setting for SMART SHIFT ENHANCED feature
* Don't unnecessarily use long messages for HID++ 1.0 commands
* Correctly select choices in solaar config and use 1-origin addressing
* Add quirk for G915 TKL keyboard because its host mode interferes with its Fn keys
* Show command outputs both saved and on-device settings
* Update documentation
* Fix bug in hidconsole
* Update French translation
# 1.0.5
* Update documentation on devices forgetting settings.
* Improve help messages
* Fix bug in finding receiver to pair
* Solaar config command can set keyed settings.
* Add setting for polling rate
* Use long HID++ messages for all 2.0 requests
* Update German, Italian, and Polish translations
* Solaar config command no longer selects paired but unconnected devices
* Show HID++ 1.0 remaining pairings value in solaar show for devices that support it
* Add option to not use battery icons in system tray.
* Update Polish and Dutch translation.
* Add Czech translation.
* Remove information on SUSE package as it is very old.
* Turn GKEY notifications into Gn key keypresses that can trigger rules.
* Push device settings to devices after suspend when device is immediately active.
* Reduce unnecessary saving of configuration file.
* Better handling of disconnected devices.
* Implement GUI to edit rules.
* Implement rule-base processing of HID++ feature notifications (depends on X11).
* Add settings for diversion of crown and remappable keys.
* Access widgets by name instead of by index.
* Implement UNIFIED_BATTERY feature and use in battery reports.
* Add a clickable lock icon that determines where each setting can be changed.
# 1.0.4
* Update pt_BR translation
* Support USB and BT connected devices that are not in descriptors.py
* Use FRIENDLY NAME for codename if needed and available.
* Extract manufacturer and product ID from Udev HID information.
* Add Bluetooth and USB product IDs to device descriptors records.
* Support Bluetooth-connected devices.
* Add model ID and unit ID to device identification.
* Support changing DPI by pressing DPI Switch button and sliding horizontally
* Add device-specific notification handlers.
* Add MX Vertical USB information.
* Udev rule adds seat permissions for all Logitech devices.
* Support USB-connected devices in GUI.
* Make probe and config work for USB-connected devices.
* Improve strings and display for settings.
* Correctly handle non-unifying connection notifications.
* Update GUI strings for several settings.
* Better support for EX100 and devices that connect to it.
* Partial support for feature GESTURE_2.
* Simplify interface for settings.
* Use DJ connection notifications to set device active status
* Udev rule sets seat write permissions for hidraw nodes for device as well as receivers.
* Handle USB devices that use HID++ protocol in CLI.
* Use device hidraw nodes where possible.
* Handle receivers with serial numbers that don't provide number of pairings.
* Ignore exceptions when setting locale.
* Correctly discover settings that share a name.
* Don't show pop-up notifications at startup.
* Keep battery voltage updated in GUI.
* Add Portuguese translation.
* Update several translations.
* Add Lightspeed receivers c545 and c541.
* Reimplement REPROG_CONTROLS data structure.
# 1.0.3
* Clean up documentation files.
* Update documentation on installation.
* Update Swedish and French translations.
* Add Norwegian Nynorsk and Danish translations.
* Fix bug handling DJ pairing notifications.
* Add Norwegian Bokmål translation.
* Remove deprecated solaar-cli application.
* Don't install udev or autostart files from python (or pip).
* Solaar needs Python 3.6+ and probably needs kernel 5.2+
* Handle exceptions on dynamic settings when device is not connected.
* Fix infinite loop on some low-level write errors
* Add support for EX100 keyboard/mouse and receiver (046d:c517)
* Add two settings for THUMB_WHEEL feature - inversion and reporting via HID++
* Update German translation
* Use REPORT RATE feature when available to determine polling rate.
* Improve config command speed when not printing all settings
* Improve config command handling and checking of arguments
* Add setting for CHANGE_HOST feature
* Add argument to settings for values that are not to persist
* Add argument to settings to not wait for reply when writing a value to device
* Add argument to not wait for reply from request to device
* Add settings for MULTIPLATFORM and DUALPLATFORM features
* Remove Logitech documents from documentation directory
* Change config command to not read all settings when only printing or showing one
* Display hosts info in 'solaar show' if device supports it
* Remove non-working smooth-scroll from M510 v1
* Add yapf and flake8 code style checks
* Fix feature k375s Fn inversion
* Update controls (keys and buttons) and tasks (actions)
* Improved way to specify feature settings.
* Don't abort on device notifications with unexpected device numbers, just warn.
* Keep track of non-features so as not to ask device multiple times.
* Implement KEYBOARD DISABLE KEYS feature.
* Don't create notifications for DJ device activity reports.
* Update a few special keys and actions.
* Add keyed choice settings in configuration panel.
* Support remappable keys from reprogrammable keys v4 feature.
* Add setting class for keyed choice.
* Only check for features once per device.
* Use settings interface to show feature values in `solaar show` if no special code for feature.
* Remove maximum window size.
* Process battery voltage notifications.
* Display battery voltage information in main window if regular battery information not available.
* Show next battery level where available.
* Update list of implemented features and provide information on how to implement features.
* Add c53d as a Lightspeed receiver.
# 1.0.2
* Add usage document
* Don't produce error dialog for inaccessible receivers with access control lists.
* Add option --battery-icons=symbolic to use symbolic icons if available.
* Update French translation
* Update installation documentation
* Remove packaging directory tree as it is not maintained
* Pip installs udev rule and solaar autostart when doing install without --user flag
* Use Solaar icon instead of a missing battery icon
* Use only standard icons for battery levels. Symbolic icons do not change to white in dark themes because of problems external to Solaar.
* Better reporting of battery levels when charging for some devices.
* Add information on K600 TV, M350 WIPD 4080, and MX Keys
* Remove assertion requiring receivers to still be in window when they are updated.
* Augment long description of Solaar showing up in repositories.
* Update installation directions.
* Install udev rule as well as autostart file when doing system install.
* Add support for Ayatana AppIndicator.
* Use setuptools icon directory on system installs when not using pip.
* Add receiver C517 and several older devices.
* Improved translations for polish.
* Bypass bug in appindicator when solaar is file in current directory.
* Don't check that device kind matches feature kind.
* Better determination of icons for battery levels.
* Use Ayatana AppIndicator if available.
* Improve error reporting when required system packages are not install.
* Better tooltip description
* Add release script to help when creating releases
* Look up tray icon filenames to get around a bug in libappindicator.
* Make the default behavior be to show the main window at startup.
* Support c537 nano receiver
* Add logind signals for suspend/resume.
* Remove solaar-gnome3 package
* Ignore features for devices that don't follow feature specification
* Add probe command to command-line interface to dump receiver registers
* Don't terminate on malformed or unknown messages
* Create fewer internal notifications for messages from devices
* Add a button to the main window to terminate (quit) Solaar
* Set up nano receivers as receivers with no unpairing and with re-pairing
* Set up c534 as receiver with max 2 pairings, no unpairing, re-pairing
* Better support receivers that do not unpair or when pairing replace existing pairings
* Add information about receiver pairing to receiver data structure
* Better support devices that only allow a limited number of total re-pairings
* Add --window option to control main window visibility and tray usage
* Ignore receiver if USB id is not retrieved
* Fix bug with double deleting when devices are disconnected
* Determine some receiver information from data structure for USB ids
* Treat battery level of 0 as unknown
* Fix bug on devices with no serial number
* Drop support for python2, and use python3 throughout
* Fix bug in remembering features discovered from device reports
* Show icons in main window device list
* Count offline devices when determining whether pairing is possible
* Update French, Dutch, German, and Croatian translations
* Better icons for battery levels
* Support DPI, Backlight 2, Battery Voltage features
* Support M585, M590, M330, MX Master 2s and 3, new M310, new K800, craft keyboard
* Documentation improvements
* Clean up directory structure and remove unused files
# 1.0.1
* Updated the repo url.
* Fixed typo which was crashing the application.
* Improved the HID write routine which was causing issues on some devices.
* Fix non-unifying receivers in Linux 5.2.
* Add new Lightspeed receiver (used in the G305)
# 1.0.0
* Too many to track...
# 0.9.3
* Merged solaar-cli functionality into main solaar.
* Scrolling over the systray icon switches between multiple peripherals.
* Swedish translation courtesy of Daniel Zippert and Emelie Snecker
* French translation courtesy of Papoteur, David Geiger and Damien Lallement.
* Fixed some untranslated strings.
# 0.9.2
* Added support for hand detection on the K800.
* Added support for V550 and V450 Nano.
* Fixed side-scrolling with the M705 Marathon.
* Fixed identification of the T650 Touchpad.
* Added internationalization support and romanian translation.
* Polish translation courtesy of Adrian Piotrowicz.
# 0.9.1
* When devices report a battery alert, only show the alert once.
* Make sure devices in the window tree are sorted by registration index.
* Added an autostart .desktop file.
* Replaced single-instance code with GtkApplication.
* Fixed identification of the M505 mouse.
* Fixed an occasional windowing layout bug with the C52F Nano Receiver.
# 0.9.0
* New single-window UI.
* Performance MX leds show the current battery charge.
* Support the VX Nano mouse.
* Faster and more accurate detection of devices.
* If upower is accessible through DBus, handle suspend/resume.
* Replaced Solaar icons with SVGs.
* Running solaar-cli in parallel with solaar is now less likely to cause issues.
* Bugfixes to saving and applying device settings.
* Properly handle ^C when running in console.
# 0.8.9
* Improved support for gnome-shell/Unity.
* Persist devices settings between runs.
* Fixed reading of MK700 keyboard battery status.
* Use battery icons from the current theme instead of custom ones.
* Debian/Ubuntu packages now depend on an icon theme, to make sure
no missing icons appear in the application window.
* Fixed missing icons under Kubuntu.
* Many more bug-fixes and reliability improvements.
# 0.8.8
* Partial support for some Nano receivers.
* Improved support for some devices: M510, K800, Performance MX.
* Improved battery support for some HID++ 1.0 devices.
* Properly handle device loss on computer sleep/wake.
* Better handling of receiver adding and removal at runtime.
* Removed a few more unhelpful notifications.
* Incipient support for multiple connected receivers.
* More Python 3 fixes.
# 0.8.7
* Don't show the "device disconnected" notification, it can be annoying and
not very useful.
* More robust detection of systray icon visibility.
# 0.8.6
* Ensure the Gtk application is single-instance.
* Fix identifying available dpi values.
* Fixed locating application icons when installed in a custom prefix.
* Fixed some icon names for the oxygen theme.
* Python 3 fixes.
================================================
FILE: COPYRIGHT
================================================
Copyright 2012, 2013
Daniel Pavel <daniel.pavel@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 2.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
================================================
FILE: LICENSE.txt
================================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The 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.
When 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.
To 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.
For 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.
We 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.
Also, 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.
Finally, 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.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. 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".
Activities 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.
1. 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.
You 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.
2. 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:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
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.
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.)
These 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.
Thus, 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.
In 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.
3. 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:
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,
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,
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.)
The 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.
If 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.
4. 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.
5. 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.
6. 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.
7. 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.
If 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.
It 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.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. 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.
9. 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.
Each 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.
10. 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.
NO WARRANTY
11. 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.
12. 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.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If 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.
To 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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The 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.
You 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:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This 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.
================================================
FILE: MANIFEST.in
================================================
include COPYRIGHT LICENSE.txt README.md CHANGELOG.md lib/solaar/version lib/solaar/commit
recursive-include rules.d *
recursive-include share/locale *
================================================
FILE: Makefile
================================================
UDEV_RULE_FILE = 42-logitech-unify-permissions.rules
UDEV_RULES_SOURCE := rules.d/$(UDEV_RULE_FILE)
UDEV_RULES_SOURCE_UINPUT := rules.d-uinput/$(UDEV_RULE_FILE)
UDEV_RULES_DEST := /etc/udev/rules.d/
PIP_ARGS ?= .
.PHONY: install_ubuntu install_macos
.PHONY: install_apt install_brew install_pip
.PHONY: install_udev install_udev_uinput reload_udev uninstall_udev
.PHONY: format lint test
install_ubuntu: install_apt install_udev_uinput install_pip
install_macos: install_brew install_pip
install_apt:
@echo "Installing Solaar dependencies via apt"
sudo apt update
sudo apt install libdbus-1-dev libglib2.0-dev libgtk-3-dev libgirepository1.0-dev
install_apt_python3.13:
@echo "Installing Solaar dependencies via apt"
sudo apt update
sudo apt install libdbus-1-dev libglib2.0-dev libgtk-3-dev libgirepository-2.0-dev gobject-introspection
install_dnf:
@echo "Installing Solaar dependencies via dnf"
sudo dnf install gtk3 python3-devel python3-gobject python3-dbus python3-pyudev python3-psutil python3-xlib python3-yaml
install_brew:
@echo "Installing Solaar dependencies via brew"
brew update
brew install hidapi gtk+3 pygobject3 gobject-introspection
install_pip:
@echo "Installing Solaar via pip"
python -m pip install --upgrade pip
pip install $(PIP_ARGS)
install_pipx:
@echo "Installing Solaar via pipx"
pipx install --system-site-packages $(PIP_ARGS)
install_udev:
@echo "Copying Solaar udev rule to $(UDEV_RULES_DEST)"
sudo cp $(UDEV_RULES_SOURCE) $(UDEV_RULES_DEST)
make reload_udev
install_udev_uinput:
@echo "Copying Solaar udev rule (uinput) to $(UDEV_RULES_DEST)"
sudo cp $(UDEV_RULES_SOURCE_UINPUT) $(UDEV_RULES_DEST)
make reload_udev
reload_udev:
@echo "Reloading udev rules"
sudo udevadm control --reload-rules
uninstall_udev:
@echo "Removing Solaar udev rules from $(UDEV_RULES_DEST)"
sudo rm -f $(UDEV_RULES_DEST)/$(UDEV_RULE_FILE)
make reload_udev
format:
@echo "Formatting Solaar code"
ruff format .
lint:
@echo "Linting Solaar code"
ruff check . --fix
test:
@echo "Running Solaar tests"
pytest --cov --cov-report=xml
================================================
FILE: README.md
================================================
# <img src="https://pwr-solaar.github.io/Solaar/img/solaar.svg" width="60px"/> Solaar
Solaar is a Linux manager for many Logitech keyboards, mice, and other devices
that connect wirelessly to a Unifying, Bolt, Lightspeed or Nano receiver
as well as many Logitech devices that connect via a USB cable or Bluetooth.
Solaar is not a device driver and responds only to special messages from devices
that are otherwise ignored by the Linux input system.
<a href="https://pwr-solaar.github.io/Solaar/index">More Information</a> -
<a href="https://pwr-solaar.github.io/Solaar/usage">Usage</a> -
<a href="https://pwr-solaar.github.io/Solaar/capabilities">Capabilities</a> -
<a href="https://pwr-solaar.github.io/Solaar/rules">Rules</a> -
<a href="https://pwr-solaar.github.io/Solaar/installation">Manual Installation</a> -
<a href="https://pwr-solaar.github.io/Solaar/issues">Known Issues</a>
[](https://codecov.io/gh/pwr-Solaar/Solaar)
[](../LICENSE.txt)
<p align="center">
<img src="https://pwr-solaar.github.io/Solaar/screenshots/Solaar-main-window-multiple.png" width="54%"/>
 
<img src="https://pwr-solaar.github.io/Solaar/screenshots/Solaar-main-window-receiver.png" width="43%"/>
</p>
<p align="center">
<img src="https://pwr-solaar.github.io/Solaar/screenshots/Solaar-main-window-back-divert.png" width="49%"/>
 
<img src="https://pwr-solaar.github.io/Solaar/screenshots/Solaar-rule-editor.png" width="48%"/>
</p>
Solaar supports:
- pairing/unpairing of devices with receivers
- configuring device settings
- custom button configuration
- running rules in response to special messages from devices
For more information see
<a href="https://pwr-solaar.github.io/Solaar/index">the main Solaar documentation page.</a> -
## Installation Packages
Up-to-date prebuilt packages are available for some Linux distros
(e.g., Fedora) in their standard repositories.
If a recent version of Solaar is not
available from the standard repositories for your distribution, you can try
one of these packages:
- Arch solaar package in the [extra repository][arch]
- Ubuntu/Kubuntu package in [Solaar stable ppa][ppa stable]
- NixOS Flake package in [Svenum/Solaar-Flake][nix flake]
Solaar is available from some other repositories
but may be several versions behind the current version:
- a [Debian package][debian], courtesy of Stephen Kitt
- a Ubuntu package is available from [universe repository][ubuntu universe repository]
- a [Gentoo package][gentoo], courtesy of Carlos Silva and Tim Harder
- a [Mageia package][mageia], courtesy of David Geiger
[ppa stable]: https://launchpad.net/~solaar-unifying/+archive/ubuntu/stable
[arch]: https://www.archlinux.org/packages/extra/any/solaar/
[gentoo]: https://packages.gentoo.org/packages/app-misc/solaar
[mageia]: http://mageia.madb.org/package/show/release/cauldron/application/0/name/solaar
[ubuntu universe repository]: http://packages.ubuntu.com/search?keywords=solaar&searchon=names&suite=all§ion=all
[nix flake]: https://github.com/Svenum/Solaar-Flake
[debian]: https://packages.debian.org/search?keywords=solaar&searchon=names&suite=all§ion=all
================================================
FILE: RELEASE.md
================================================
# Solaar releases
## Please read before making a release
We support two type of releases: normal releases (ex. `1.0.0`) and release
candidates (ex. `1.0.0rc1`). Release candidates must have a `rcX` suffix.
Release routine:
- Update version in `lib/solaar/version`
- Add release changes to `CHANGELOG.md`
- Add release information to `share/solaar/io.github.pwr_solaar.solaar.metainfo.xml`
- Create a commit that starts with `release VERSION`
- Push commit to Solaar repository
- Invoke `./release.sh`
- Git tags are signed so you must have GPG set up
- You are required to have a github token with `public_repo` access
in `~/.github-token`
================================================
FILE: RHEL.md
================================================
# Solaar installation guide for RHEL, Rocky, AlmaLinux, and CentOS Stream
This guide covers manual installation and an automated install example for
RHEL-family systems using `dnf`.
## Supported distributions
- Red Hat Enterprise Linux (RHEL)
- Rocky Linux
- AlmaLinux
- Oracle Linux
- CentOS Stream
The commands assume a minimal CLI system with `sudo` access.
## 1) Install dependencies
```bash
sudo dnf makecache --refresh
sudo dnf install -y \
git \
gtk3 \
python3 \
python3-devel \
python3-dbus \
python3-gobject \
python3-pip \
python3-psutil \
python3-pyudev \
python3-setuptools \
python3-xlib \
python3-yaml
```
Optional troubleshooting helpers:
```bash
sudo dnf install -y \
evemu \
libinput \
usbutils
```
## 2) Clone Solaar
```bash
git clone https://github.com/pwr-Solaar/Solaar.git
cd Solaar
```
## 3) Install Solaar
Install for the current user:
```bash
python3 -m pip install --user .
```
Or install system-wide:
```bash
sudo python3 -m pip install .
```
## 4) Install udev rules
Install the recommended `uinput` rule:
```bash
sudo make install_udev_uinput
```
Verify rule installation:
```bash
ls -l /etc/udev/rules.d/42-logitech-unify-permissions.rules
```
Rollback udev rule installation:
```bash
sudo make uninstall_udev
```
## 5) Run Solaar
```bash
solaar
```
or:
```bash
python3 -m solaar
```
## 6) Automated install options
Use the guided installer in this repository:
```bash
./tools/install-rhel.sh
```
Minimal non-interactive example script:
```bash
cat > install-rhel-solaar.sh <<'SCRIPT'
#!/usr/bin/env bash
set -euo pipefail
if [[ "${EUID}" -eq 0 ]]; then
echo "Run as a regular user with sudo access, not as root."
exit 1
fi
sudo dnf makecache --refresh
sudo dnf install -y \
git \
gtk3 \
python3 \
python3-devel \
python3-dbus \
python3-gobject \
python3-pip \
python3-psutil \
python3-pyudev \
python3-setuptools \
python3-xlib \
python3-yaml
if [[ ! -d Solaar/.git ]]; then
git clone https://github.com/pwr-Solaar/Solaar.git
fi
cd Solaar
python3 -m pip install --user .
sudo make install_udev_uinput
~/.local/bin/solaar --version
SCRIPT
chmod +x install-rhel-solaar.sh
./install-rhel-solaar.sh
```
## 7) Verification
```bash
command -v solaar
solaar --version
python3 -m pip show solaar
```
If installed with `--user`, ensure `~/.local/bin` is on your `PATH`:
```bash
echo "$PATH" | tr ':' '\n' | grep -Fx "$HOME/.local/bin" >/dev/null || \
echo 'Add ~/.local/bin to PATH'
```
## 8) Troubleshooting
Receiver not detected:
```bash
lsusb | grep -Ei 'logitech|046d'
sudo udevadm trigger
```
Check access to hidraw devices:
```bash
ls -l /dev/hidraw*
getfacl /dev/hidraw* 2>/dev/null | sed -n '1,80p'
```
================================================
FILE: Release_Notes.md
================================================
# Notes on Major Changes in Releases
## Version 1.1.18
* Solaar is only guaranteed to work in Python 3.13 or later.
## Version 1.1.17
* Several new features have been added related to the MX Master 4
* The scroll ratchet force can be adjusted
* The force required to click the button under your thumb can be adjusted
* The haptic force can be adjusted
* Haptic feeback can be triggered by commands like `solaar config 'mx master 4' haptic-play 'HAPPY ALER'`
## Version 1.1.16
* Two bugs that were affecting users in 1.1.15 are fixed.
## Version 1.1.15
* 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.
* Device and Action rule conditions match on device codename and name
* Solaar supports configuration of Bluetooth devices on macOS.
## Version 1.1.13
* Solaar will drop support for Python 3.7 immediately after version 1.1.13.
* 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.
## Version 1.1.12
* 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.
* 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.
* 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`
* A unit test test suite is being constructed using pytest.
* 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.
* The Later rule action uses precision timing for delays of less than one second.
* 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.
## Version 1.1.11
* 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.
* Solaar has settings for each LED Zone that a device supports under feature Color LED Effects.
* Solaar has settings for extended report rate, backlight levels, durations, and profile selection.
* 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.
* Solaar works better when the Python package hid-parser is available. Distriubtions should try have this package installed.
## Version 1.1.10
* The mouse click rule action can now just simulate depressing or releasing the button.
* There is a new rule condition to check the hostname.
## Version 1.1.9
* Solaar now exits with at 0 exit code when killed.
* 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.
* The Device rule condition checks for the device that produced a notification.
* The KeyIsDown rule condition checks whether a *diverted* rule key is down.
## Version 1.1.8
* The thumb wheel rule conditions take an optional parameter that checks for total signed thumb wheel movement.
## Version 1.1.7
* Solaar responds to scroll wheel ratchet notifications by changing its scroll wheel ratcheting.
* Solaar processing of report descriptors is optional, depending on whether the package hid-parser is available.
## Version 1.1.6
* Solaar requires Python version 3.7.
* Solaar uses report descriptors to recognize unknown devices that use HID++.
* 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.
## Version 1.1.5
* 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.
* 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.
* 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.
* 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.
* 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.
## Version 1.1.4
* There are settings for sidetone and equalizer gains for headsets.
* The KeyPress action can now either deppress, release, or click (default) keys.
* 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.
## Version 1.1.3
* Solaar uses yaml for configuration files, converting the json configuration file to yaml if necessary.
* Solaar rules work better under Wayland but still cannot access the current process nor the current keyboard modifiers.
* Solaar uses uinput for simulating input in Wayland. See https://pwr-solaar.github.io/Solaar/rules for instructions on setting up uinput correctly.
## Version 1.1.2
* 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.
* 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.
* There is a setting to divert gestures so that they can trigger rules.
* 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.
* There is a setting for the Persistent Remappable Keys feature.
* There is a new rule condition that tests device settings.
* There are new settings to set M-Key LEDs and MR-Key LED.
* There is a new kind of Solaar rule action to change settings for devices.
## Version 1.1.1
* There is a new setting to switch keyboard crowns between smooth and ratchet scrolling.
## Version 1.1.0
* Solaar now supports Bolt receivers and devices that connect to them, including authentication of devices when pairing.
* A setting has been added for the DPI CHANGE button to switch movement sensitivity.
## Version 1.0.7
* Solaar rules can now trigger on both pressing and releasing a diverted key.
* The new rule condition MouseProcess is like the Process condition except for the process of the window under the mouse.
* 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.
## Version 1.0.6
* The sliding DPI setting now looks for suitable keys to use to trigger its effects.
* 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.
* 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.
* Icon handling in the tray and the tray menu has been updated to work better with some system tray implementations.
* The process rule condition also matches against the current X11 WM_CLASS.
* The SMART SHIFT ENHANCED feature is supported.
## Version 1.0.5
* 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.
* Each setting has a clickable lock icon that determines whether the setting can be changed.
## Version 1.0.4
* 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.
* There are new settings for gestures, thumb wheels, adjusting the wheel ratchet behavior, and changing DPI using a DPI Switch button.
* 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.
## Version 1.0.3
* The separate deprecated solaar-cli command has been removed.
* 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.
## Version 1.0.2
* The separate unneeded solaar-gnome3 command has been removed. The packaging directories have been removed.
* Non-unifying receivers are modelled better. Many of them cannot unpair but instead new pairings replace existing pairings.
* Battery icon selection has been simplified.
================================================
FILE: bin/solaar
================================================
#!/usr/bin/env python3
# -*- python-mode -*-
# -*- coding: UTF-8 -*-
## Copyright (C) 2012-2013 Daniel Pavel
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
def init_paths():
"""Make the app work in the source tree."""
import os.path
import sys
root = os.path.join(os.path.realpath(sys.path[0]), "..")
prefix = os.path.normpath(root)
src_lib = os.path.join(prefix, "lib")
share_lib = os.path.join(prefix, "share", "solaar", "lib")
for location in src_lib, share_lib:
init_py = os.path.join(location, "solaar", "__init__.py")
if os.path.exists(init_py):
sys.path[0] = location
break
if __name__ == "__main__":
init_paths()
import solaar.gtk
solaar.gtk.main()
================================================
FILE: docs/.gitignore
================================================
# ignore documentation-specific files
.jekyll-metadata
Gemfile
Gemfile.lock
_site/
================================================
FILE: docs/LICENSE.txt
================================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
<https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The 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.
When 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.
To 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.
For 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.
We 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.
Also, 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.
Finally, 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.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. 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".
Activities 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.
1. 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.
You 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.
2. 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:
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
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.
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.)
These 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.
Thus, 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.
In 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.
3. 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:
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,
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,
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.)
The 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.
If 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.
4. 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.
5. 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.
6. 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.
7. 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.
If 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.
It 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.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
8. 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.
9. 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.
Each 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.
10. 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.
NO WARRANTY
11. 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.
12. 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.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If 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.
To 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.
one line to give the program's name and an idea of what it does.
Copyright (C) yyyy name of author
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see
<https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
type `show w'. This is free software, and you are welcome
to redistribute it under certain conditions; type `show c'
for details.
The 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.
You 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:
Yoyodyne, Inc., hereby disclaims all copyright
interest in the program `Gnomovision'
(which makes passes at compilers) written
by James Hacker.
signature of Moe Ghoul, 1 April 1989
Moe Ghoul, President of Vice
This 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.
================================================
FILE: docs/README.text
================================================
# Documentation Readme
This project's documentation is hosted using GitHub pages, which serves static pages using Jekyll.
[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/)
================================================
FILE: docs/capabilities.md
================================================
---
title: Solaar Capabilities
layout: page
---
# Solaar Capabilities
[**Solaar**][solaar] reports on and controls [Logitech][logitech] devices
(keyboards, mice, and trackballs) that connect to your computer via a
Logitech USB receiver (a very small piece of hardware that plugs into one of
your USB ports).
Solaar is designed to detect all connected devices,
and at the very least display some basic information about them.
At this moment, all [Unifying][unifying] receivers are supported (e.g., devices
with USB ID `046d:c52b` or `046d:c532`) as are several Lightspeed Receivers
and many Nano receivers.
Solaar also reports on and controls some Logitech devices that directly connect
to your computer using a USB cable or via Bluetooth.
Not all such devices supported in Solaar as information needs to be added to Solaar
for each device type that directly connects.
## HID++
The devices that Solaar handles use Logitech's HID++ protocol.
HID++ is a Logitech-proprietary protocol that extends the standard HID
protocol for interfacing with receivers, keyboards, mice, and so on. It allows
Logitech receivers to communicate with multiple devices and modify some
features of the device. As the HID++ protocol is
proprietary, many aspects of it are unknown. Some information about HID++
has been obtained from Logitech but even that is subject to change and
extension.
There are several versions of HID++ and many Logitech
receivers and devices that utilize it. Different receivers and devices
implement different portions of HID++ so even if two devices appear to be
the same in both physical appearance and behavior they may work
differently underneath. (For example, there are versions of the
M510 mouse that use different versions of the HID++ protocol.)
Contrariwise, two different devices may appear different physically but
actually look the same to software. (For example, some M185 mice look the
same to software as some M310 mice.)
The software identity of a receiver can be determined by its USB product ID
(reported by Solaar and also viewable in Linux using `lsusb`). The software
identity of a device that connects to a receiver can be determined by
its wireless PID as reported by Solaar. The software identity of devices that
connect via a USB cable or via bluetooth can be determined by their USB or
Bluetooth product ID.
## Pairing and Unpairing
Solaar is able to pair and unpair devices with
receivers as supported by the device and receiver.
For Unifying and Bolt receivers, pairing adds a new paired device, but
only if there is an open slot on the receiver. So these receivers need to
be able to unpair devices that they have been paired with or else they will
not have any open slots for pairing. Some Nano and Lightspeed receivers, like the
Nano receiver with USB ID `046d:c534`, can only pair with one keyboard and one mouse
and pairing a new device replaces whatever device of that kind was
previously paired to the receiver. These receivers cannot unpair. Further,
some receivers can pair an unlimited number of times but others can only
pair a limited number of times.
Bolt receivers add an authentication phase to pairing,
where the user has type a passcode or click some buttons to authenticate the device.
Only some connections between receivers and devices are possible. It should
be possible to connect any device with a Unifying logo on it to any receiver
with a Unifying logo on it and any device with a Bolt logo on it to any receiver
with a Bolt logo on it.
Many receivers without the Unifying or Bolt logo
can connect only to the model of devices they were bought with and many devices
without the Unifying or Bolt logo can only connect to a receiver
that matches the one they were bought with.
## Device Settings
Solaar can display quite a few changeable settings of receivers and devices.
For a list of HID++ features and their support see [the features page](features.md).
Solaar does not do much beyond using the HID++ protocol to change the
behavior of receivers and devices via changing their settings.
In particular, Solaar cannot change how
the operating system turns the keycodes that a keyboard produces into
characters that are sent to programs. That is the province of HID device
drivers and other software (such as X11).
Settings can only be changed in the Solaar GUI when they are unlocked.
To unlock a setting click on the icon at the right-hand edge of the setting
until an unlocked lock appears (with tooltop "Changes allowed").
Solaar keeps track of most of the changeable settings of a device.
Devices forget most changed settings when the device is turned off
or goes into a power-saving mode.
Exceptions include the setting to change the host the device is connected to,
the setting to persistently change what a key or button does,
and, for some devices, the fn-swap setting.
When Solaar starts, it restores on-line devices to their previously-known state
except for host connection and persistent key and button changes and while running Solaar restores
devices to their previously-known state when the device itself comes on line.
Setting information is stored in the file `~/.config/solaar/config.yaml`.
Updating of a setting can be turned off in the Solaar GUI by clicking on the icon
at the right-hand edge of the setting until a red icon appears (with tooltip
"Ignore this setting").
Solaar keeps track of settings independently on each computer.
As a result if a device is switched between different computers
Solaar may apply different settings for it on the different computers.
Querying a device for its current state can require quite a few HID++
interactions. These interactions can temporarily slow down the device, so
Solaar tries to internally cache information about devices while it is
running. If the device
state is changed by some other means, even sometimes by another invocation
of Solaar, this cached information may become incorrect. Currently there is
no way to force an update of the cached information besides restarting Solaar.
Logitech receivers and devices have firmware in them. Some firmware
can be updated using Logitech software in Windows. For example, there are
security issues with some Logitech receivers and devices and Logitech has
firmware updates to alleviate these problems. Some Logitech firmware can
also be updated in Linux using `fwupdmgr`.
WARNING: Updating firmware can cause a piece of hardware to become
permanently non-functional if something goes wrong with the update or the
update installs the wrong firmware.
## Other Solaar Capabilities
Solaar has a few capabilities that go beyond simply changing device settings.
### Rule-based Processing of HID++ Notifications
Solaar can process HID++ Notifications from devices to, for example,
change the speed of some thumb wheels. These notifications are only sent
for actions that are set in Solaar to their HID++ setting (also known as diverted).
For more information on this capability of Solaar see
[the rules page](https://pwr-solaar.github.io/Solaar/rules).
Users can edit rules using a GUI by clicking on the `Rule Editor` button in the Solaar main window.
### Sliding DPI
A few mice (such as the MX Vertical) have a button that is supposed to be used to change
the sensitivity (DPI) of the mouse by pressing the button and moving the mouse left and right.
Other mice (such as the MX Master 3) don't have a button specific for this purpose
but have buttons that can be used for it.
The `Key/Button Diversion` setting can assign buttons to adjust sensitivity by setting the value for the button to `Sliding DPI`.
This capability is only present if the device supports changing the DPI in this way.
Pressing a button when it is set to `Sliding DPI` causes the mouse pointer to stop moving.
When the button is released a new Sensitivity (DPI) value is applied to the mouse,
depending on how far right or left the mouse is moved. If the mouse is moved only a little bit
the previous value that was set is applied to the mouse.
Notifications from Solaar are displayed showing the setting that will be applied.
### Mouse Gestures
Some mice (such as the MX Master 3) have a button that is supposed to be used to
create up/down/left/right mouse gestures. Other mice (such as the MX Vertical) don't
have a button specific for this purpose but have buttons that can be used for it.
The `Key/Button Diversion` setting can assign buttons to initiate mouse gestures by setting the value for the button to `Mouse Gestures`.
This capability is only present if the device can support it.
Pressing a button when it is set to `Mouse Gestures` causes the mouse pointer to stop moving.
When the button is released a `MOUSE_GESTURE` notification with the mouse movements and diverted key presses
is sent to the Solaar rule system so that rules can detect these notifications.
For more information on Mouse Gestures rule conditions see
[the rules page](https://pwr-solaar.github.io/Solaar/rules).
### Keyboard Key Names and Locations
Solaar 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.
Solaar 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:
Z: 25
Y: 26
This is an experimental feature and may be modified or even eliminated.
### Onboard Profiles
Some 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.
When 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.
Solaar 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.
A profile file has some bookkeeping information, including profile version and the name of the device, and a sequence of profiles.
Each profile has the following fields:
- enabled: Whether the profile is enabled.
- 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).
- name: A memonic name for the profile.
- report_rate: A report rate in milliseconds from 1 to 8.
- resolutions: A sequence of five sensor resolutions in DPI.
- resolution_default_index: The index of the default sensor resolution (0 to 4).
- resolution_shift_index: The index of the sensor resolution used when the DPI Shift button is pressed (0 to 4).
- buttons: The action for each button on the mouse in normal mode.
- gbuttons: The action for each button on the mouse in G-Shift mode.
- angle_snap: Enable angle snapping for devices.
- red, blue, green: Color indicator for the profile.
- lighting: Lighting information for logo and side LEDs in normal mode, then for power saving mode.
- ps_timeout: Delay in ms to go into power saving mode.
- po_timeout: Delay in ms to go from power saving mode to fully off.
- power_mode: Unknown purpose.
- write count: Unknown purpose.
Missing or unused parts of a profile are often a sequence of 0xFF bytes.
Button actions can either perform a function (behavior: 9) or send a button click or key press (behaviour: 8).
Functions are:
- 0: No Action - do nothing
- 1: Tilt Left
- 2: Tilt Right
- 3: Next DPI - change device resolution to the next DPI
- 4: Previous DPI - change device resolution to the previous DPI
- 5: Cycle DPI - change device resolution to the next DPI considered as a cycle
- 6: Default_DPI - change device resolution to the default resolution
- 7: Shift_DPI - change device resolution to the shift resolution
- 8: Next Profile - change to the next enabled profile
- 9: Previous Profile - change to the previous enabled profile
- 10: Cycle Profile - change to the next enabled profile considered as a cycle
- 11: G-Shift - change all buttons to their G-Shift state
- 12: Battery Status - show battery status on the device LEDs
- 13: Profile Select - select the n'th enabled profile
- 14: Mode Switch
- 15: Host Button - switch between hosts (unverified)
- 16: Scroll Down
- 17: Scroll Up
Some devices might not be able to perform all functions.
Buttons can send (type):
- 0: Don't send anything.
- 1: A button click (value) as a 16-bit bitmap, i.e., 1 is left click, 2 is right, 4 is middle, etc.
- 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.
- 3: A 16-bit HID Consumer keycode (value).
See USB_HID_KEYCODES and HID_CONSUMERCODES in lib/logitech_receiver/special_keys.py for values to use for keycodes.
Buttons can also execute macros but Solaar does not provide any support for macros.
Lighting information is a sequence of lighting effects, with the first usually for the logo LEDs and the second usually for the side LEDs.
The fields possible in an effect are:
- ID: The kind of effect:
- color: A color parameter for the effect as a 24-bit RGB value.
- intensity: How intense to make the color (1%-100%), 0 for the default (usually 100%).
- speed: How fast to pulse in ms (one byte).
- ramp: How to change to the color (0=default, 1=ramp up/down, 2=no ramping).
- period: How fast to perform the effect in ms (two bytes).
- form: The form of the breathe effect.
- bytes: The raw bytes of other effects.
The possible effects and the fields the use are:
- 0x0: Disable - No fields.
- 0x1: Fixed color - color, whether to ramp.
- 0x2: Pulse a color - color, speed.
- 0x3 Cycle through the spectrum - period, intensity, form.
- 0x8; A boot effect - No fields.
- 0x9: A demo effect - NO fields.
- 0xa: breathe a color (like pulse) - color, period.
- 0xb: Ripple - color, period.
- null: An unknown effect.
Only effects supported by the device can be used.
To 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.
Keep 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.
## System Tray
Solaar's GUI normally uses an icon in the system tray.
This allows users to close Solaar and reopen from the tray.
This aspect of Solaar depends on having an active system tray which may
require some special setup when using Gnome, particularly under Wayland.
If you are running Gnome, you most likely need the
`gnome-shell-extension-appindicator` package installed.
In Fedora, this can be done by running
```
sudo dnf install gnome-shell-extension-appindicator
```
The likely command in Ubuntu and related distributions is
```
sudo apt install gnome-shell-extension-appindicator
```
You may have to log out and log in again before the system tray shows up.
## Battery Icons
For many devices, Solaar shows the approximate battery level via icons that
show up in both the main window and the system tray. In previous versions
several heuristics determined which icon names to use for this purpose,
but as more and more battery icon schemes have been developed this has
become impossible to do well. Solaar now uses the eleven standard
battery icon names `battery-{full,good,low,critical,empty}[-charging]` and
`battery-missing`.
Solaar will use the symbolic versions of these icons if started with the
option `--battery-icons=symbolic`. Because of external bugs,
these symbolic icons may be nearly invisible in dark themes.
[solaar]: https://github.com/pwr-Solaar/Solaar
[logitech]: https://www.logitech.com
[unifying]: https://en.wikipedia.org/wiki/Logitech_Unifying_receiver
================================================
FILE: docs/debian.md
================================================
---
title: Debian Repository
layout: page
---
# Debian repository
Solaar 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`
================================================
FILE: docs/devices/00README.txt
================================================
Files in this directory are edited output from `solaar show` providing
information about devices and receivers that Solaar supports. This
directory does not contain information about all devices and receivers that
Solaar supports. Information is generally only added when provided in a
Solaar issue.
Directions for constructing the files are given below. The files
Unifying Receiver C52B.txt
Craft Advanced Keyboard 4066.txt
Craft Advanced Keyboard B350.txt
MX Master 3 Wireless Mouse 4082.txt
MX Master 3 Wireless Mouse B023.txt
are good examples of following the directions below.
File Naming
Logitech device names are often reused so the names of files can't just be
the device name. File names start with the name of the device or receiver
as given in the first line of of output for the device. The file name
continues with a space and the WPID, if the device is connected to a
receiver, or the second half of the USB ID, if the device is connected via
USB or Bluetooth. The WPID or USB ID are in upper case. As devices can
behave differently when connected via a receiver or USB or Bluetooth there
should be a file for each possible connection method.
Files that do not follow this naming convention are retained for historical purposes.
File Contents
Each file should contain the output of `solaar show NAME` where NAME
is enough of the full name of a device or receiver to identify it.
The output of `solaar show` will provide information on all connnected
devices and receivers including their names.
The output of `solaar show NAME` can be edited
to remove serial numbers and variable information such as the current values
of settings.
Passing the style requirements for Solaar documentation may require removing
trailing white space on lines.
For older devices probes of the device registers should be
included but for newer devices this is not necessary.
Unifying receivers can pair with any device that has the Unifying logo.
Bolt receivers can pair with any device that has the Bolt logo.
Nano and Lightspeed receivers can only pair with certain devices,
so the end of their files should state the devices that they have
been seen to be paired with or are part of.
Updating Files
Newer versions of Solaar add support for more settings so it is useful to
provide updated versions of these files if there is information from the
current version of `solaar show NAME` that is not in the existing file.
================================================
FILE: docs/devices/Bluetooth Multi-Device Keyboard K380 B342.txt
================================================
Solaar version 1.1.4
1: Bluetooth Multi-Device Keyboard K380
Device path : /dev/hidraw5
USB id : 046d:B342
Codename : Keyboard K380
Kind : ?
Protocol : HID++ 4.5
Serial number:
Model ID: B34200000000
Unit ID: 16000000
Firmware: RBK 42.01.B0017
Hardware: 72
Supports 14 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
Firmware: Firmware RBK 42.01.B0017 B342C18DBFDD
Firmware: Hardware 72
Unit ID: 16000000 Model ID: B34200000000 Transport IDs: {'btid': 'B342'}
3: DEVICE NAME {0005}
Name: Bluetooth Multi-Device Keyboard K380
Kind: keyboard
4: DEVICE FRIENDLY NAME {0007}
Friendly Name: Keyboard K380
5: RESET {0020}
6: BATTERY STATUS {1000}
Battery: 20%, discharging, next level 5%.
7: CHANGE HOST {1814}
Change Host : 1:Luay-A
8: HOSTS INFO {1815}
Host 0 (paired): Luay-A
Host 1 (paired): BCM20703A2 Generic UART UHE App
Host 2 (unpaired):
9: REPROG CONTROLS V4 {1B04}
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}
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}
10: unknown:1E00 {1E00} hidden
11: NEW FN INVERSION {40A2}
Fn-swap: disabled
Fn-swap default: enabled
Swap Fx function (saved): False
Swap Fx function : False
12: LOCK KEY STATE {4220}
13: KEYBOARD DISABLE KEYS {4521}
Disable keys (saved): {Caps Lock:False, Scroll Lock:False, Insert:True, Win:False}
Disable keys : {Caps Lock:False, Scroll Lock:False, Insert:True, Win:False}
Has 16 reprogrammable keys:
0: Multiplatform Home , default: MultiPlatform Home => MultiPlatform Home
is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, group mask:empty
reporting: default
1: Multiplatform App Switch , default: MultiPlatform App Switch => MultiPlatform App Switch
is FN, FN sensitive, reprogrammable, divertable, pos:5, group:0, group mask:empty
reporting: default
2: Multiplatform Menu , default: MultiPlatform Menu => MultiPlatform Menu
is FN, FN sensitive, reprogrammable, divertable, pos:6, group:0, group mask:empty
reporting: diverted
3: Multiplatform Back , default: MultiPlatform Back => MultiPlatform Back
is FN, FN sensitive, reprogrammable, divertable, pos:7, group:0, group mask:empty
reporting: default
4: Previous , default: Previous => Previous
is FN, FN sensitive, divertable, pos:8, group:0, group mask:empty
reporting: default
5: Play/Pause , default: Play/Pause => Play/Pause
is FN, FN sensitive, divertable, pos:9, group:0, group mask:empty
reporting: default
6: Next , default: Next => Next
is FN, FN sensitive, divertable, pos:10, group:0, group mask:empty
reporting: default
7: Mute , default: Mute => Mute
is FN, FN sensitive, divertable, pos:11, group:0, group mask:empty
reporting: default
8: Volume Down , default: Volume Down => Volume Down
is FN, FN sensitive, divertable, pos:12, group:0, group mask:empty
reporting: default
9: Volume Up , default: Volume Up => Volume Up
is FN, FN sensitive, divertable, pos:0, group:0, group mask:empty
reporting: default
10: Multiplatform Insert , default: Switch Language => Switch Language
FN sensitive, reprogrammable, divertable, pos:0, group:0, group mask:empty
reporting: default
11: Fn Up , default: unknown:0070 => unknown:0070
is FN, divertable, pos:0, group:0, group mask:empty
reporting: default
12: Fn Down , default: unknown:006F => unknown:006F
is FN, divertable, pos:0, group:0, group mask:empty
reporting: default
13: Screen Capture/Print Screen, default: Screen Capture => Screen Capture
is FN, reprogrammable, divertable, pos:0, group:0, group mask:empty
reporting: default
14: Search , default: Search Files => Search Files
is FN, reprogrammable, divertable, pos:0, group:0, group mask:empty
reporting: default
15: Multiplatform Lock , default: WindowsLock => WindowsLock
is FN, reprogrammable, divertable, pos:0, group:0, group mask:empty
reporting: default
Battery: 20%, discharging, next level 5%.
================================================
FILE: docs/devices/Bolt Receiver C548.txt
================================================
Solaar version 1.1.4
Bolt Receiver
Device path : /dev/hidraw8
USB id : 046d:C548
Serial : 38423638313332394241363434313837
Has 2 paired device(s) out of a maximum of 6.
Notifications: wireless, software present (0x000900)
Device activity counters: 1=252, 2=135
================================================
FILE: docs/devices/Candy companion chip 405F.txt
================================================
7: Candy companion chip
Device path : /dev/hidraw11
Codename : Candy
Kind : touchpad
Protocol : HID++ 4.2
Serial number: 5B2B9A98
Model ID: 405F00000000
Unit ID: 32314707
Firmware: CC 07.00.B0010
Bootloader: BOT 32.00.B0010
Supports 11 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
Firmware: Firmware CC 07.00.B0010 405F
Firmware: Bootloader BOT 32.00.B0010 405F
Unit ID: 32314707 Model ID: 405F00000000 Transport IDs: {'wpid': '405F'}
3: DEVICE NAME {0005}
Name: Candy companion chip
Kind: touchpad
4: unknown:18A1 {18A1} internal, hidden
5: unknown:1E00 {1E00} hidden
6: unknown:1EB0 {1EB0} internal, hidden
7: DFUCONTROL SIGNED {00C2}
8: unknown:1801 {1801} internal, hidden
9: DEVICE RESET {1802} internal, hidden
10: unknown:1803 {1803} internal, hidden
Battery status unavailable.
Part of the G PowerPlay Wireless Mouse Pad.
================================================
FILE: docs/devices/Couch Mouse M515 4007.txt
================================================
1: Couch Mouse M515
Codename : M515
Kind : mouse
Wireless PID : 4007
Protocol : HID++ 2.0
Polling rate : 8 ms
Serial number: BED587E9
Firmware: RQM 24.00.B0023
Bootloader: DFU 00.02.B0010
The power switch is located on the base.
Supports 16 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: DFUCONTROL {00C0}
5: BATTERY STATUS {1000}
6: unknown:1A30 {1A30} hidden
7: REPROG CONTROLS {1B00}
8: WIRELESS DEVICE STATUS {1D4B}
9: unknown:1DF3 {1DF3} hidden
10: VERTICAL SCROLLING {2100}
11: HI RES SCROLLING {2120}
12: MOUSE POINTER {2200}
13: unknown:1F02 {1F02} hidden
14: unknown:1F03 {1F03} hidden
15: unknown:1E80 {1E80} hidden
Has 5 reprogrammable keys:
0: LEFT CLICK => LeftClick mse, reprogrammable
1: RIGHT CLICK => RightClick mse, reprogrammable
2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable
3: BACK AS BUTTON 4 => BackEx mse, reprogrammable
4: FORWARD AS BUTTON 5 => BrowserForwardEx mse, reprogrammable
Battery: 65%, discharging,
================================================
FILE: docs/devices/Craft Advanced Keyboard 4066.txt
================================================
Solaar version 1.1.4
2: Craft Advanced Keyboard
Device path : /dev/hidraw4
WPID : 4066
Codename : Craft
Kind : keyboard
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
Serial number: 112C46EA
Model ID: B35040660000
Unit ID: 43DAF041
Bootloader: BOT 41.01.B0015
Firmware: MPK 07.01.B0015
Other:
Other:
The power switch is located on the edge of top right corner.
Supports 38 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
Firmware: Bootloader BOT 41.01.B0015 0000B6A2C54601
Firmware: Firmware MPK 07.01.B0015 4066B6A2C54601
Firmware: Other
Firmware: Other
Unit ID: 43DAF041 Model ID: B35040660000 Transport IDs: {'btleid': 'B350', 'wpid': '4066'}
3: DEVICE NAME {0005}
Name: Craft Advanced Keyboard
Kind: keyboard
4: WIRELESS DEVICE STATUS {1D4B}
5: RESET {0020}
6: DEVICE FRIENDLY NAME {0007}
Friendly Name: Keyboard Craft
7: BATTERY STATUS {1000}
Battery: 50%, discharging, next level 20%.
8: CHANGE HOST {1814}
Change Host : 1:idefix
9: HOSTS INFO {1815}
Host 0 (paired): idefix
Host 1 (paired): idefix
Host 2 (paired): Galaxy Tab S6
10: BACKLIGHT2 {1982}
Backlight (saved): True
Backlight : True
11: REPROG CONTROLS V4 {1B04}
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}
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}
12: PERSISTENT REMAPPABLE ACTION {1C00}
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}
13: K375S FN INVERSION {40A3}
Swap Fx function (saved): True
Swap Fx function : True
14: ENCRYPTION {4100}
15: LOCK KEY STATE {4220}
16: KEYBOARD DISABLE KEYS {4521}
Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}
Disable keys : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}
17: MULTIPLATFORM {4531}
Set OS (saved): Windows
Set OS : Windows
18: CROWN {4600}
Crown smooth scroll (saved): False
Crown smooth scroll : False
Divert crown events (saved): True
Divert crown events : True
19: DFUCONTROL SIGNED {00C2}
20: unknown:1803 {1803} internal, hidden
21: CONFIG DEVICE PROPS {1806} internal, hidden
22: unknown:1813 {1813} internal, hidden
23: OOBSTATE {1805} internal, hidden
24: unknown:1830 {1830} internal, hidden
25: unknown:1890 {1890} internal, hidden
26: unknown:1891 {1891} internal, hidden
27: unknown:1801 {1801} internal, hidden
28: unknown:18A1 {18A1} internal, hidden
29: unknown:9280 {9280} internal, hidden
30: unknown:1A20 {1A20} internal, hidden
31: unknown:1DF3 {1DF3} internal, hidden
32: unknown:1E00 {1E00} hidden
33: unknown:1EB0 {1EB0} internal, hidden
34: unknown:1861 {1861} internal, hidden
35: unknown:18B0 {18B0} internal, hidden
36: unknown:92C0 {92C0} internal, hidden
37: unknown:9203 {9203} internal, hidden
Has 24 reprogrammable keys:
0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1
nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2
nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: diverted
2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3
nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: diverted
3: Brightness Down , default: Brightness Down => Brightness Down
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:1, group:0, group mask:empty
reporting: default
4: Brightness Up , default: Brightness Up => Brightness Up
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:2, group:0, group mask:empty
reporting: default
5: Mission Control/Task View , default: Mission Control/Task View => Mission Control/Task View
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:3, group:0, group mask:empty
reporting: default
6: Dashboard Launchpad/Action Center, default: Dashboard Launchpad/Action Center => Dashboard Launchpad/Action Center
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty
reporting: default
7: Show Desktop , default: Show Desktop => Show Desktop
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:5, group:0, group mask:empty
reporting: diverted
8: Backlight Down , default: Backlight Down => Backlight Down
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:6, group:0, group mask:empty
reporting: default
9: Backlight Up , default: Backlight Up => Backlight Up
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:7, group:0, group mask:empty
reporting: default
10: Previous Fn , default: Previous => Previous
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:8, group:0, group mask:empty
reporting: default
11: Play/Pause Fn , default: Play/Pause => Play/Pause
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:9, group:0, group mask:empty
reporting: default
12: Next Fn , default: Next => Next
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:10, group:0, group mask:empty
reporting: default
13: Mute Fn , default: Mute => Mute
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, group mask:empty
reporting: default
14: Volume Down Fn , default: Volume Down => Volume Down
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, group mask:empty
reporting: default
15: Volume Up Fn , default: Volume Up => Volume Up
nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
16: Calculator , default: Calculator => Calculator
nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
17: Screen Capture/Print Screen, default: Screen Capture => Screen Capture
nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
18: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu
nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
19: Lock PC , default: WindowsLock => WindowsLock
nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
20: Left Arrow , default: Keyboard Left Arrow => Keyboard Left Arrow
nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
21: Right Arrow , default: Keyboard Right Arrow => Keyboard Right Arrow
nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
22: F Lock , default: Do Nothing One => Do Nothing One
is FN, pos:0, group:0, group mask:empty
reporting: default
23: FN Key , default: Do Nothing One => Do Nothing One
nonstandard, pos:0, group:0, group mask:empty
reporting: default
Has 17 persistent remappable keys:
0: Brightness Down => Consumer: Brightness Down (remapped)
1: Brightness Up => Consumer: Brightness Up (remapped)
2: Mission Control/Task View => Key: Meta+TAB
3: Dashboard Launchpad/Action Center => Key: Meta+A
4: Show Desktop => Key: Meta+D
5: Backlight Down => None
6: Backlight Up => None
7: Previous Fn => Consumer: Scan Previous Track
8: Play/Pause Fn => Consumer: Play/Pause
9: Next Fn => Consumer: Scan Next Track
10: Mute Fn => Consumer: Mute
11: Volume Down Fn => Key: No Output (remapped)
12: Volume Up Fn => Consumer: Volume Up
13: Calculator => Consumer: AL Calculator
14: Screen Capture/Print Screen => Key: SYSRQ
15: App Contextual Menu/Right Click => Key: COMPOSE
16: Lock PC => Key: Meta+L
Battery: 50%, discharging, next level 20%.
================================================
FILE: docs/devices/Craft Advanced Keyboard B350.txt
================================================
Solaar version 1.1.4
1: Craft Advanced Keyboard
Device path : /dev/hidraw5
USB id : 046d:B350
Codename : Craft
Kind : keyboard
Protocol : HID++ 4.5
Serial number:
Model ID: B35040660000
Unit ID: 43DAF041
Bootloader: BOT 41.01.B0015
Firmware: MPK 07.01.B0015
Other:
Other:
Supports 33 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
Firmware: Bootloader BOT 41.01.B0015 0000B6A2C54601
Firmware: Firmware MPK 07.01.B0015 B350B6A2C54601
Firmware: Other
Firmware: Other
Unit ID: 43DAF041 Model ID: B35040660000 Transport IDs: {'btleid': 'B350', 'wpid': '4066'}
3: DEVICE NAME {0005}
Name: Craft Advanced Keyboard
Kind: keyboard
4: WIRELESS DEVICE STATUS {1D4B}
5: RESET {0020}
6: DEVICE FRIENDLY NAME {0007}
Friendly Name: Keyboard Craft
7: BATTERY STATUS {1000}
Battery: 50%, discharging, next level 20%.
8: CHANGE HOST {1814}
Change Host : 2:idefix
9: HOSTS INFO {1815}
Host 0 (paired): idefix
Host 1 (paired): idefix
Host 2 (paired): Galaxy Tab S6
10: BACKLIGHT2 {1982}
Backlight (saved): True
Backlight : True
11: REPROG CONTROLS V4 {1B04}
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}
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}
12: PERSISTENT REMAPPABLE ACTION {1C00}
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}
13: K375S FN INVERSION {40A3}
Swap Fx function (saved): True
Swap Fx function : True
14: ENCRYPTION {4100}
15: LOCK KEY STATE {4220}
16: KEYBOARD DISABLE KEYS {4521}
Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}
Disable keys : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False}
17: MULTIPLATFORM {4531}
Set OS (saved): Windows
Set OS : Windows
18: CROWN {4600}
Crown smooth scroll (saved): False
Crown smooth scroll : False
Divert crown events (saved): True
Divert crown events : True
19: DFUCONTROL SIGNED {00C2}
20: unknown:1803 {1803} internal, hidden
21: unknown:1813 {1813} internal, hidden
22: unknown:1830 {1830} internal, hidden
23: unknown:1801 {1801} internal, hidden
24: unknown:18A1 {18A1} internal, hidden
25: unknown:1A20 {1A20} internal, hidden
26: unknown:1DF3 {1DF3} internal, hidden
27: unknown:1E00 {1E00} hidden
28: unknown:1EB0 {1EB0} internal, hidden
29: unknown:1861 {1861} internal, hidden
30: unknown:18B0 {18B0} internal, hidden
31: unknown:92C0 {92C0} internal, hidden
32: unknown:9203 {9203} internal, hidden
Has 24 reprogrammable keys:
0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1
nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2
nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: diverted
2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3
nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: diverted
3: Brightness Down , default: Brightness Down => Brightness Down
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:1, group:0, group mask:empty
reporting: default
4: Brightness Up , default: Brightness Up => Brightness Up
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:2, group:0, group mask:empty
reporting: default
5: Mission Control/Task View , default: Mission Control/Task View => Mission Control/Task View
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:3, group:0, group mask:empty
reporting: default
6: Dashboard Launchpad/Action Center, default: Dashboard Launchpad/Action Center => Dashboard Launchpad/Action Center
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty
reporting: default
7: Show Desktop , default: Show Desktop => Show Desktop
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:5, group:0, group mask:empty
reporting: diverted
8: Backlight Down , default: Backlight Down => Backlight Down
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:6, group:0, group mask:empty
reporting: default
9: Backlight Up , default: Backlight Up => Backlight Up
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:7, group:0, group mask:empty
reporting: default
10: Previous Fn , default: Previous => Previous
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:8, group:0, group mask:empty
reporting: default
11: Play/Pause Fn , default: Play/Pause => Play/Pause
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:9, group:0, group mask:empty
reporting: default
12: Next Fn , default: Next => Next
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:10, group:0, group mask:empty
reporting: default
13: Mute Fn , default: Mute => Mute
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, group mask:empty
reporting: default
14: Volume Down Fn , default: Volume Down => Volume Down
is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, group mask:empty
reporting: default
15: Volume Up Fn , default: Volume Up => Volume Up
nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
16: Calculator , default: Calculator => Calculator
nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
17: Screen Capture/Print Screen, default: Screen Capture => Screen Capture
nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
18: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu
nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
19: Lock PC , default: WindowsLock => WindowsLock
nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
20: Left Arrow , default: Keyboard Left Arrow => Keyboard Left Arrow
nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
21: Right Arrow , default: Keyboard Right Arrow => Keyboard Right Arrow
nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty
reporting: default
22: F Lock , default: Do Nothing One => Do Nothing One
is FN, pos:0, group:0, group mask:empty
reporting: default
23: FN Key , default: Do Nothing One => Do Nothing One
nonstandard, pos:0, group:0, group mask:empty
reporting: default
Has 17 persistent remappable keys:
0: Brightness Down => None
1: Brightness Up => None
2: Mission Control/Task View => Key: Meta+TAB
3: Dashboard Launchpad/Action Center => Key: Meta+A
4: Show Desktop => Key: Meta+D
5: Backlight Down => None
6: Backlight Up => None
7: Previous Fn => Consumer: Scan Previous Track
8: Play/Pause Fn => Consumer: Play/Pause
9: Next Fn => Consumer: Scan Next Track
10: Mute Fn => Consumer: Mute
11: Volume Down Fn => Consumer: Volume Down
12: Volume Up Fn => Consumer: Volume Up
13: Calculator => Consumer: AL Calculator
14: Screen Capture/Print Screen => Key: SYSRQ
15: App Contextual Menu/Right Click => Key: COMPOSE
16: Lock PC => Key: Meta+L
Battery: 50%, discharging, next level 20%.
================================================
FILE: docs/devices/ERGO M575 Trackball 4096.txt
================================================
Solaar version 1.1.4
1: ERGO M575 Trackball
Device path : /dev/hidraw5
WPID : 4096
Codename : ERGO M575
Kind : mouse
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
Serial number: 460DFDC2
Model ID: B02740960000
Unit ID: 460DFDC2
Bootloader: BOT 40.00.B0009
Firmware: MPM 26.00.B0009
Other:
The power switch is located on the base.
Supports 25 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
Firmware: Bootloader BOT 40.00.B0009 0000ABF1CB8B01
Firmware: Firmware MPM 26.00.B0009 4096ABF1CB8B01
Firmware: Other
Unit ID: 460DFDC2 Model ID: B02740960000 Transport IDs: {'btleid': 'B027', 'wpid': '4096'}
3: DEVICE NAME {0005}
Name: ERGO M575 Trackball
Kind: trackball
4: WIRELESS DEVICE STATUS {1D4B}
5: RESET {0020}
6: DEVICE FRIENDLY NAME {0007}
Friendly Name: ERGO M575
7: UNIFIED BATTERY {1004}
8: REPROG CONTROLS V4 {1B04}
DPI Sliding Adjustment (saved): Off
DPI Sliding Adjustment : Off
Mouse Gestures (saved): Off
Mouse Gestures : Off
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}
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}
Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular}
Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular}
9: ADJUSTABLE DPI {2201}
Sensitivity (DPI) (saved): 500
Sensitivity (DPI) : 500
10: XY STATS {2250}
11: DFUCONTROL SIGNED {00C2}
12: DEVICE RESET {1802} internal, hidden
13: unknown:1803 {1803} internal, hidden
14: CONFIG DEVICE PROPS {1806} internal, hidden
15: unknown:1812 {1812} internal, hidden
16: OOBSTATE {1805} internal, hidden
17: unknown:1830 {1830} internal, hidden
18: unknown:1890 {1890} internal, hidden
19: unknown:1891 {1891} internal, hidden
20: unknown:18A1 {18A1} internal, hidden
21: unknown:1E00 {1E00} hidden
22: unknown:1EB0 {1EB0} internal, hidden
23: unknown:1861 {1861} internal, hidden
24: unknown:1E22 {1E22} internal, hidden
Has 6 reprogrammable keys:
0: Left Button , default: Left Click => Left Click
mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1
reporting: default
1: Right Button , default: Right Click => Right Click
mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1
reporting: default
2: Middle Button , default: Mouse Middle Button => Mouse Middle Button
mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2
reporting: default
3: Forward Button , default: Mouse Forward Button => Mouse Forward Button
mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2
reporting: default
4: Back Button , default: Mouse Back Button => Mouse Back Button
mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2
reporting: default
5: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button
divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty
reporting: default
Battery: 85%, discharging.
================================================
FILE: docs/devices/EX100 Receiver 27 Mhz C517.text
================================================
solaar version 1.1.11-80-gdea496f
EX100 Receiver 27 Mhz
Device path : /dev/hidraw2
USB id : 046d:C517
Serial : None
Has 2 paired device(s) out of a maximum of 4.
Notifications: wireless (0x000100)
1: Wireless Mouse EX100
Device path : /dev/hidraw3
WPID : 003F
Codename : EX100m
Kind : mouse
Protocol : HID++ 1.0
Serial number:
The power switch is located on the (unknown).
Notifications: roller V, mouse extra buttons, battery status, roller H (0x3C0000).
Battery: good, discharging.
3: Wireless Keyboard EX100
Device path : /dev/hidraw6
WPID : 0065
Codename : EX100
Kind : keyboard
Protocol : HID++ 1.0
Serial number:
The power switch is located on the (unknown).
Notifications: keyboard multimedia raw, battery status (0x110000).
Battery: good, discharging.
Register Dump
Notifications 0x00: 0x000100
Connection State 0x02: 0x000100
Device Activity 0xb3: None
Pairing Register 0xb5 0x00: None
Pairing Register 0xb5 0x01: None
Pairing Register 0xb5 0x02: None
Pairing Register 0xb5 0x03: None
Pairing Register 0xb5 0x04: None
Pairing Register 0xb5 0x05: None
Pairing Register 0xb5 0x06: None
Pairing Register 0xb5 0x07: None
Pairing Register 0xb5 0x08: None
Pairing Register 0xb5 0x09: None
Pairing Register 0xb5 0x0a: None
Pairing Register 0xb5 0x0b: None
Pairing Register 0xb5 0x0c: None
Pairing Register 0xb5 0x0d: None
Pairing Register 0xb5 0x0e: None
Pairing Register 0xb5 0x0f: None
Pairing Register 0xb5 0x10: None
Pairing Register 0xb5 0x20: None
Pairing Register 0xb5 0x30: None
Pairing Register 0xb5 0x50: None
Pairing Name 0xb5 0x40: None
Pairing Name 0xb5 0x60 0x1: 0 None
Pairing Name 0xb5 0x60 0x2: 0 None
Pairing Name 0xb5 0x60 0x3: 0 None
Pairing Register 0xb5 0x11: None
Pairing Register 0xb5 0x21: None
Pairing Register 0xb5 0x31: None
Pairing Register 0xb5 0x51: None
Pairing Name 0xb5 0x41: None
Pairing Name 0xb5 0x61 0x1: 0 None
Pairing Name 0xb5 0x61 0x2: 0 None
Pairing Name 0xb5 0x61 0x3: 0 None
Pairing Register 0xb5 0x12: None
Pairing Register 0xb5 0x22: None
Pairing Register 0xb5 0x32: None
Pairing Register 0xb5 0x52: None
Pairing Name 0xb5 0x42: None
Pairing Name 0xb5 0x62 0x1: 0 None
Pairing Name 0xb5 0x62 0x2: 0 None
Pairing Name 0xb5 0x62 0x3: 0 None
Pairing Register 0xb5 0x13: None
Pairing Register 0xb5 0x23: None
Pairing Register 0xb5 0x33: None
Pairing Register 0xb5 0x53: None
Pairing Name 0xb5 0x43: None
Pairing Name 0xb5 0x63 0x1: 0 None
Pairing Name 0xb5 0x63 0x2: 0 None
Pairing Name 0xb5 0x63 0x3: 0 None
Pairing Register 0xb5 0x14: None
Pairing Register 0xb5 0x24: None
Pairing Register 0xb5 0x34: None
Pairing Register 0xb5 0x54: None
Pairing Name 0xb5 0x44: None
Pairing Name 0xb5 0x64 0x1: 0 None
Pairing Name 0xb5 0x64 0x2: 0 None
Pairing Name 0xb5 0x64 0x3: 0 None
Pairing Register 0xb5 0x15: None
Pairing Register 0xb5 0x25: None
Pairing Register 0xb5 0x35: None
Pairing Register 0xb5 0x55: None
Pairing Name 0xb5 0x45: None
Pairing Name 0xb5 0x65 0x1: 0 None
Pairing Name 0xb5 0x65 0x2: 0 None
Pairing Name 0xb5 0x65 0x3: 0 None
Pairing Register 0xb5 0x16: None
Pairing Register 0xb5 0x26: None
Pairing Register 0xb5 0x36: None
Pairing Register 0xb5 0x56: None
Pairing Name 0xb5 0x46: None
Pairing Name 0xb5 0x66 0x1: 0 None
Pairing Name 0xb5 0x66 0x2: 0 None
Pairing Name 0xb5 0x66 0x3: 0 None
Firmware 0xf1 0x00: None
Firmware 0xf1 0x01: None
Firmware 0xf1 0x02: None
Firmware 0xf1 0x03: None
Firmware 0xf1 0x04: None
Register Short 0x00 0x00: 0x000100
Register Long 0x00 0x00: invalid SubID/command
...
Register Long 0x00 0xfe: invalid SubID/command
Register Short 0x01 0x00: 0x000200
Register Long 0x01 0x00: invalid SubID/command
Register Long 0x01 0x01: invalid SubID/command
Register Long 0x01 0x02: invalid SubID/command
...
./scan-registers.sh ff /dev/hidraw4
# Old notification flags: 000100
>> ( 0.035) [10 FF 8100 000100] '\x10\xff\x81\x00\x00\x01\x00'
<< ( 0.015) [10 FF 8101 000000] '\x10\xff\x81\x01\x00\x00\x00'
>> ( 0.020) [10 FF 8101 000200] '\x10\xff\x81\x01\x00\x02\x00'
<< ( 0.030) [10 FF 8102 000000] '\x10\xff\x81\x02\x00\x00\x00'
>> ( 0.036) [10 FF 8102 000200] '\x10\xff\x81\x02\x00\x02\x00'
--
<< ( 0.142) [10 FF 8109 000000] '\x10\xff\x81\t\x00\x00\x00'
>> ( 0.148) [10 FF 8109 010000] '\x10\xff\x81\t\x01\x00\x00'
--
<< ( 1.790) [10 FF 8170 000000] '\x10\xff\x81p\x00\x00\x00'
>> ( 1.796) [10 FF 8170 012100] '\x10\xff\x81p\x01!\x00'
<< ( 1.806) [10 FF 8171 000000] '\x10\xff\x81q\x00\x00\x00'
>> ( 1.812) [10 FF 8171 011200] '\x10\xff\x81q\x01\x12\x00'
--
<< ( 1.838) [10 FF 8173 000000] '\x10\xff\x81s\x00\x00\x00'
>> ( 1.844) [10 FF 8173 643F00] '\x10\xff\x81sd?\x00'
--
<< ( 2.046) [10 FF 8180 000000] '\x10\xff\x81\x80\x00\x00\x00'
>> ( 2.052) [10 FF 8180 030000] '\x10\xff\x81\x80\x03\x00\x00'
--
<< ( 3.326) [10 FF 81D0 000000] '\x10\xff\x81\xd0\x00\x00\x00'
>> ( 3.332) [10 FF 81D0 000000] '\x10\xff\x81\xd0\x00\x00\x00'
devices
01 mouse
Red button pressed
>> ( 1676.106) [10 01 0810 000000] '\x10\x01\x08\x10\x00\x00\x00'
>> ( 1676.114) [10 01 4600 000021] '\x10\x01F\x00\x00\x00!'
>> ( 1676.122) [10 FF 4600 211100] '\x10\xffF\x00!\x11\x00'
Power lewel?
?? Input: 10 01 81 07 00 00 00
<< ( 1739.032) [10 01 8107 000000] '\x10\x01\x81\x07\x00\x00\x00'
>> ( 1739.040) [10 01 8107 030000] '\x10\x01\x81\x07\x03\x00\x00'
[10 01 8107 070000] '\x10\x01\x81\x07\x07\x00\x00'
power change
>> ( 2441.563) [10 01 0703 000000] '\x10\x01\x07\x03\x00\x00\x00'
>> ( 100.159) [10 01 0707 000000] '\x10\x01\x07\x07\x00\x00\x00'
enable power event
<< ( 59.190) [10 01 8000 100000] '\x10\x01\x80\x00\x10\x00\x00'
>> ( 59.193) [10 01 8000 000000] '\x10\x01\x80\x00\x00\x00\x00'
03 keyboard
Power level?
?? Input: 10 03 81 07 00 00 00
<< ( 1777.961) [10 03 8107 000000] '\x10\x03\x81\x07\x00\x00\x00'
>> ( 1777.967) [10 03 8107 070000] '\x10\x03\x81\x07\x07\x00\x00'
power on
>> ( 1571.805) [10 03 0810 000000] '\x10\x03\x08\x10\x00\x00\x00'
>> ( 1574.709) [10 03 0800 000000] '\x10\x03\x08\x00\x00\x00\x00'
red button pressed
>> ( 1619.043) [10 03 0810 000000] '\x10\x03\x08\x10\x00\x00\x00'
>> ( 1619.051) [10 03 4600 000011] '\x10\x03F\x00\x00\x00\x11'
>> ( 1619.059) [10 FF 4600 221100] '\x10\xffF\x00"\x11\x00'
>> ( 1621.747) [10 03 0800 000000] '\x10\x03\x08\x00\x00\x00\x00'
Fn pressed
>> ( 1651.715) [10 03 032C 100000] '\x10\x03\x03,\x10\x00\x00'
>> ( 1652.170) [10 03 0300 000000] '\x10\x03\x03\x00\x00\x00\x00'
Battery status:
1.9V critical
2.3V low
2.5V full
================================================
FILE: docs/devices/G Pro Wireless Gaming Mouse 4079.txt
================================================
Solaar version 1.1.4rc1
1: G Pro Wireless Gaming Mouse
Device path : /dev/hidraw10
WPID : 4079
Codename : G Pro
Kind : mouse
Protocol : HID++ 4.2
Polling rate : 2 ms (500Hz)
Serial number: 40B217C0
Model ID: 4079C0880000
Unit ID: 40B217C0
Bootloader: BOT 74.02.B0026
Firmware: MPM 15.02.B0026
Other:
The power switch is located on the base.
Supports 28 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
Firmware: Bootloader BOT 74.02.B0026 AADF85EE714A
Firmware: Firmware MPM 15.02.B0026 407985EE714A
Firmware: Other
Unit ID: 40B217C0 Model ID: 4079C0880000 Transport IDs: {'wpid': '4079', 'usbid': 'C088'}
3: DEVICE NAME {0005}
Name: G Pro Wireless Gaming Mouse
Kind: mouse
4: WIRELESS DEVICE STATUS {1D4B}
5: RESET {0020}
6: BATTERY VOLTAGE {1001}
Battery: 3926mV, discharging, 70.
7: COLOR LED EFFECTS {8070}
8: LED CONTROL {1300}
9: ONBOARD PROFILES {8100}
Device Mode: On-Board
Onboard Profiles (saved): Enable
Onboard Profiles : Enable
10: MOUSE BUTTON SPY {8110}
11: REPORT RATE {8060}
Polling Rate (ms): 2
Polling Rate (ms) (saved): 2
Polling Rate (ms) : 2
12: ADJUSTABLE DPI {2201}
Sensitivity (DPI) (saved): 1600
Sensitivity (DPI) : 1600
13: DEVICE RESET {1802} internal, hidden
14: unknown:1803 {1803} internal, hidden
15: OOBSTATE {1805} internal, hidden
16: CONFIG DEVICE PROPS {1806} internal, hidden
17: unknown:1811 {1811} internal, hidden
18: unknown:1830 {1830} internal, hidden
19: unknown:1890 {1890} internal, hidden
20: unknown:1891 {1891} internal, hidden
21: unknown:18A1 {18A1} internal, hidden
22: unknown:1801 {1801} internal, hidden
23: unknown:18B1 {18B1} internal, hidden
24: unknown:1DF3 {1DF3} internal, hidden
25: unknown:1E00 {1E00} hidden
26: unknown:1EB0 {1EB0} internal, hidden
27: unknown:1863 {1863} internal, hidden
Battery: 3926mV, discharging, 70.
================================================
FILE: docs/devices/G213 Prodigy Gaming Keyboard C366.txt
================================================
Solaar version 1.1.5rc1
USB and Bluetooth Devices
1: G213 Prodigy Gaming Keyboard
Device path : /dev/hidraw2
USB id : 046d:C336
Codename : G213
Kind : keyboard
Protocol : HID++ 4.2
Polling rate : 1 ms (1000Hz)
Serial number:
Model ID: C33600000000
Unit ID: 31314709
Firmware: U1 09.00.B0006
Bootloader: BOT 31.00.B0002
Supports 15 HID++ 2.0 features:
0: ROOT {0000} V0
1: FEATURE SET {0001} V0
2: DEVICE FW VERSION {0003} V2
Firmware: Firmware U1 09.00.B0006 C336
Firmware: Bootloader BOT 31.00.B0002 AAC8
Unit ID: 31314709 Model ID: C33600000000 Transport IDs: {'usbid': 'C336'}
3: KEYBOARD DISABLE BY USAGE {4522} V0
4: DEVICE NAME {0005} V0
Name: Gaming Keyboard G213
Kind: keyboard
5: unknown:1E00 {1E00} V0 hidden
6: KEYBOARD LAYOUT 2 {4540} V0
7: unknown:1EB0 {1EB0} V0 internal, hidden
8: REPORT RATE {8060} V0
Polling Rate (ms): 1
Polling Rate (ms) : 1
9: DFUCONTROL SIGNED {00C2} V0
10: unknown:1801 {1801} V0 internal, hidden
11: DEVICE RESET {1802} V0 internal, hidden
12: COLOR LED EFFECTS {8070} V5
13: unknown:1821 {1821} V0
14: REPORT HID USAGE {1BC0} V0
Battery: N/A, None.
================================================
FILE: docs/devices/G304 Lightspeed Wireless Gaming Mouse 4074.txt
================================================
solaar version 1.1.8
1: G304 Lightspeed Wireless Gaming Mouse
Device path : /dev/hidraw6
WPID : 4074
Codename : G304
Kind : mouse
Protocol : HID++ 4.2
Polling rate : 8 ms (125Hz)
Serial number: B2D05D23
Model ID: 407400000000
Unit ID: EB490C63
Bootloader: BOT 69.02.B0021
Firmware: RQM 68.02.B0021
The power switch is located on the base.
Supports 27 HID++ 2.0 features:
0: ROOT {0000} V0
1: FEATURE SET {0001} V0
2: DEVICE FW VERSION {0003} V2
Firmware: Bootloader BOT 69.02.B0021 4074452F3940
Firmware: Firmware RQM 68.02.B0021 4074452F3940
Unit ID: EB490C63 Model ID: 407400000000 Transport IDs: {'wpid': '4074'}
3: DEVICE NAME {0005} V0
Name: G304 Lightspeed Wireless Gaming Mouse
Kind: mouse
4: WIRELESS DEVICE STATUS {1D4B} V0
5: BATTERY STATUS {1000} V0
Battery: 90%, discharging, next level 50%.
6: COLOR LED EFFECTS {8070} V6
7: ONBOARD PROFILES {8100} V0
Device Mode: Host
Onboard Profiles (saved): Disable
Onboard Profiles : Disable
8: MOUSE BUTTON SPY {8110} V0
9: REPORT RATE {8060} V0
Polling Rate (ms): 8
Polling Rate (ms) (saved): 8
Polling Rate (ms) : 8
10: MODE STATUS {8090} V1
11: DFUCONTROL SIGNED {00C2} V0
12: DEVICE RESET {1802} V0 internal, hidden
13: unknown:1803 {1803} V0 internal, hidden
14: CONFIG DEVICE PROPS {1806} V4 internal, hidden
15: unknown:1811 {1811} V0 internal, hidden
16: OOBSTATE {1805} V0 internal, hidden
17: unknown:1830 {1830} V0 internal, hidden
18: unknown:1890 {1890} V0 internal, hidden
19: unknown:1DF3 {1DF3} V0 internal, hidden
20: unknown:1E00 {1E00} V0 hidden
21: unknown:1EB0 {1EB0} V0 internal, hidden
22: unknown:1861 {1861} V0 internal, hidden
23: unknown:18B1 {18B1} V0 internal, hidden
24: unknown:1E22 {1E22} V0 internal, hidden
25: unknown:1801 {1801} V0 internal, hidden
26: ADJUSTABLE DPI {2201} V1
Sensitivity (DPI) (saved): 2200
Sensitivity (DPI) : 2200
Battery: 90%, discharging, next level 50%.
================================================
FILE: docs/devices/G305 Lightspeed Wireless Gaming Mouse 4074.text
================================================
solaar version 1.1.10
1: G305 Lightspeed Wireless Gaming Mouse
Device path : /dev/hidraw7
WPID : 4074
Codename : G305
Kind : mouse
Protocol : HID++ 4.2
Polling rate : 1 ms (1000Hz)
Serial number: ED5E9515
Model ID: 407400000000
Unit ID: F074D567
Bootloader: BOT 69.02.B0021
Firmware: RQM 68.02.B0021
The power switch is located on the base.
Supports 27 HID++ 2.0 features:
0: ROOT {0000} V0
1: FEATURE SET {0001} V0
2: DEVICE FW VERSION {0003} V2
Firmware: Bootloader BOT 69.02.B0021 4074452F3940
Firmware: Firmware RQM 68.02.B0021 4074452F3940
Unit ID: F074D567 Model ID: 407400000000 Transport IDs: {'wpid': '4074'}
3: DEVICE NAME {0005} V0
Name: G305 Lightspeed Wireless Gaming Mouse
Kind: mouse
4: WIRELESS DEVICE STATUS {1D4B} V0
5: BATTERY STATUS {1000} V0
Battery: 50%, discharging, next level 30%.
6: COLOR LED EFFECTS {8070} V6
7: ONBOARD PROFILES {8100} V0
Device Mode: On-Board
Onboard Profiles (saved): Enable
Onboard Profiles : Enable
8: MOUSE BUTTON SPY {8110} V0
9: REPORT RATE {8060} V0
Polling Rate (ms): 1
Polling Rate (ms) (saved): 1
Polling Rate (ms) : 1
10: MODE STATUS {8090} V1
11: DFUCONTROL SIGNED {00C2} V0
12: DEVICE RESET {1802} V0 internal, hidden
13: unknown:1803 {1803} V0 internal, hidden
14: CONFIG DEVICE PROPS {1806} V4 internal, hidden
15: unknown:1811 {1811} V0 internal, hidden
16: OOBSTATE {1805} V0 internal, hidden
17: unknown:1830 {1830} V0 internal, hidden
18: unknown:1890 {1890} V0 internal, hidden
19: unknown:1DF3 {1DF3} V0 internal, hidden
20: unknown:1E00 {1E00} V0 hidden
21: unknown:1EB0 {1EB0} V0 internal, hidden
22: unknown:1861 {1861} V0 internal, hidden
23: unknown:18B1 {18B1} V0 internal, hidden
24: unknown:1E22 {1E22} V0 internal, hidden
25: unknown:1801 {1801} V0 internal, hidden
26: ADJUSTABLE DPI {2201} V1
Sensitivity (DPI) (saved): 1600
Sensitivity (DPI) : 1600
Battery: 50%, discharging, next level 30%.
================================================
FILE: docs/devices/G502 Gaming Mouse C07D.text
================================================
Solaar version 1.1.5
1: G502 Gaming Mouse
Device path : /dev/hidraw1
USB id : 046d:C07D
Codename : G502
Kind : mouse
Protocol : HID++ 4.2
Polling rate : 1 ms (1000Hz)
Serial number:
Model ID: 000000000000
Unit ID: 00000000
Firmware: U 88.02.B0017
Bootloader: BOT 14.00.B0007
Hardware: 72
Other:
Supports 19 HID++ 2.0 features:
0: ROOT {0000} V0
1: FEATURE SET {0001} V0
2: FEATURE INFO {0002} V0
3: DEVICE FW VERSION {0003} V0
Firmware: Firmware U 88.02.B0017
Firmware: Bootloader BOT 14.00.B0007
Firmware: Hardware 72
Firmware: Other
Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {}
4: DEVICE NAME {0005} V0
Name: Tunable FPS Gaming Mouse G502
Kind: mouse
5: LED CONTROL {1300} V0
6: unknown:18A1 {18A1} V0 internal, hidden
7: unknown:1E00 {1E00} V0 hidden
8: unknown:1E20 {1E20} V0
9: unknown:1EB0 {1EB0} V0 internal, hidden
10: ADJUSTABLE DPI {2201} V0
Sensitivity (DPI) : 800
11: ANGLE SNAPPING {2230} V0
12: SURFACE TUNING {2240} V0
13: REPORT RATE {8060} V0
Polling Rate (ms): 1
Polling Rate (ms) : 1
14: ONBOARD PROFILES {8100} V0
Device Mode: Host
Onboard Profiles : Disable
15: MOUSE BUTTON SPY {8110} V0
16: unknown:1850 {1850} V0 internal, hidden
17: DFUCONTROL UNSIGNED {00C1} V0
18: unknown:1801 {1801} V0 internal, hidden
Battery: N/A, None.
================================================
FILE: docs/devices/G502 Lightspeed Wireless Gaming Mouse 407F.txt
================================================
solaar version 1.1.12rc1
1: G502 Gaming Mouse
Device path : /dev/hidraw20
WPID : 407F
Codename : G502
Kind : mouse
Protocol : HID++ 4.2
Report Rate : 1ms
Serial number: DDDAADBC
Model ID: 407FC08D0000
Unit ID: DDDAADBC
1: BOT 92.00.B0008
0: MPM 17.00.B0008
3:
The power switch is located on the base.
Supports 30 HID++ 2.0 features:
0: ROOT {0000} V0
1: FEATURE SET {0001} V0
2: DEVICE FW VERSION {0003} V2
Firmware: Bootloader BOT 92.00.B0008 AAEF21F1FA5F
Firmware: Firmware MPM 17.00.B0008 407F21F1FA5F
Firmware: Other
Unit ID: DDDAADBC Model ID: 407FC08D0000 Transport IDs: {'wpid': '407F', 'usbid': 'C08D'}
3: DEVICE NAME {0005} V0
Name: G502 LIGHTSPEED Wireless Gaming Mouse
Kind: mouse
4: WIRELESS DEVICE STATUS {1D4B} V0
5: CONFIG CHANGE {0020} V0
Configuration: 11000000000000000000000000000000
6: BATTERY VOLTAGE {1001} V2
Battery: 90% 4166mV , discharging.
7: COLOR LED EFFECTS {8070} V4
LED Control (saved): Device
LED Control : Device
LEDs Primary (saved): !LEDEffectSetting {ID: 1, color: 16711680, intensity: 0, period: 100, ramp: 0, speed: 0}
LEDs Primary : None
LEDs Logo : None
8: LED CONTROL {1300} V0
9: ONBOARD PROFILES {8100} V0
Device Mode: On-Board
Onboard Profiles (saved): Profile 1
Onboard Profiles : Profile 1
10: MOUSE BUTTON SPY {8110} V0
11: REPORT RATE {8060} V0
Report Rate: 1ms
Report Rate (saved): 1ms
Report Rate : 1ms
12: ADJUSTABLE DPI {2201} V1
Sensitivity (DPI) (saved): 900
Sensitivity (DPI) : 900
13: DEVICE RESET {1802} V0 internal, hidden
14: unknown:1803 {1803} V0 internal, hidden
15: OOBSTATE {1805} V0 internal, hidden
16: CONFIG DEVICE PROPS {1806} V4 internal, hidden
17: unknown:1811 {1811} V0 internal, hidden
18: unknown:1830 {1830} V0 internal, hidden
19: unknown:1890 {1890} V4 internal, hidden
20: unknown:1891 {1891} V4 internal, hidden
21: unknown:18A1 {18A1} V0 internal, hidden
22: unknown:1801 {1801} V0 internal, hidden
23: unknown:18B1 {18B1} V0 internal, hidden
24: unknown:1DF3 {1DF3} V0 internal, hidden
25: unknown:1E00 {1E00} V0 hidden
26: unknown:1EB0 {1EB0} V0 internal, hidden
27: unknown:1863 {1863} V0 internal, hidden
28: unknown:1E22 {1E22} V0 internal, hidden
29: HIRES WHEEL {2121} V0
Multiplier: 8
Has invert: Normal wheel motion
Has ratchet switch: Normal wheel mode
High resolution mode
HID notification
Scroll Wheel Direction (saved): False
Scroll Wheel Direction : False
Scroll Wheel Resolution (saved): True
Scroll Wheel Resolution : True
Scroll Wheel Diversion (saved): False
Scroll Wheel Diversion : False
Battery: 90% 4166mV , discharging.
================================================
FILE: docs/devices/G502 Proteus Spectrum Optical Mouse C332.txt
================================================
solaar version 1.1.9
2: G502 Proteus Spectrum Optical Mouse
Device path : /dev/hidraw4
USB id : 046d:C332
Codename : G502 Proteus Spectrum
Kind : mouse
Protocol : HID++ 4.2
Polling rate : 1 ms (1000Hz)
Serial number:
Model ID: C33200000000
Unit ID: 31374706
Firmware: U1 03.02.B0012
Bootloader: BOT 14.00.B0007
Supports 20 HID++ 2.0 features:
0: ROOT {0000} V0
1: FEATURE SET {0001} V0
2: COLOR LED EFFECTS {8070} V3
3: DEVICE FW VERSION {0003} V1
Firmware: Firmware U1 03.02.B0012 C332
Firmware: Bootloader BOT 14.00.B0007 AABF
Unit ID: 31374706 Model ID: C33200000000 Transport IDs: {'usbid': 'C332'}
4: DEVICE NAME {0005} V0
Name: Tunable RGB Gaming Mouse G502
Kind: mouse
5: LED CONTROL {1300} V0
6: unknown:18A1 {18A1} V0 internal, hidden
7: unknown:1E00 {1E00} V0 hidden
8: unknown:1E20 {1E20} V0
9: unknown:1EB0 {1EB0} V0 internal, hidden
10: ADJUSTABLE DPI {2201} V1
Sensitivity (DPI) (saved): 7000
Sensitivity (DPI) : 7000
11: ANGLE SNAPPING {2230} V0
12: SURFACE TUNING {2240} V0
13: REPORT RATE {8060} V0
Polling Rate (ms): 1
Polling Rate (ms) (saved): 1
Polling Rate (ms) : 1
14: ONBOARD PROFILES {8100} V0
Device Mode: On-Board
Onboard Profiles (saved): Enable
Onboard Profiles : Enable
15: MOUSE BUTTON SPY {8110} V0
16: unknown:1850 {1850} V0 internal, hidden
17: DFUCONTROL UNSIGNED {00C1} V0
18: unknown:1801 {1801} V0 internal, hidden
19: DEVICE RESET {1802} V0 internal, hidden
Battery status unavailable.
================================================
FILE: docs/devices/G502 SE Hero Gaming Mouse C08B.txt
================================================
1: G502 SE Hero Gaming Mouse
Device path : /dev/hidraw7
USB id : 046d:C08B
Codename : G502 Hero
Kind : mouse
Protocol : HID++ 4.2
Polling rate : 1 ms (1000Hz)
Serial number:
Model ID: C08B00000000
Unit ID: 30324703
Firmware: U1 27.03.B0010
Bootloader: BOT 81.00.B0002
Supports 19 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: COLOR LED EFFECTS {8070}
3: DEVICE FW VERSION {0003}
Firmware: Firmware U1 27.03.B0010 C08B
Firmware: Bootloader BOT 81.00.B0002 AAE6
Unit ID: 30324703 Model ID: C08B00000000 Transport IDs: {'usbid': 'C08B'}
4: DEVICE NAME {0005}
Name: G502 HERO Gaming Mouse
Kind: mouse
5: LED CONTROL {1300}
6: unknown:18A1 {18A1} internal, hidden
7: unknown:1E00 {1E00} hidden
8: unknown:1E22 {1E22} internal, hidden
9: unknown:1EB0 {1EB0} internal, hidden
10: ADJUSTABLE DPI {2201}
Sensitivity (DPI) (saved): 2400
Sensitivity (DPI) : 2400
11: REPORT RATE {8060}
Polling Rate (ms): 1
Polling Rate (ms) (saved): 1
Polling Rate (ms) : 1
12: ONBOARD PROFILES {8100}
Device Mode: Host
13: MOUSE BUTTON SPY {8110}
14: DFUCONTROL SIGNED {00C2}
15: unknown:1801 {1801} internal, hidden
16: DEVICE RESET {1802} internal, hidden
17: CONFIG DEVICE PROPS {1806} internal, hidden
18: unknown:18B1 {18B1} internal, hidden
Battery status unavailable.
==============
gitextract_9uiytb4r/
├── .coveragerc
├── .git-blame-ignore-revs
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ └── workflows/
│ ├── checks.yml
│ ├── gh-pages.yml
│ └── tests.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .python-version
├── CHANGELOG.md
├── COPYRIGHT
├── LICENSE.txt
├── MANIFEST.in
├── Makefile
├── README.md
├── RELEASE.md
├── RHEL.md
├── Release_Notes.md
├── bin/
│ └── solaar
├── docs/
│ ├── .gitignore
│ ├── LICENSE.txt
│ ├── README.text
│ ├── capabilities.md
│ ├── debian.md
│ ├── devices/
│ │ ├── 00README.txt
│ │ ├── Bluetooth Multi-Device Keyboard K380 B342.txt
│ │ ├── Bolt Receiver C548.txt
│ │ ├── Candy companion chip 405F.txt
│ │ ├── Couch Mouse M515 4007.txt
│ │ ├── Craft Advanced Keyboard 4066.txt
│ │ ├── Craft Advanced Keyboard B350.txt
│ │ ├── ERGO M575 Trackball 4096.txt
│ │ ├── EX100 Receiver 27 Mhz C517.text
│ │ ├── G Pro Wireless Gaming Mouse 4079.txt
│ │ ├── G213 Prodigy Gaming Keyboard C366.txt
│ │ ├── G304 Lightspeed Wireless Gaming Mouse 4074.txt
│ │ ├── G305 Lightspeed Wireless Gaming Mouse 4074.text
│ │ ├── G502 Gaming Mouse C07D.text
│ │ ├── G502 Lightspeed Wireless Gaming Mouse 407F.txt
│ │ ├── G502 Proteus Spectrum Optical Mouse C332.txt
│ │ ├── G502 SE Hero Gaming Mouse C08B.txt
│ │ ├── G502 X C099.txt
│ │ ├── G502 X PLUS 4099.txt
│ │ ├── G515 LS TKL 40B4.text
│ │ ├── G535 Wireless Gaming Headset 0AC4.txt
│ │ ├── G600 Gaming Mouse C24A.txt
│ │ ├── G604 Wireless Gaming Mouse 4085.txt
│ │ ├── G613 Wireless Mechanical Gaming Keyboard 4065.txt
│ │ ├── G703 Wired-Wireless Gaming Mouse 4070.txt
│ │ ├── G733 Gaming Headset 0AB5.text
│ │ ├── G733 Gaming Headset 0AFE.text
│ │ ├── G815 Mechanical Keyboard C33F.txt
│ │ ├── G903 LIGHTSPEED Wireless Gaming Mouse 4087.txt
│ │ ├── G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard 408E.txt
│ │ ├── G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD 407C.text
│ │ ├── G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD C33E.text
│ │ ├── G915 WIRELESS RGB Mechanical Gaming Keyboard 407E.txt
│ │ ├── G935 Gaming Headset 0A87.txt
│ │ ├── Illuminated Keyboard C318.txt
│ │ ├── Illuminated Living-Room Keyboard K830 4032.txt
│ │ ├── K850 Performance Wireless Keyboard 4062.txt
│ │ ├── K850 Performance Wireless Keyboard B34D.txt
│ │ ├── Keyboard K600 TV 4078.txt
│ │ ├── LIFT For Business B033.txt
│ │ ├── LIFT VERTICAL ERGONOMIC MOUSE B031.txt
│ │ ├── Lightspeed Receiver C539.txt
│ │ ├── Lightspeed Receiver C53A.txt
│ │ ├── Lightspeed Receiver C53D.txt
│ │ ├── Lightspeed Receiver C53F.txt
│ │ ├── Lightspeed Receiver C541.txt
│ │ ├── Lightspeed Receiver C545.txt
│ │ ├── Lightspeed Receiver C547.txt
│ │ ├── Logi Pop Keys B365.txt
│ │ ├── Logitech G933 Gaming Wireless Headset 0A5B.txt
│ │ ├── Logitech PRO X Wireless Gaming Headset 0ABA.txt
│ │ ├── M720 Triathlon Multi-Device Mouse 405E.txt
│ │ ├── M720 Triathlon Multi-Device Mouse B015.txt
│ │ ├── MX Anywhere 3 4090.txt
│ │ ├── MX Anywhere 3 B025.txt
│ │ ├── MX Anywhere 3 for Business B02D.txt
│ │ ├── MX Ergo Multi-Device Trackball 406F.txt
│ │ ├── MX Keys Keyboard 408A.txt
│ │ ├── MX Keys Keyboard B35B.txt
│ │ ├── MX Keys Mini B369.txt
│ │ ├── MX Keys S B378.text
│ │ ├── MX Keys for Business B363.text
│ │ ├── MX Master 3 Wireless Mouse 4082.txt
│ │ ├── MX Master 3 Wireless Mouse B023.txt
│ │ ├── MX Master 3 for Business B028.text
│ │ ├── MX Master 3S B034.txt
│ │ ├── MX Master 4.text
│ │ ├── MX Mechanical B366.txt
│ │ ├── MX Mechanical Mini B367.txt
│ │ ├── MX Vertical Wireless Mouse 407B.txt
│ │ ├── MX Vertical Wireless Mouse B020.txt
│ │ ├── Marathon Mouse M705 101B.txt
│ │ ├── Marathon Mouse M705 406D.txt
│ │ ├── Multi Device Silent Mouse M585-M590 406B.txt
│ │ ├── Nano Receiver C52F.txt
│ │ ├── Nano Receiver C534.txt
│ │ ├── Nano Receiver C535.txt
│ │ ├── Number Pad N545 2006.txt
│ │ ├── PRO X 2 40A9.text
│ │ ├── PRO X Wireless 4093.txt
│ │ ├── Rechargeable Trackpad T651 B00C.txt
│ │ ├── Signature M550.text
│ │ ├── Signature M650 L Mouse B02A.txt
│ │ ├── Unifying Receiver C52B.txt
│ │ ├── Wireless All-in-One Keyboard TK820 4102.txt
│ │ ├── Wireless Illuminated Keyboard K800 2010.txt
│ │ ├── Wireless Illuminated Keyboard K800 new 406E.txt
│ │ ├── Wireless Keyboard 4075.txt
│ │ ├── Wireless Keyboard Dell KB714 4015.txt
│ │ ├── Wireless Keyboard K220 4005.txt
│ │ ├── Wireless Keyboard K230 400D.txt
│ │ ├── Wireless Keyboard K270(unifying) 4003.txt
│ │ ├── Wireless Keyboard K360 4004.txt
│ │ ├── Wireless Keyboard K470 4075.txt
│ │ ├── Wireless Keyboard K520 2011.txt
│ │ ├── Wireless Keyboard MK270 4023.txt
│ │ ├── Wireless Mobile Mouse MX Anywhere 2 4072.txt
│ │ ├── Wireless Mobile Mouse MX Anywhere 2S 406A.txt
│ │ ├── Wireless Mobile Mouse MX Anywhere 2S B01A.txt
│ │ ├── Wireless Mouse 4022.txt
│ │ ├── Wireless Mouse Dell WM514 4029.txt
│ │ ├── Wireless Mouse M185 new 4054.txt
│ │ ├── Wireless Mouse M185,M235,M310 4055.txt
│ │ ├── Wireless Mouse M185.text
│ │ ├── Wireless Mouse M215 2nd Gen 401B.txt
│ │ ├── Wireless Mouse M310 M310t 4031.txt
│ │ ├── Wireless Mouse M325 400A.txt
│ │ ├── Wireless Mouse M345 4017.txt
│ │ ├── Wireless Mouse M510 1025.txt
│ │ ├── Wireless Mouse M510 4051.txt
│ │ ├── Wireless Mouse M525 4013.txt
│ │ ├── Wireless Mouse M560 402D.txt
│ │ ├── Wireless Mouse MX Anywhere 2 404A.txt
│ │ ├── Wireless Mouse MX Master 2S 4069.txt
│ │ ├── Wireless Mouse MX Master 2S B019.txt
│ │ ├── Wireless Mouse MX Master 4041.txt
│ │ ├── Wireless Mouse MX Master 4071.txt
│ │ ├── Wireless Mouse MX Master B012.txt
│ │ ├── Wireless Mouse Pebble M350 4080.txt
│ │ ├── Wireless Multi-Device Keyboard K780 405B.txt
│ │ ├── Wireless Rechargeable Touchpad T650 4101.txt
│ │ ├── Wireless Solar Keyboard K750 4002.txt
│ │ ├── Wireless Touch Keyboard K400 4024.txt
│ │ ├── Wireless Touch Keyboard K400 Plus 404D.txt
│ │ ├── Wireless Trackball M570 1028.txt
│ │ ├── Zone Touch Mouse T400 4026.txt
│ │ ├── anywhere-mx.txt
│ │ ├── mk700.txt
│ │ └── performance-mx.txt
│ ├── devices.md
│ ├── features.md
│ ├── hidpp-documentation.txt
│ ├── i18n.md
│ ├── implementation.md
│ ├── index.md
│ ├── installation.md
│ ├── issues.md
│ ├── rules.md
│ ├── uninstallation.md
│ ├── usage.md
│ └── usb.ids.txt
├── lib/
│ ├── hid_parser/
│ │ ├── __init__.py
│ │ └── data.py
│ ├── hidapi/
│ │ ├── __init__.py
│ │ ├── common.py
│ │ ├── hidapi_impl.py
│ │ ├── hidconsole.py
│ │ └── udev_impl.py
│ ├── keysyms/
│ │ ├── __init__.py
│ │ ├── generate.py
│ │ └── keysymdef.py
│ ├── logitech_receiver/
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── base_usb.py
│ │ ├── common.py
│ │ ├── descriptors.py
│ │ ├── desktop_notifications.py
│ │ ├── device.py
│ │ ├── diversion.py
│ │ ├── exceptions.py
│ │ ├── hidpp10.py
│ │ ├── hidpp10_constants.py
│ │ ├── hidpp20.py
│ │ ├── hidpp20_constants.py
│ │ ├── i18n.py
│ │ ├── listener.py
│ │ ├── notifications.py
│ │ ├── receiver.py
│ │ ├── settings.py
│ │ ├── settings_new.py
│ │ ├── settings_templates.py
│ │ ├── settings_validator.py
│ │ └── special_keys.py
│ └── solaar/
│ ├── __init__.py
│ ├── cli/
│ │ ├── __init__.py
│ │ ├── config.py
│ │ ├── pair.py
│ │ ├── probe.py
│ │ ├── profiles.py
│ │ ├── show.py
│ │ └── unpair.py
│ ├── configuration.py
│ ├── custom_logger.py
│ ├── dbus.py
│ ├── gtk.py
│ ├── i18n.py
│ ├── listener.py
│ ├── tasks.py
│ ├── ui/
│ │ ├── __init__.py
│ │ ├── about/
│ │ │ ├── __init__.py
│ │ │ ├── about.py
│ │ │ ├── model.py
│ │ │ ├── presenter.py
│ │ │ └── view.py
│ │ ├── action.py
│ │ ├── common.py
│ │ ├── config_panel.py
│ │ ├── desktop_notifications.py
│ │ ├── diversion_rules.py
│ │ ├── icons.py
│ │ ├── pair_window.py
│ │ ├── rule_actions.py
│ │ ├── rule_base.py
│ │ ├── rule_conditions.py
│ │ ├── tray.py
│ │ └── window.py
│ └── version
├── mkdocs.yml
├── po/
│ ├── README
│ ├── ca.po
│ ├── cs.po
│ ├── da.po
│ ├── de.po
│ ├── el.po
│ ├── es.po
│ ├── fi.po
│ ├── fr.po
│ ├── hr.po
│ ├── id.po
│ ├── it.po
│ ├── ja.po
│ ├── ka.po
│ ├── nb.po
│ ├── nl.po
│ ├── nn.po
│ ├── pl.po
│ ├── pt.po
│ ├── pt_BR.po
│ ├── ro.po
│ ├── ru.po
│ ├── sk.po
│ ├── solaar.pot
│ ├── sr.po
│ ├── sv.po
│ ├── tr.po
│ ├── uk.po
│ ├── zh_CN.po
│ └── zh_TW.po
├── pyproject.toml
├── release.sh
├── rules.d/
│ └── 42-logitech-unify-permissions.rules
├── rules.d-uinput/
│ └── 42-logitech-unify-permissions.rules
├── setup.py
├── share/
│ ├── README
│ ├── applications/
│ │ └── solaar.desktop
│ ├── autostart/
│ │ └── solaar.desktop
│ └── solaar/
│ └── io.github.pwr_solaar.solaar.metainfo.xml
├── tests/
│ ├── __init__.py
│ ├── hid_parser/
│ │ ├── __init__.py
│ │ └── test_data.py
│ ├── hidapi/
│ │ ├── __init__.py
│ │ └── test_hidapi.py
│ ├── logitech_receiver/
│ │ ├── __init__.py
│ │ ├── fake_hidpp.py
│ │ ├── test_base.py
│ │ ├── test_base_usb.py
│ │ ├── test_common.py
│ │ ├── test_desktop_notifications.py
│ │ ├── test_device.py
│ │ ├── test_diversion.py
│ │ ├── test_hidpp10.py
│ │ ├── test_hidpp20_complex.py
│ │ ├── test_hidpp20_simple.py
│ │ ├── test_notifications.py
│ │ ├── test_receiver.py
│ │ ├── test_setting_templates.py
│ │ └── test_settings_validator.py
│ ├── solaar/
│ │ ├── test_gtk.py
│ │ └── ui/
│ │ ├── test_about_dialog.py
│ │ ├── test_common.py
│ │ ├── test_desktop_notifications.py
│ │ ├── test_i18n.py
│ │ ├── test_pair_window.py
│ │ └── test_probe.py
│ └── test_keysyms/
│ ├── __init__.py
│ └── test_keysymdef.py
└── tools/
├── clean.sh
├── create-macos-app.sh
├── create-macos-launchagent.sh
├── hidconsole
├── install-rhel.sh
├── po-compile.sh
├── po-update.sh
└── scan-registers.sh
SYMBOL INDEX (2129 symbols across 83 files)
FILE: lib/hid_parser/__init__.py
class HIDWarning (line 29) | class HIDWarning(Warning):
class HIDComplianceWarning (line 33) | class HIDComplianceWarning(HIDWarning):
class HIDReportWarning (line 37) | class HIDReportWarning(HIDWarning):
class HIDUnsupportedWarning (line 41) | class HIDUnsupportedWarning(HIDWarning):
class Type (line 45) | class Type:
class TagMain (line 51) | class TagMain:
class TagGlobal (line 59) | class TagGlobal:
class TagLocal (line 74) | class TagLocal:
function _data_bit_shift (line 87) | def _data_bit_shift(data: Sequence[int], offset: int, length: int) -> Se...
class BitNumber (line 124) | class BitNumber(int):
method __init__ (line 125) | def __init__(self, value: int):
method __int__ (line 128) | def __int__(self) -> int:
method __eq__ (line 131) | def __eq__(self, other: Any) -> bool:
method byte (line 138) | def byte(self) -> int:
method bit (line 145) | def bit(self) -> int:
method _param_repr (line 157) | def _param_repr(value: int, unit: str) -> str:
method __repr__ (line 162) | def __repr__(self) -> str:
class Usage (line 178) | class Usage:
method __init__ (line 179) | def __init__(
method __int__ (line 193) | def __int__(self) -> int:
method __eq__ (line 196) | def __eq__(self, other: Any) -> bool:
method __hash__ (line 201) | def __hash__(self) -> int:
method __repr__ (line 204) | def __repr__(self) -> str:
method usage_types (line 219) | def usage_types(self) -> Tuple[hid_parser.data.UsageTypes]:
class UsageValue (line 234) | class UsageValue:
method __init__ (line 235) | def __init__(self, item: MainItem, value: int):
method __int__ (line 239) | def __int__(self) -> int:
method __repr__ (line 242) | def __repr__(self) -> str:
method value (line 246) | def value(self) -> Union[int, bool]:
method constant (line 250) | def constant(self) -> bool:
method data (line 254) | def data(self) -> bool:
method relative (line 258) | def relative(self) -> bool:
method absolute (line 262) | def absolute(self) -> bool:
class VendorUsageValue (line 266) | class VendorUsageValue(UsageValue):
method __init__ (line 267) | def __init__(
method __int__ (line 282) | def __int__(self) -> int:
method __iter__ (line 285) | def __iter__(self) -> Iterator[int]:
method value (line 289) | def value(self) -> Union[int, bool]:
method list (line 293) | def list(self) -> List[int]:
class BaseItem (line 297) | class BaseItem:
method __init__ (line 298) | def __init__(self, offset: int, size: int):
method offset (line 303) | def offset(self) -> BitNumber:
method size (line 307) | def size(self) -> BitNumber:
method __repr__ (line 310) | def __repr__(self) -> str:
class PaddingItem (line 314) | class PaddingItem(BaseItem):
class MainItem (line 318) | class MainItem(BaseItem):
method __init__ (line 319) | def __init__(
method offset (line 338) | def offset(self) -> BitNumber:
method size (line 342) | def size(self) -> BitNumber:
method logical_min (line 346) | def logical_min(self) -> int:
method logical_max (line 350) | def logical_max(self) -> int:
method physical_min (line 354) | def physical_min(self) -> Optional[int]:
method physical_max (line 358) | def physical_max(self) -> Optional[int]:
method constant (line 364) | def constant(self) -> bool:
method data (line 368) | def data(self) -> bool:
method relative (line 372) | def relative(self) -> bool:
method absolute (line 376) | def absolute(self) -> bool:
class VariableItem (line 380) | class VariableItem(MainItem):
method __init__ (line 393) | def __init__(
method __repr__ (line 413) | def __repr__(self) -> str:
method parse (line 416) | def parse(self, data: Sequence[int]) -> UsageValue:
method usage (line 437) | def usage(self) -> Usage:
method wrap (line 443) | def wrap(self) -> bool:
method linear (line 447) | def linear(self) -> bool:
method preferred_state (line 451) | def preferred_state(self) -> bool:
method null_state (line 455) | def null_state(self) -> bool:
method buffered_bytes (line 459) | def buffered_bytes(self) -> bool:
method bitfield (line 463) | def bitfield(self) -> bool:
class ArrayItem (line 467) | class ArrayItem(MainItem):
method __init__ (line 489) | def __init__(
method __repr__ (line 520) | def __repr__(self) -> str:
method parse (line 541) | def parse(self, data: Sequence[int]) -> Dict[Usage, UsageValue]:
method count (line 570) | def count(self) -> int:
method usages (line 574) | def usages(self) -> List[Usage]:
class InvalidReportDescriptor (line 578) | class InvalidReportDescriptor(Exception):
class ReportDescriptor (line 586) | class ReportDescriptor:
method __init__ (line 587) | def __init__(self, data: Sequence[int]) -> None:
method data (line 603) | def data(self) -> Sequence[int]:
method input_report_ids (line 607) | def input_report_ids(self) -> List[Optional[int]]:
method output_report_ids (line 611) | def output_report_ids(self) -> List[Optional[int]]:
method feature_report_ids (line 615) | def feature_report_ids(self) -> List[Optional[int]]:
method _get_report_size (line 618) | def _get_report_size(self, items: List[BaseItem]) -> BitNumber:
method get_input_items (line 627) | def get_input_items(self, report_id: Optional[int] = None) -> List[Bas...
method get_input_report_size (line 631) | def get_input_report_size(self, report_id: Optional[int] = None) -> Bi...
method get_output_items (line 634) | def get_output_items(self, report_id: Optional[int] = None) -> List[Ba...
method get_output_report_size (line 638) | def get_output_report_size(self, report_id: Optional[int] = None) -> B...
method get_feature_items (line 641) | def get_feature_items(self, report_id: Optional[int] = None) -> List[B...
method get_feature_report_size (line 645) | def get_feature_report_size(self, report_id: Optional[int] = None) -> ...
method _parse_report_items (line 648) | def _parse_report_items(self, items: List[BaseItem], data: Sequence[in...
method _parse_report (line 665) | def _parse_report(self, item_poll: _ITEM_POOL, data: Sequence[int]) ->...
method parse_input_report (line 671) | def parse_input_report(self, data: Sequence[int]) -> Dict[Usage, Usage...
method parse_output_report (line 674) | def parse_output_report(self, data: Sequence[int]) -> Dict[Usage, Usag...
method parse_feature_report (line 677) | def parse_feature_report(self, data: Sequence[int]) -> Dict[Usage, Usa...
method _iterate_raw (line 680) | def _iterate_raw(self) -> Iterable[Tuple[int, int, Optional[int]]]:
method _append_item (line 712) | def _append_item(
method _append_items (line 725) | def _append_items(
method _parse (line 780) | def _parse(self, level: int = 0, file: TextIO = sys.stdout) -> None: ...
method _get_main_item_desc (line 922) | def _get_main_item_desc(value: int) -> str:
method print (line 939) | def print(self, level: int = 0, file: TextIO = sys.stdout) -> None: #...
FILE: lib/hid_parser/data.py
class _DataMeta (line 12) | class _DataMeta(type):
method __new__ (line 49) | def __new__(mcs, name: str, bases: Tuple[Any], dic: Dict[str, Any]): ...
class _Data (line 106) | class _Data(metaclass=_DataMeta):
method _get_data (line 117) | def _get_data(cls, num: Optional[int]) -> _DATA:
method get_description (line 131) | def get_description(cls, num: Optional[int]) -> str:
method get_subdata (line 135) | def get_subdata(cls, num: Optional[int]) -> Any:
class UsageTypes (line 144) | class UsageTypes(enum.Enum):
class Collections (line 193) | class Collections(_Data):
class GenericDesktopControls (line 204) | class GenericDesktopControls(_Data):
class KeyboardKeypad (line 276) | class KeyboardKeypad(_Data):
class Led (line 498) | class Led(_Data):
class Button (line 578) | class Button(_Data):
class Consumer (line 597) | class Consumer(_Data):
class PowerDevice (line 964) | class PowerDevice(_Data):
class FIDO (line 1044) | class FIDO(_Data):
class UsagePages (line 1050) | class UsagePages(_Data):
FILE: lib/hidapi/common.py
class DeviceInfo (line 7) | class DeviceInfo:
FILE: lib/hidapi/hidapi_impl.py
class _cHidApiVersion (line 81) | class _cHidApiVersion(ctypes.Structure):
class _cDeviceInfo (line 95) | class _cDeviceInfo(ctypes.Structure):
method as_dict (line 96) | def as_dict(self):
class HIDError (line 172) | class HIDError(Exception):
function _enumerate_devices (line 176) | def _enumerate_devices():
class _DeviceMonitor (line 199) | class _DeviceMonitor(Thread):
method __init__ (line 200) | def __init__(self, device_callback, polling_delay=5.0):
method run (line 207) | def run(self):
function _match (line 224) | def _match(
function find_paired_node (line 350) | def find_paired_node(receiver_path: str, index: int, timeout: int):
function find_paired_node_wpid (line 355) | def find_paired_node_wpid(receiver_path: str, index: int):
function monitor_glib (line 360) | def monitor_glib(
function enumerate (line 390) | def enumerate(filter_func) -> DeviceInfo:
function open (line 404) | def open(vendor_id, product_id, serial=None):
function open_path (line 420) | def open_path(device_path: str) -> int:
function close (line 436) | def close(device_handle) -> None:
function write (line 445) | def write(device_handle: int, data: bytes) -> int:
function read (line 476) | def read(device_handle, bytes_count, timeout_ms=None):
function _get_input_report (line 506) | def _get_input_report(device_handle, report_id, size):
function _readstring (line 516) | def _readstring(device_handle, func, max_length=255):
function get_manufacturer (line 525) | def get_manufacturer(device_handle):
function get_product (line 533) | def get_product(device_handle):
function get_serial (line 541) | def get_serial(device_handle):
FILE: lib/hidapi/hidconsole.py
function strhex (line 43) | def strhex(d):
function _print (line 50) | def _print(marker, data, scroll=False):
function _error (line 84) | def _error(text, scroll=False):
function _continuous_read (line 88) | def _continuous_read(handle, timeout=2000):
function _validate_input (line 100) | def _validate_input(line, hidpp=False):
function _open (line 133) | def _open(args):
function _parse_arguments (line 174) | def _parse_arguments():
function main (line 185) | def main():
FILE: lib/hidapi/udev_impl.py
function init (line 64) | def init():
function exit (line 73) | def exit():
function _match (line 82) | def _match(action: str, device, filter_func: typing.Callable[[int, int, ...
function find_paired_node (line 190) | def find_paired_node(receiver_path: str, index: int, timeout: int):
function find_paired_node_wpid (line 211) | def find_paired_node_wpid(receiver_path: str, index: int):
function monitor_glib (line 232) | def monitor_glib(glib: GLib, callback: Callable, filter_func: Callable):
function enumerate (line 273) | def enumerate(filter_func: typing.Callable[[int, int, int, bool, bool], ...
function open (line 289) | def open(vendor_id, product_id, serial=None):
function open_path (line 305) | def open_path(device_path):
function close (line 329) | def close(device_handle) -> None:
function write (line 338) | def write(device_handle, data):
function read (line 377) | def read(device_handle, bytes_count, timeout_ms=-1):
function get_manufacturer (line 418) | def get_manufacturer(device_handle):
function get_product (line 426) | def get_product(device_handle):
function get_serial (line 434) | def get_serial(device_handle):
function get_indexed_string (line 443) | def get_indexed_string(device_handle, index):
FILE: lib/keysyms/generate.py
function main (line 15) | def main():
FILE: lib/logitech_receiver/base.py
class HIDProtocol (line 59) | class HIDProtocol(typing.Protocol):
method find_paired_node_wpid (line 60) | def find_paired_node_wpid(self, receiver_path: str, index: int):
method find_paired_node (line 63) | def find_paired_node(self, receiver_path: str, index: int, timeout: int):
method open (line 66) | def open(self, vendor_id, product_id, serial=None):
method open_path (line 69) | def open_path(self, path) -> int:
method enumerate (line 72) | def enumerate(self, filter_func: Callable[[int, int, int, bool, bool],...
method monitor_glib (line 75) | def monitor_glib(
method read (line 80) | def read(self, device_handle, bytes_count, timeout_ms):
method write (line 83) | def write(self, device_handle: int, data: bytes) -> int:
method close (line 86) | def close(self, device_handle) -> None:
class HIDPPNotification (line 116) | class HIDPPNotification:
method __str__ (line 123) | def __str__(self):
function _usb_device (line 128) | def _usb_device(product_id: int, usb_interface: int) -> dict[str, Any]:
function _bluetooth_device (line 138) | def _bluetooth_device(product_id: int) -> dict[str, Any]:
function product_information (line 152) | def product_information(usb_id: int) -> dict[str, Any]:
function receivers (line 157) | def receivers():
function filter_products_of_interest (line 162) | def filter_products_of_interest(
function get_known_device_info (line 183) | def get_known_device_info(bus_id: int, vendor_id: int, product_id: int) ...
function get_unknown_hid_device_info (line 189) | def get_unknown_hid_device_info(bus_id: int, vendor_id: int, product_id:...
function get_unknown_logitech_device_info (line 193) | def get_unknown_logitech_device_info(bus_id: int, vendor_id: int, produc...
function _match_device (line 213) | def _match_device(record: dict[str, Any], bus_id: int, vendor_id: int, p...
function get_known_receiver_info (line 221) | def get_known_receiver_info(
function receivers_and_devices (line 242) | def receivers_and_devices():
function notify_on_receivers_glib (line 247) | def notify_on_receivers_glib(glib: GLib, callback: Callable):
function open_path (line 258) | def open_path(path) -> int:
function open (line 274) | def open():
function close (line 285) | def close(handle):
function write (line 300) | def write(handle, devnumber, data, long_message=False):
function read (line 339) | def read(handle, timeout=DEFAULT_TIMEOUT):
function _is_relevant_message (line 357) | def _is_relevant_message(data: bytes) -> bool:
function _read (line 381) | def _read(handle, timeout) -> tuple[int, int, bytes]:
function make_notification (line 418) | def make_notification(report_id: int, devnumber: int, data: bytes) -> HI...
function handle_lock (line 453) | def handle_lock(handle):
function acquire_timeout (line 464) | def acquire_timeout(lock, handle, timeout):
function find_paired_node (line 475) | def find_paired_node(receiver_path: str, index: int, timeout: int):
function find_paired_node_wpid (line 480) | def find_paired_node_wpid(receiver_path: str, index: int):
function request (line 489) | def request(
function ping (line 617) | def ping(handle, devnumber, long_message: bool = False):
function _read_input_buffer (line 673) | def _read_input_buffer(handle, ihandle, notifications_hook):
function _get_next_sw_id (line 700) | def _get_next_sw_id() -> int:
FILE: lib/logitech_receiver/base_usb.py
function _bolt_receiver (line 47) | def _bolt_receiver(product_id: int) -> dict:
function _unifying_receiver (line 59) | def _unifying_receiver(product_id: int) -> dict:
function _nano_receiver (line 70) | def _nano_receiver(product_id: int) -> dict:
function _nano_receiver_no_unpair (line 82) | def _nano_receiver_no_unpair(product_id: int) -> dict:
function _nano_receiver_max2 (line 95) | def _nano_receiver_max2(product_id: int) -> dict:
function _lenovo_receiver (line 108) | def _lenovo_receiver(product_id: int) -> dict:
function _lightspeed_receiver (line 119) | def _lightspeed_receiver(product_id: int) -> dict:
function _ex100_receiver (line 131) | def _ex100_receiver(product_id: int) -> dict:
function get_receiver_info (line 212) | def get_receiver_info(product_id: int) -> dict[str, Any]:
FILE: lib/logitech_receiver/common.py
function crc16 (line 40) | def crc16(data: bytes):
class NamedInt (line 310) | class NamedInt(int):
method __new__ (line 316) | def __new__(cls, value, name):
method bytes (line 322) | def bytes(self, count=2):
method __eq__ (line 325) | def __eq__(self, other):
method __ne__ (line 338) | def __ne__(self, other):
method __hash__ (line 341) | def __hash__(self):
method __str__ (line 344) | def __str__(self):
method __repr__ (line 347) | def __repr__(self):
method from_yaml (line 351) | def from_yaml(cls, loader, node):
method to_yaml (line 356) | def to_yaml(cls, dumper, data):
class NamedInts (line 364) | class NamedInts:
method __init__ (line 380) | def __init__(self, dict_=None, **kwargs):
method list (line 397) | def list(cls, items, name_generator=lambda x: str(x)): # noqa: B008
method range (line 402) | def range(cls, from_value, to_value, name_generator=lambda x: str(x), ...
method flag_names (line 406) | def flag_names(self, value):
method _sort_values (line 417) | def _sort_values(self):
method __getitem__ (line 421) | def __getitem__(self, index):
method __setitem__ (line 467) | def __setitem__(self, index, name):
method __contains__ (line 488) | def __contains__(self, value):
method __iter__ (line 496) | def __iter__(self):
method __len__ (line 499) | def __len__(self):
method __repr__ (line 502) | def __repr__(self):
method __or__ (line 505) | def __or__(self, other):
method __eq__ (line 508) | def __eq__(self, other):
function flag_names (line 512) | def flag_names(enum_class: Iterable, value: int) -> Generator[str]:
class UnsortedNamedInts (line 537) | class UnsortedNamedInts(NamedInts):
method _sort_values (line 538) | def _sort_values(self):
method __or__ (line 541) | def __or__(self, other):
function strhex (line 546) | def strhex(x):
function bytes2int (line 552) | def bytes2int(x, signed=False):
function int2bytes (line 556) | def int2bytes(x, count=None, signed=False):
class KwException (line 563) | class KwException(Exception):
method __init__ (line 568) | def __init__(self, **kwargs):
method __getattr__ (line 571) | def __getattr__(self, k):
class FirmwareKind (line 578) | class FirmwareKind(IntEnum):
class FirmwareInfo (line 586) | class FirmwareInfo:
class BatteryStatus (line 593) | class BatteryStatus(Flag):
class BatteryLevelApproximation (line 603) | class BatteryLevelApproximation(IntEnum):
class Battery (line 612) | class Battery:
method __post_init__ (line 623) | def __post_init__(self):
method ok (line 632) | def ok(self) -> bool:
method charging (line 637) | def charging(self) -> bool:
method to_str (line 645) | def to_str(self) -> str:
class Alert (line 656) | class Alert(IntEnum):
class Notification (line 664) | class Notification(IntEnum):
class BusID (line 674) | class BusID(IntEnum):
FILE: lib/logitech_receiver/descriptors.py
class _DeviceDescriptor (line 31) | class _DeviceDescriptor:
method __init__ (line 32) | def __init__(
function _D (line 60) | def _D(
function get_wpid (line 131) | def get_wpid(wpid):
function get_codename (line 135) | def get_codename(codename):
function get_usbid (line 139) | def get_usbid(usbid):
function get_btid (line 146) | def get_btid(btid):
FILE: lib/logitech_receiver/desktop_notifications.py
function notifications_available (line 25) | def notifications_available():
function init (line 55) | def init():
function uninit (line 69) | def uninit():
function show (line 77) | def show(dev, message: str, icon=None):
function device_icon_list (line 93) | def device_icon_list(name="_", kind=None):
function device_icon_name (line 113) | def device_icon_name(name, kind=None):
function init (line 122) | def init():
function uninit (line 125) | def uninit():
function show (line 128) | def show(dev, reason=None):
FILE: lib/logitech_receiver/device.py
class LowLevelInterface (line 53) | class LowLevelInterface(Protocol):
method open_path (line 54) | def open_path(self, path) -> int:
method find_paired_node (line 57) | def find_paired_node(self, receiver_path: str, index: int, timeout: int):
method ping (line 60) | def ping(self, handle, number, long_message: bool):
method request (line 63) | def request(self, handle, devnumber, request_id, *params, **kwargs):
method close (line 66) | def close(self, handle, *args, **kwargs) -> bool:
function create_device (line 70) | def create_device(low_level: LowLevelInterface, device_info, setting_cal...
class Device (line 96) | class Device:
method __init__ (line 101) | def __init__(
method find (line 214) | def find(self, id): # find a device by serial number or unit ID or na...
method protocol (line 221) | def protocol(self):
method codename (line 230) | def codename(self):
method name (line 246) | def name(self):
method get_ids (line 254) | def get_ids(self):
method unitId (line 262) | def unitId(self):
method modelId (line 268) | def modelId(self):
method tid_map (line 274) | def tid_map(self):
method kind (line 280) | def kind(self):
method firmware (line 286) | def firmware(self) -> tuple[common.FirmwareInfo]:
method serial (line 295) | def serial(self):
method id (line 299) | def id(self):
method power_switch_location (line 303) | def power_switch_location(self):
method polling_rate (line 307) | def polling_rate(self):
method led_effects (line 314) | def led_effects(self):
method keys (line 323) | def keys(self):
method remap_keys (line 330) | def remap_keys(self):
method gestures (line 337) | def gestures(self):
method backlight (line 346) | def backlight(self):
method profiles (line 353) | def profiles(self):
method force_buttons (line 359) | def force_buttons(self):
method set_configuration (line 365) | def set_configuration(self, configuration_, no_reply=False):
method reset (line 369) | def reset(self, no_reply=False):
method persister (line 373) | def persister(self):
method settings (line 381) | def settings(self):
method battery (line 403) | def battery(self): # None or level, next, status, voltage
method set_battery_info (line 419) | def set_battery_info(self, info):
method read_battery (line 444) | def read_battery(self):
method changed (line 449) | def changed(self, active=None, alert=Alert.NONE, reason=None, push=Fal...
method enable_connection_notifications (line 482) | def enable_connection_notifications(self, enable=True):
method add_notification_handler (line 506) | def add_notification_handler(self, id: str, fn):
method remove_notification_handler (line 520) | def remove_notification_handler(self, id: str):
method handle_notification (line 528) | def handle_notification(self, n) -> Optional[bool]:
method request (line 535) | def request(self, request_id, *params, no_reply=False):
method feature_request (line 550) | def feature_request(self, feature, function=0x00, *params, no_reply=Fa...
method ping (line 554) | def ping(self):
method notify_devices (line 572) | def notify_devices(self): # no need to notify, as there are none
method close (line 575) | def close(self):
method __index__ (line 584) | def __index__(self):
method __eq__ (line 589) | def __eq__(self, other):
method __ne__ (line 592) | def __ne__(self, other):
method __hash__ (line 595) | def __hash__(self):
method __bool__ (line 598) | def __bool__(self):
method status_string (line 603) | def status_string(self):
method __str__ (line 606) | def __str__(self):
method __del__ (line 615) | def __del__(self):
FILE: lib/logitech_receiver/diversion.py
class XkbDisplay (line 146) | class XkbDisplay(ctypes.Structure):
class XkbStateRec (line 150) | class XkbStateRec(ctypes.Structure):
function x11_setup (line 169) | def x11_setup():
function gnome_dbus_interface_setup (line 190) | def gnome_dbus_interface_setup():
function xkb_setup (line 209) | def xkb_setup():
function setup_uinput (line 258) | def setup_uinput():
function kbdgroup (line 271) | def kbdgroup():
function modifier_code (line 280) | def modifier_code(keycode):
function signed (line 288) | def signed(bytes_: bytes) -> int:
function xy_direction (line 292) | def xy_direction(_x, _y):
function simulate_uinput (line 319) | def simulate_uinput(what, code, arg):
function simulate_key (line 333) | def simulate_key(code, event): # X11 keycode but Solaar event code
function click_uinput (line 339) | def click_uinput(button, count):
function click (line 356) | def click(button, count):
function simulate_scroll (line 363) | def simulate_scroll(dx, dy):
function thumb_wheel_up (line 375) | def thumb_wheel_up(f, r, d, a):
function thumb_wheel_down (line 388) | def thumb_wheel_down(f, r, d, a):
function charging (line 401) | def charging(f, r, d, _a):
class RuleComponent (line 455) | class RuleComponent:
method compile (line 456) | def compile(self, c):
function _evaluate (line 467) | def _evaluate(components, feature, notification: HIDPPNotification, devi...
class Rule (line 478) | class Rule(RuleComponent):
method __init__ (line 479) | def __init__(self, args, source=None, warn=True):
method __str__ (line 483) | def __str__(self):
method evaluate (line 487) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method once (line 492) | def once(self, feature, notification: HIDPPNotification, device, last_...
method data (line 496) | def data(self):
class Condition (line 500) | class Condition(RuleComponent):
method __init__ (line 501) | def __init__(self, *args):
method __str__ (line 504) | def __str__(self):
method evaluate (line 507) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
class Not (line 513) | class Not(Condition):
method __init__ (line 514) | def __init__(self, op, warn=True):
method __str__ (line 520) | def __str__(self):
method evaluate (line 523) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 529) | def data(self):
class Or (line 533) | class Or(Condition):
method __init__ (line 534) | def __init__(self, args, warn=True):
method __str__ (line 537) | def __str__(self):
method evaluate (line 540) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 552) | def data(self):
class And (line 556) | class And(Condition):
method __init__ (line 557) | def __init__(self, args, warn=True):
method __str__ (line 560) | def __str__(self):
method evaluate (line 563) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 568) | def data(self):
function x11_focus_prog (line 572) | def x11_focus_prog():
function x11_pointer_prog (line 590) | def x11_pointer_prog():
function gnome_dbus_focus_prog (line 604) | def gnome_dbus_focus_prog():
function gnome_dbus_pointer_prog (line 611) | def gnome_dbus_pointer_prog():
class Process (line 618) | class Process(Condition):
method __init__ (line 619) | def __init__(self, process, warn=True):
method __str__ (line 633) | def __str__(self):
method evaluate (line 636) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 645) | def data(self):
class MouseProcess (line 649) | class MouseProcess(Condition):
method __init__ (line 650) | def __init__(self, process, warn=True):
method __str__ (line 664) | def __str__(self):
method evaluate (line 667) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 676) | def data(self):
class Feature (line 680) | class Feature(Condition):
method __init__ (line 681) | def __init__(self, feature: str, warn: bool = True):
method __str__ (line 689) | def __str__(self):
method evaluate (line 692) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 697) | def data(self):
class Report (line 701) | class Report(Condition):
method __init__ (line 702) | def __init__(self, report, warn=True):
method __str__ (line 710) | def __str__(self):
method evaluate (line 713) | def evaluate(self, report, notification: HIDPPNotification, device, la...
method data (line 718) | def data(self):
class Setting (line 723) | class Setting(Condition):
method __init__ (line 724) | def __init__(self, args, warn=True):
method __str__ (line 732) | def __str__(self):
method evaluate (line 735) | def evaluate(self, report, notification: HIDPPNotification, device, la...
method data (line 757) | def data(self):
class Modifiers (line 770) | class Modifiers(Condition):
method __init__ (line 771) | def __init__(self, modifiers, warn=True):
method __str__ (line 783) | def __str__(self):
method evaluate (line 786) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 796) | def data(self):
class Key (line 800) | class Key(Condition):
method __init__ (line 804) | def __init__(self, args, warn=True):
method __str__ (line 843) | def __str__(self):
method evaluate (line 846) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 851) | def data(self):
class KeyIsDown (line 855) | class KeyIsDown(Condition):
method __init__ (line 856) | def __init__(self, args, warn=True):
method __str__ (line 875) | def __str__(self):
method evaluate (line 878) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 883) | def data(self):
function bit_test (line 887) | def bit_test(start, end, bits):
function range_test (line 891) | def range_test(start, end, min, max):
class Test (line 899) | class Test(Condition):
method __init__ (line 900) | def __init__(self, test, warn=True):
method __str__ (line 929) | def __str__(self):
method evaluate (line 932) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 937) | def data(self):
class TestBytes (line 941) | class TestBytes(Condition):
method __init__ (line 942) | def __init__(self, test, warn=True):
method __str__ (line 957) | def __str__(self):
method evaluate (line 960) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 965) | def data(self):
class MouseGesture (line 969) | class MouseGesture(Condition):
method __init__ (line 981) | def __init__(self, movements, warn=True):
method __str__ (line 990) | def __str__(self):
method evaluate (line 993) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 1020) | def data(self):
class Active (line 1024) | class Active(Condition):
method __init__ (line 1025) | def __init__(self, devID, warn=True):
method __str__ (line 1032) | def __str__(self):
method evaluate (line 1035) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 1041) | def data(self):
class Device (line 1045) | class Device(Condition):
method __init__ (line 1046) | def __init__(self, devID, warn=True):
method __str__ (line 1053) | def __str__(self):
method evaluate (line 1056) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 1066) | def data(self):
class Host (line 1070) | class Host(Condition):
method __init__ (line 1071) | def __init__(self, host, warn=True):
method __str__ (line 1078) | def __str__(self):
method evaluate (line 1081) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 1087) | def data(self):
class Action (line 1091) | class Action(RuleComponent):
method __init__ (line 1092) | def __init__(self, *args):
method evaluate (line 1095) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
function keysym_to_keycode (line 1099) | def keysym_to_keycode(keysym, _modifiers) -> Tuple[int, int]: # maybe s...
class KeyPress (line 1125) | class KeyPress(Action):
method __init__ (line 1126) | def __init__(self, args, warn=True):
method regularize_args (line 1139) | def regularize_args(self, args):
method __str__ (line 1149) | def __str__(self):
method needed (line 1152) | def needed(self, k, modifiers):
method mods (line 1156) | def mods(self, level, modifiers, direction):
method keyDown (line 1166) | def keyDown(self, keysyms_, modifiers):
method keyUp (line 1175) | def keyUp(self, keysyms_, modifiers):
method evaluate (line 1182) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 1202) | def data(self):
class MouseScroll (line 1215) | class MouseScroll(Action):
method __init__ (line 1216) | def __init__(self, amounts, warn=True):
method __str__ (line 1225) | def __str__(self):
method evaluate (line 1228) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 1239) | def data(self):
class MouseClick (line 1243) | class MouseClick(Action):
method __init__ (line 1244) | def __init__(self, args, warn=True):
method __str__ (line 1267) | def __str__(self):
method evaluate (line 1270) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 1278) | def data(self):
class Set (line 1282) | class Set(Action):
method __init__ (line 1283) | def __init__(self, args, warn=True):
method __str__ (line 1291) | def __str__(self):
method evaluate (line 1294) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 1324) | def data(self):
class Execute (line 1328) | class Execute(Action):
method __init__ (line 1329) | def __init__(self, args, warn=True):
method __str__ (line 1339) | def __str__(self):
method evaluate (line 1342) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 1348) | def data(self):
class Later (line 1352) | class Later(Action):
method __init__ (line 1353) | def __init__(self, args, warn=True):
method __str__ (line 1370) | def __str__(self):
method evaluate (line 1373) | def evaluate(self, feature, notification: HIDPPNotification, device, l...
method data (line 1381) | def data(self):
function key_is_down (line 1427) | def key_is_down(key: NamedInt) -> bool:
function evaluate_rules (line 1438) | def evaluate_rules(feature, notification: HIDPPNotification, device):
function process_notification (line 1444) | def process_notification(device, notification: HIDPPNotification, featur...
function _save_config_rule_file (line 1500) | def _save_config_rule_file(file_name: str = _file_path):
function load_config_rule_file (line 1548) | def load_config_rule_file():
function _load_rule_config (line 1556) | def _load_rule_config(file_path: str) -> Rule:
FILE: lib/logitech_receiver/exceptions.py
class NoReceiver (line 23) | class NoReceiver(KwException):
class NoSuchDevice (line 32) | class NoSuchDevice(KwException):
class DeviceUnreachable (line 38) | class DeviceUnreachable(KwException):
class FeatureNotSupported (line 44) | class FeatureNotSupported(KwException):
class FeatureCallError (line 50) | class FeatureCallError(KwException):
FILE: lib/logitech_receiver/hidpp10.py
class Device (line 35) | class Device(Protocol):
method request (line 36) | def request(self, request_id, *params):
method kind (line 40) | def kind(self) -> Any:
method online (line 44) | def online(self) -> bool:
method protocol (line 48) | def protocol(self) -> Any:
method registers (line 52) | def registers(self) -> list:
function read_register (line 56) | def read_register(device: Device, register: Registers | int, *params) ->...
function write_register (line 63) | def write_register(device: Device, register: Registers | int, *value) ->...
function get_configuration_pending_flags (line 70) | def get_configuration_pending_flags(receiver):
function set_configuration_pending_flags (line 77) | def set_configuration_pending_flags(receiver, devices):
class Hidpp10 (line 83) | class Hidpp10:
method get_battery (line 84) | def get_battery(self, device: Device):
method get_firmware (line 114) | def get_firmware(self, device: Device) -> tuple[common.FirmwareInfo] |...
method set_3leds (line 149) | def set_3leds(self, device: Device, battery_level=None, charging=None,...
method get_notification_flags (line 191) | def get_notification_flags(self, device: Device):
method set_notification_flags (line 196) | def set_notification_flags(self, device: Device, *flag_bits: Notificat...
method get_device_features (line 211) | def get_device_features(self, device: Device):
method _get_register (line 214) | def _get_register(self, device: Device, register: Registers | int):
function parse_battery_status (line 230) | def parse_battery_status(register: Registers | int, reply) -> Battery | ...
FILE: lib/logitech_receiver/hidpp10_constants.py
class PowerSwitchLocation (line 49) | class PowerSwitchLocation(IntEnum):
method location (line 64) | def location(cls, loc: int) -> PowerSwitchLocation:
class NotificationFlag (line 71) | class NotificationFlag(IntFlag):
method flag_names (line 92) | def flag_names(cls, flags) -> List[str]:
function flags_to_str (line 114) | def flags_to_str(flags, fallback: str) -> str:
class ErrorCode (line 124) | class ErrorCode(IntEnum):
class PairingError (line 139) | class PairingError(IntEnum):
method label (line 146) | def label(self) -> str:
class BoltPairingError (line 150) | class BoltPairingError(IntEnum):
method label (line 155) | def label(self) -> str:
class Registers (line 159) | class Registers(IntEnum):
class InfoSubRegisters (line 199) | class InfoSubRegisters(IntEnum):
class DeviceFeature (line 210) | class DeviceFeature(IntFlag):
method flag_names (line 218) | def flag_names(cls, flag_bits: int) -> List[str]:
FILE: lib/logitech_receiver/hidpp20.py
class Device (line 63) | class Device(Protocol):
method feature_request (line 64) | def feature_request(self, feature, function=0x00, *params, no_reply=Fa...
method features (line 68) | def features(self) -> Any:
method _gestures (line 72) | def _gestures(self) -> Any:
method _backlight (line 76) | def _backlight(self) -> Any:
method _profiles (line 80) | def _profiles(self) -> Any:
class KeyFlag (line 87) | class KeyFlag(Flag):
class MappingFlag (line 112) | class MappingFlag(Flag):
class ChargeStatus (line 129) | class ChargeStatus(Flag):
class FeaturesArray (line 136) | class FeaturesArray(dict):
method __init__ (line 137) | def __init__(self, device):
method _check (line 146) | def _check(self) -> bool:
method get_feature (line 173) | def get_feature(self, index: int) -> SupportedFeature | None:
method enumerate (line 193) | def enumerate(self): # return all features and their index, ordered b...
method get_feature_version (line 199) | def get_feature_version(self, feature: NamedInt) -> Optional[int]:
method get_flags (line 203) | def get_flags(self, feature: NamedInt) -> Optional[int]:
method get_hidden (line 207) | def get_hidden(self, feature: NamedInt) -> Optional[bool]:
method __contains__ (line 212) | def __contains__(self, feature: NamedInt) -> bool:
method __getitem__ (line 219) | def __getitem__(self, feature: NamedInt) -> Optional[int]:
method __setitem__ (line 235) | def __setitem__(self, feature, index):
method __delitem__ (line 242) | def __delitem__(self, feature):
method __len__ (line 245) | def __len__(self) -> int:
class ReprogrammableKey (line 251) | class ReprogrammableKey:
method __init__ (line 263) | def __init__(self, device: Device, index: int, cid: int, task_id: int,...
method key (line 271) | def key(self) -> NamedInt:
method default_task (line 275) | def default_task(self) -> NamedInt:
method flags (line 287) | def flags(self) -> KeyFlag:
class ReprogrammableKeyV4 (line 291) | class ReprogrammableKeyV4(ReprogrammableKey):
method __init__ (line 308) | def __init__(self, device: Device, index, cid, task_id, flags, pos, gr...
method group_mask (line 317) | def group_mask(self) -> Generator[str]:
method mapped_to (line 321) | def mapped_to(self) -> NamedInt:
method remappable_to (line 332) | def remappable_to(self):
method mapping_flags (line 351) | def mapping_flags(self) -> MappingFlag:
method set_diverted (line 356) | def set_diverted(self, value: bool) -> None:
method set_persistently_diverted (line 361) | def set_persistently_diverted(self, value: bool) -> None:
method set_rawXY_reporting (line 366) | def set_rawXY_reporting(self, value: bool) -> None:
method remap (line 371) | def remap(self, to: NamedInt):
method _getCidReporting (line 375) | def _getCidReporting(self):
method _setCidReporting (line 406) | def _setCidReporting(self, flags: Dict[NamedInt, bool] = None, remap: ...
class PersistentRemappableAction (line 461) | class PersistentRemappableAction:
method __init__ (line 462) | def __init__(self, device, index, cid, actionId, remapped, modifierMas...
method key (line 472) | def key(self) -> NamedInt:
method actionType (line 476) | def actionType(self) -> NamedInt:
method action (line 480) | def action(self):
method modifiers (line 505) | def modifiers(self):
method data_bytes (line 509) | def data_bytes(self):
method remap (line 514) | def remap(self, data_bytes):
class KeysArray (line 527) | class KeysArray:
method __init__ (line 530) | def __init__(self, device, count, version):
method _ensure_all_keys_queried (line 544) | def _ensure_all_keys_queried(self):
method __getitem__ (line 552) | def __getitem__(self, index):
method index (line 566) | def index(self, value):
method __iter__ (line 572) | def __iter__(self):
method __len__ (line 576) | def __len__(self):
class KeysArrayV2 (line 580) | class KeysArrayV2(KeysArray):
method __init__ (line 581) | def __init__(self, device: Device, count, version=1):
method _query_key (line 595) | def _query_key(self, index: int):
class KeysArrayV4 (line 607) | class KeysArrayV4(KeysArrayV2):
method __init__ (line 608) | def __init__(self, device, count):
method _query_key (line 611) | def _query_key(self, index: int):
class KeysArrayPersistent (line 627) | class KeysArrayPersistent(KeysArray):
method __init__ (line 628) | def __init__(self, device, count):
method capabilities (line 633) | def capabilities(self):
method _query_key (line 640) | def _query_key(self, index: int):
class SubParam (line 684) | class SubParam:
method __init__ (line 687) | def __init__(self, id, length, minimum=None, maximum=None, widget=None):
method __str__ (line 694) | def __str__(self):
method __repr__ (line 697) | def __repr__(self):
class SpecGesture (line 719) | class SpecGesture(IntEnum):
method __str__ (line 733) | def __str__(self):
class ActionId (line 737) | class ActionId(IntEnum):
class Gesture (line 754) | class Gesture:
method __init__ (line 755) | def __init__(self, device, low, high, next_index, next_diversion_index):
method _offset_mask (line 770) | def _offset_mask(self, index): # offset and mask
method enable_offset_mask (line 778) | def enable_offset_mask(self):
method diversion_offset_mask (line 781) | def diversion_offset_mask(self):
method enabled (line 784) | def enabled(self): # is the gesture enabled?
method set (line 791) | def set(self, enable): # enable or disable the gesture
method diverted (line 801) | def diverted(self): # is the gesture diverted?
method divert (line 808) | def divert(self, diverted): # divert or undivert the gesture
method as_int (line 823) | def as_int(self):
method __int__ (line 826) | def __int__(self):
method __repr__ (line 829) | def __repr__(self):
class Param (line 837) | class Param:
method __init__ (line 838) | def __init__(self, device, low: int, high, next_param_index):
method sub_params (line 849) | def sub_params(self):
method value (line 853) | def value(self):
method read (line 856) | def read(self): # returns the bytes for the parameter
method default_value (line 863) | def default_value(self):
method _read_default (line 868) | def _read_default(self):
method write (line 874) | def write(self, bytes):
method __str__ (line 878) | def __str__(self):
method __int__ (line 881) | def __int__(self):
class Spec (line 885) | class Spec:
method __init__ (line 886) | def __init__(self, device, low: int, high):
method value (line 897) | def value(self):
method read (line 902) | def read(self):
method __repr__ (line 913) | def __repr__(self):
class Gestures (line 917) | class Gestures:
method __init__ (line 923) | def __init__(self, device):
method gesture (line 960) | def gesture(self, gesture):
method gesture_enabled (line 963) | def gesture_enabled(self, gesture): # is the gesture enabled?
method enable_gesture (line 967) | def enable_gesture(self, gesture):
method disable_gesture (line 971) | def disable_gesture(self, gesture):
method param (line 975) | def param(self, param):
method get_param (line 978) | def get_param(self, param):
method set_param (line 982) | def set_param(self, param, value):
class Backlight (line 987) | class Backlight:
method __init__ (line 990) | def __init__(self, device):
method write (line 1003) | def write(self):
class LEDParam (line 1010) | class LEDParam:
class LedRampChoice (line 1020) | class LedRampChoice(IntEnum):
class LedFormChoices (line 1026) | class LedFormChoices(IntEnum):
class LEDEffectSetting (line 1067) | class LEDEffectSetting: # an effect plus its parameters
method __init__ (line 1068) | def __init__(self, **kwargs):
method from_bytes (line 1074) | def from_bytes(cls, bytes, options=None):
method to_bytes (line 1085) | def to_bytes(self, options=None):
method from_yaml (line 1099) | def from_yaml(cls, loader, node):
method to_yaml (line 1103) | def to_yaml(cls, dumper, data):
method __eq__ (line 1106) | def __eq__(self, other):
method __str__ (line 1109) | def __str__(self):
class LEDEffectInfo (line 1117) | class LEDEffectInfo: # an effect that a zone can do
method __init__ (line 1118) | def __init__(self, feature, function, device, zindex, eindex):
method __str__ (line 1122) | def __str__(self):
class LEDZoneInfo (line 1141) | class LEDZoneInfo: # effects that a zone can do
method __init__ (line 1142) | def __init__(self, feature, function, offset, effect_function, device,...
method to_command (line 1151) | def to_command(self, setting):
method __str__ (line 1158) | def __str__(self):
class LEDEffectsInfo (line 1162) | class LEDEffectsInfo: # effects that the LEDs can do, using COLOR_LED_E...
method __init__ (line 1163) | def __init__(self, device):
method to_command (line 1172) | def to_command(self, index, setting):
method __str__ (line 1175) | def __str__(self):
class RGBEffectsInfo (line 1180) | class RGBEffectsInfo(LEDEffectsInfo): # effects that the LEDs can do us...
method __init__ (line 1181) | def __init__(self, device):
class ButtonBehavior (line 1191) | class ButtonBehavior(IntEnum):
class ButtonMappingType (line 1199) | class ButtonMappingType(IntEnum):
class ButtonFunctions (line 1206) | class ButtonFunctions(IntEnum):
class Button (line 1233) | class Button:
method __init__ (line 1236) | def __init__(self, **kwargs):
method from_yaml (line 1242) | def from_yaml(cls, loader, node):
method to_yaml (line 1247) | def to_yaml(cls, dumper, data):
method from_bytes (line 1251) | def from_bytes(cls, bytes_) -> Button:
method to_bytes (line 1286) | def to_bytes(self):
method __repr__ (line 1308) | def __repr__(self):
class OnboardProfile (line 1319) | class OnboardProfile:
method __init__ (line 1322) | def __init__(self, **kwargs):
method from_yaml (line 1327) | def from_yaml(cls, loader, node):
method to_yaml (line 1332) | def to_yaml(cls, dumper, data):
method from_bytes (line 1336) | def from_bytes(cls, sector, enabled, buttons, gbuttons, bytes):
method from_dev (line 1360) | def from_dev(cls, dev, i, sector, s, enabled, buttons, gbuttons):
method to_bytes (line 1364) | def to_bytes(self, length):
method dump (line 1387) | def dump(self):
class OnboardProfiles (line 1409) | class OnboardProfiles:
method __init__ (line 1412) | def __init__(self, **kwargs):
method from_yaml (line 1417) | def from_yaml(cls, loader, node):
method to_yaml (line 1422) | def to_yaml(cls, dumper, data):
method get_profile_headers (line 1426) | def get_profile_headers(cls, device) -> list[tuple[int, int]]:
method from_device (line 1449) | def from_device(cls, device):
method to_bytes (line 1473) | def to_bytes(self):
method read_sector (line 1486) | def read_sector(cls, dev, sector, s): # doesn't check for valid secto...
method write_sector (line 1505) | def write_sector(cls, device, s, bs): # doesn't check for valid secto...
method write (line 1517) | def write(self, device):
method show (line 1533) | def show(self):
function feature_request (line 1541) | def feature_request(device, feature, function=0x00, *params, no_reply=Fa...
class Hidpp20 (line 1548) | class Hidpp20:
method get_firmware (line 1549) | def get_firmware(self, device) -> tuple[common.FirmwareInfo] | None:
method get_ids (line 1578) | def get_ids(self, device):
method get_kind (line 1593) | def get_kind(self, device: Device):
method get_name (line 1608) | def get_name(self, device: Device):
method get_friendly_name (line 1629) | def get_friendly_name(self, device: Device):
method get_battery_status (line 1650) | def get_battery_status(self, device: Device):
method get_battery_unified (line 1655) | def get_battery_unified(self, device: Device):
method get_battery_voltage (line 1660) | def get_battery_voltage(self, device: Device):
method get_adc_measurement (line 1665) | def get_adc_measurement(self, device: Device):
method get_battery (line 1673) | def get_battery(self, device, feature):
method get_keys (line 1690) | def get_keys(self, device: Device):
method get_remap_keys (line 1701) | def get_remap_keys(self, device: Device):
method get_gestures (line 1706) | def get_gestures(self, device: Device):
method get_backlight (line 1712) | def get_backlight(self, device: Device):
method get_force_buttons (line 1718) | def get_force_buttons(self, device: Device):
method get_profiles (line 1724) | def get_profiles(self, device: Device):
method get_mouse_pointer_info (line 1730) | def get_mouse_pointer_info(self, device: Device):
method get_vertical_scrolling_info (line 1744) | def get_vertical_scrolling_info(self, device: Device):
method get_hi_res_scrolling_info (line 1760) | def get_hi_res_scrolling_info(self, device: Device):
method get_pointer_speed_info (line 1766) | def get_pointer_speed_info(self, device: Device):
method get_lowres_wheel_status (line 1774) | def get_lowres_wheel_status(self, device: Device):
method get_hires_wheel (line 1781) | def get_hires_wheel(self, device: Device):
method get_new_fn_inversion (line 1807) | def get_new_fn_inversion(self, device: Device):
method get_host_names (line 1815) | def get_host_names(self, device: Device):
method set_host_name (line 1841) | def set_host_name(self, device: Device, name, currentName=""):
method get_onboard_mode (line 1865) | def get_onboard_mode(self, device: Device):
method set_onboard_mode (line 1872) | def set_onboard_mode(self, device: Device, mode):
method get_polling_rate (line 1876) | def get_polling_rate(self, device: Device):
method get_remaining_pairing (line 1888) | def get_remaining_pairing(self, device: Device):
method config_change (line 1895) | def config_change(self, device: Device, configuration, no_reply=False):
function decipher_battery_status (line 1907) | def decipher_battery_status(report: FixedBytes5) -> Tuple[Any, Battery]:
function decipher_battery_voltage (line 1923) | def decipher_battery_voltage(report: bytes):
function decipher_battery_unified (line 1960) | def decipher_battery_unified(report) -> tuple[SupportedFeature, Battery]:
function decipher_adc_measurement (line 1984) | def decipher_adc_measurement(report) -> tuple[SupportedFeature, Battery]:
function estimate_battery_level_percentage (line 1993) | def estimate_battery_level_percentage(value_millivolt: int) -> int | None:
class ForceSensingButton (line 2034) | class ForceSensingButton:
method create (line 2038) | def create(cls, device, number: int):
method __init__ (line 2047) | def __init__(self, device, number: int, changeable: bool, default: int...
method get_current (line 2056) | def get_current(self) -> int:
method set_current (line 2059) | def set_current(self, current: int) -> None:
method acceptable_current (line 2069) | def acceptable_current(self, value: int) -> bool:
class ForceSensingButtonArray (line 2073) | class ForceSensingButtonArray(UserDict):
method __new__ (line 2076) | def __new__(cls, device: Device):
method __init__ (line 2084) | def __init__(self, device: Device):
method __getitem__ (line 2090) | def __getitem__(self, index: int):
method query_key (line 2096) | def query_key(self, index):
method query (line 2104) | def query(self):
method get_current (line 2112) | def get_current(self):
method set_current (line 2115) | def set_current(self, current: int) -> None:
method acceptable (line 2118) | def acceptable(self, value: int) -> bool:
method acceptable_current_key (line 2121) | def acceptable_current_key(self, index: int, value: int) -> bool:
FILE: lib/logitech_receiver/hidpp20_constants.py
class SupportedFeature (line 32) | class SupportedFeature(IntEnum):
method __str__ (line 184) | def __str__(self):
class FeatureFlag (line 188) | class FeatureFlag(IntFlag):
class OnboardMode (line 208) | class OnboardMode(IntEnum):
class ChargeLevel (line 214) | class ChargeLevel(IntEnum):
class ChargeType (line 220) | class ChargeType(IntEnum):
class ErrorCode (line 226) | class ErrorCode(IntEnum):
class GestureId (line 238) | class GestureId(IntEnum):
class ParamId (line 304) | class ParamId(IntEnum):
FILE: lib/logitech_receiver/listener.py
class _ThreadedHandle (line 28) | class _ThreadedHandle:
method __init__ (line 35) | def __init__(self, listener, path, handle):
method _open (line 48) | def _open(self):
method close (line 59) | def close(self):
method notifications_hook (line 69) | def notifications_hook(self):
method __del__ (line 75) | def __del__(self):
method __index__ (line 79) | def __index__(self):
method __str__ (line 90) | def __str__(self):
method __repr__ (line 94) | def __repr__(self):
method __bool__ (line 97) | def __bool__(self):
class EventsListener (line 110) | class EventsListener(threading.Thread):
method __init__ (line 115) | def __init__(self, receiver, notifications_callback):
method run (line 127) | def run(self):
method stop (line 160) | def stop(self):
method has_started (line 164) | def has_started(self):
method has_stopped (line 169) | def has_stopped(self):
method _notifications_hook (line 173) | def _notifications_hook(self, n):
method __bool__ (line 183) | def __bool__(self):
FILE: lib/logitech_receiver/notifications.py
function process (line 59) | def process(device: Device | Receiver, notification: HIDPPNotification):
function process_receiver_notification (line 69) | def process_receiver_notification(receiver: Receiver, notification: HIDP...
function process_device_notification (line 97) | def process_device_notification(device: Device, notification: HIDPPNotif...
function _process_dj_notification (line 136) | def _process_dj_notification(device: Device, notification: HIDPPNotifica...
function _process_hidpp10_custom_notification (line 162) | def _process_hidpp10_custom_notification(device: Device, notification: H...
function _process_hidpp10_notification (line 175) | def _process_hidpp10_notification(device: Device, notification: HIDPPNot...
function _process_feature_notification (line 240) | def _process_feature_notification(device: Device, notification: HIDPPNot...
function handle_pairing_lock (line 426) | def handle_pairing_lock(receiver: Receiver, notification: HIDPPNotificat...
function handle_discovery_status (line 444) | def handle_discovery_status(receiver: Receiver, notification: HIDPPNotif...
function handle_device_discovery (line 463) | def handle_device_discovery(receiver: Receiver, notification: HIDPPNotif...
function handle_pairing_status (line 480) | def handle_pairing_status(receiver: Receiver, notification: HIDPPNotific...
function handle_passkey_request (line 506) | def handle_passkey_request(receiver: Receiver, notification: HIDPPNotifi...
function handle_passkey_pressed (line 512) | def handle_passkey_pressed(_receiver: Receiver, _hidpp_notification: HID...
FILE: lib/logitech_receiver/receiver.py
class LowLevelInterface (line 53) | class LowLevelInterface(Protocol):
method open_path (line 54) | def open_path(self, path):
method find_paired_node_wpid (line 57) | def find_paired_node_wpid(self, receiver_path: str, index: int):
method ping (line 60) | def ping(self, handle, number, long_message=False):
method request (line 63) | def request(self, handle, devnumber, request_id, *params, **kwargs):
method close (line 66) | def close(self, handle):
class Pairing (line 71) | class Pairing:
function extract_serial (line 86) | def extract_serial(response: bytes) -> str:
function extract_max_devices (line 91) | def extract_max_devices(response: bytes) -> int:
function extract_remaining_pairings (line 97) | def extract_remaining_pairings(response: bytes) -> int:
function extract_codename (line 103) | def extract_codename(response: bytes) -> str:
function extract_power_switch_location (line 108) | def extract_power_switch_location(response: bytes) -> str:
function extract_connection_count (line 114) | def extract_connection_count(response: bytes) -> int:
function extract_wpid (line 119) | def extract_wpid(response: bytes) -> str:
function extract_polling_rate (line 124) | def extract_polling_rate(response: bytes) -> int:
function extract_device_kind (line 129) | def extract_device_kind(response: int) -> str:
class Receiver (line 133) | class Receiver:
method __init__ (line 143) | def __init__(
method initialize (line 175) | def initialize(self, product_info: dict):
method close (line 187) | def close(self):
method __del__ (line 195) | def __del__(self):
method changed (line 198) | def changed(self, alert=Alert.NOTIFICATION, reason=None):
method firmware (line 204) | def firmware(self) -> tuple[common.FirmwareInfo]:
method remaining_pairings (line 210) | def remaining_pairings(self, cache=True):
method enable_connection_notifications (line 217) | def enable_connection_notifications(self, enable=True):
method device_codename (line 241) | def device_codename(self, n):
method notify_devices (line 246) | def notify_devices(self):
method notification_information (line 252) | def notification_information(self, number, notification: HIDPPNotifica...
method device_pairing_information (line 261) | def device_pairing_information(self, n: int) -> dict:
method register_new_device (line 293) | def register_new_device(self, number, notification=None):
method set_lock (line 326) | def set_lock(self, lock_closed=True, device=0, timeout=0):
method count (line 334) | def count(self):
method request (line 340) | def request(self, request_id, *params):
method reset_pairing (line 344) | def reset_pairing(self):
method __iter__ (line 347) | def __iter__(self):
method __getitem__ (line 361) | def __getitem__(self, key):
method __delitem__ (line 376) | def __delitem__(self, key):
method _unpair_device (line 379) | def _unpair_device(self, key, force=False):
method _unpair_device_per_receiver (line 412) | def _unpair_device_per_receiver(self, key):
method __len__ (line 416) | def __len__(self):
method __contains__ (line 419) | def __contains__(self, dev):
method __eq__ (line 425) | def __eq__(self, other):
method __ne__ (line 428) | def __ne__(self, other):
method __hash__ (line 431) | def __hash__(self):
method status_string (line 434) | def status_string(self):
method __str__ (line 442) | def __str__(self):
class BoltReceiver (line 455) | class BoltReceiver(Receiver):
method __init__ (line 458) | def __init__(self, *args, **kwargs):
method initialize (line 461) | def initialize(self, product_info: dict):
method device_codename (line 466) | def device_codename(self, n):
method device_pairing_information (line 472) | def device_pairing_information(self, n: int) -> dict:
method discover (line 482) | def discover(self, cancel=False, timeout=30):
method pair_device (line 491) | def pair_device(self, pair=True, slot=0, address=b"\0\0\0\0\0\0", auth...
method _unpair_device_per_receiver (line 500) | def _unpair_device_per_receiver(self, key):
class UnifyingReceiver (line 505) | class UnifyingReceiver(Receiver):
method __init__ (line 506) | def __init__(self, *args, **kwargs):
class NanoReceiver (line 510) | class NanoReceiver(Receiver):
method __init__ (line 511) | def __init__(self, *args, **kwargs):
class LightSpeedReceiver (line 515) | class LightSpeedReceiver(Receiver):
method __init__ (line 516) | def __init__(self, *args, **kwargs):
class Ex100Receiver (line 520) | class Ex100Receiver(Receiver):
method __init__ (line 523) | def __init__(self, *args, **kwargs):
method initialize (line 526) | def initialize(self, product_info: dict):
method notification_information (line 530) | def notification_information(self, number, notification):
method device_pairing_information (line 539) | def device_pairing_information(self, number: int) -> dict:
function _get_kind_from_index (line 549) | def _get_kind_from_index(receiver, index: int) -> int:
function create_receiver (line 575) | def create_receiver(low_level: LowLevelInterface, device_info, setting_c...
FILE: lib/logitech_receiver/settings.py
class Kind (line 37) | class Kind(IntEnum):
class Setting (line 51) | class Setting:
method __init__ (line 63) | def __init__(self, device, rw, validator):
method build (line 71) | def build(cls, device):
method val_to_string (line 86) | def val_to_string(self, value):
method choices (line 90) | def choices(self):
method range (line 97) | def range(self):
method _pre_read (line 104) | def _pre_read(self, cached, key=None):
method read (line 115) | def read(self, cached=True):
method _pre_write (line 137) | def _pre_write(self, save=True):
method update (line 144) | def update(self, value, save=True):
method write (line 148) | def write(self, value, save=True):
method acceptable (line 179) | def acceptable(self, args, current):
method compare (line 182) | def compare(self, args, current):
method apply (line 185) | def apply(self):
method __str__ (line 198) | def __str__(self):
class Settings (line 213) | class Settings(Setting):
method read (line 217) | def read(self, cached=True):
method read_key (line 241) | def read_key(self, key, cached=True):
method write (line 260) | def write(self, map, save=True):
method update_key_value (line 280) | def update_key_value(self, key, value, save=True):
method write_key_value (line 284) | def write_key_value(self, key, value, save=True) -> Any | None:
class LongSettings (line 311) | class LongSettings(Setting):
method read (line 317) | def read(self, cached=True):
method read_item (line 343) | def read_item(self, item, cached=True):
method write (line 363) | def write(self, map, save=True):
method update_key_value (line 384) | def update_key_value(self, key, value, save=True):
method write_key_value (line 388) | def write_key_value(self, item, value, save=True):
class BitFieldSetting (line 411) | class BitFieldSetting(Setting):
method read (line 415) | def read(self, cached=True):
method _do_read (line 438) | def _do_read(self):
method read_key (line 441) | def read_key(self, key, cached=True):
method _do_read_key (line 461) | def _do_read_key(self, key):
method write (line 464) | def write(self, map, save=True):
method update_key_value (line 485) | def update_key_value(self, key, value, save=True):
method write_key_value (line 489) | def write_key_value(self, key, value, save=True):
class BitFieldWithOffsetAndMaskSetting (line 518) | class BitFieldWithOffsetAndMaskSetting(BitFieldSetting):
method _do_read (line 523) | def _do_read(self):
method _do_read_key (line 526) | def _do_read_key(self, key):
class RangeFieldSetting (line 531) | class RangeFieldSetting(Setting):
method read (line 535) | def read(self, cached=True):
method _do_read (line 555) | def _do_read(self):
method read_key (line 558) | def read_key(self, key, cached=True):
method write (line 561) | def write(self, map, save=True):
method write_key_value (line 580) | def write_key_value(self, key, value, save=True):
class RegisterRW (line 599) | class RegisterRW:
method __init__ (line 604) | def __init__(self, register: int):
method read (line 608) | def read(self, device):
method write (line 611) | def write(self, device, data_bytes):
class FeatureRW (line 615) | class FeatureRW:
method __init__ (line 620) | def __init__(
method read (line 639) | def read(self, device, data_bytes=b""):
method write (line 646) | def write(self, device, data_bytes):
class FeatureRWMap (line 653) | class FeatureRWMap(FeatureRW):
method __init__ (line 659) | def __init__(
method read (line 674) | def read(self, device, key):
method write (line 679) | def write(self, device, key, data_bytes):
class ActionSettingRW (line 686) | class ActionSettingRW:
method __init__ (line 689) | def __init__(self, feature, name="", divert_setting_name="divert-keys"):
method activate_action (line 699) | def activate_action(self): # action to take when setting is activated...
method deactivate_action (line 702) | def deactivate_action(self): # action to take when setting is deactiv...
method press_action (line 705) | def press_action(self): # action to take when key is pressed
method release_action (line 708) | def release_action(self): # action to take when key is released
method move_action (line 711) | def move_action(self, dx, dy): # action to take when mouse is moved w...
method key_action (line 714) | def key_action(self, key): # acction to take when some other diverted...
method read (line 717) | def read(self, device): # need to return bytes, as if read from device
method write (line 720) | def write(self, device, data_bytes):
class RawXYProcessing (line 778) | class RawXYProcessing:
method __init__ (line 781) | def __init__(self, device, name=""):
method handler (line 790) | def handler(self, device, n): # Called on notification events from th...
method start (line 814) | def start(self, key):
method stop (line 824) | def stop(self, key): # only stop if this is the active key
method activate_action (line 839) | def activate_action(self): # action to take when processing is activated
method deactivate_action (line 842) | def deactivate_action(self): # action to take when processing is deac...
method press_action (line 845) | def press_action(self, key): # action to take when an initiating key ...
method release_action (line 848) | def release_action(self): # action to take when key is released
method move_action (line 851) | def move_action(self, dx, dy): # action to take when mouse is moved w...
method key_action (line 854) | def key_action(self, key): # acction to take when some other diverted...
function apply_all_settings (line 858) | def apply_all_settings(device):
FILE: lib/logitech_receiver/settings_new.py
class Setting (line 30) | class Setting:
method __init__ (line 48) | def __init__(self, device, device_object):
method build (line 53) | def build(cls, device):
method check_properties (line 61) | def check_properties(cl, cls):
method setup_from_class (line 67) | def setup_from_class(self, clss):
method _pre_read (line 82) | def _pre_read(self, cached):
method read (line 92) | def read(self, cached=True):
method write (line 106) | def write(self, value, save=True):
method apply (line 110) | def apply(self):
method range (line 124) | def range(self):
method val_to_string (line 128) | def val_to_string(self, value):
class Settings (line 135) | class Settings(Setting):
method __init__ (line 144) | def __init__(self, device, device_object):
method read (line 148) | def read(self, cached=True):
method read_key (line 156) | def read_key(self, key, cached=True):
method write (line 175) | def write(self, value, save=True):
method write_key_value (line 186) | def write_key_value(self, key, value, save=True):
FILE: lib/logitech_receiver/settings_templates.py
class State (line 54) | class State(enum.Enum):
class FnSwapVirtual (line 136) | class FnSwapVirtual(settings.Setting): # virtual setting to hold fn swa...
class RegisterHandDetection (line 152) | class RegisterHandDetection(settings.Setting):
class RegisterSmoothScroll (line 160) | class RegisterSmoothScroll(settings.Setting):
class RegisterSideScroll (line 168) | class RegisterSideScroll(settings.Setting):
class RegisterDpi (line 180) | class RegisterDpi(settings.Setting):
class RegisterFnSwap (line 190) | class RegisterFnSwap(FnSwapVirtual):
class _PerformanceMXDpi (line 195) | class _PerformanceMXDpi(RegisterDpi):
class K375sFnSwap (line 227) | class K375sFnSwap(FnSwapVirtual):
class rw_class (line 231) | class rw_class(settings.FeatureRW):
method find_current_host (line 232) | def find_current_host(self, device):
method read (line 237) | def read(self, device, data_bytes=b""):
method write (line 241) | def write(self, device, data_bytes):
class FnSwap (line 246) | class FnSwap(FnSwapVirtual):
class NewFnSwap (line 250) | class NewFnSwap(FnSwapVirtual):
class Backlight (line 254) | class Backlight(settings.Setting):
class Backlight2 (line 266) | class Backlight2(settings.Setting):
class rw_class (line 274) | class rw_class:
method __init__ (line 275) | def __init__(self, feature):
method read (line 279) | def read(self, device):
method write (line 286) | def write(self, device, data_bytes):
class validator_class (line 294) | class validator_class(settings_validator.ChoicesValidator):
method build (line 296) | def build(cls, setting_class, device):
class Backlight2Level (line 309) | class Backlight2Level(settings.Setting):
class rw_class (line 316) | class rw_class:
method __init__ (line 317) | def __init__(self, feature):
method read (line 321) | def read(self, device):
method write (line 325) | def write(self, device, data_bytes):
class validator_class (line 331) | class validator_class(settings_validator.RangeValidator):
method build (line 333) | def build(cls, setting_class, device):
class Backlight2Duration (line 340) | class Backlight2Duration(settings.Setting):
class rw_class (line 348) | class rw_class:
method __init__ (line 349) | def __init__(self, feature, field):
method read (line 354) | def read(self, device):
method write (line 358) | def write(self, device, data_bytes):
class Backlight2DurationHandsOut (line 367) | class Backlight2DurationHandsOut(Backlight2Duration):
class Backlight2DurationHandsIn (line 376) | class Backlight2DurationHandsIn(Backlight2Duration):
class Backlight2DurationPowered (line 385) | class Backlight2DurationPowered(Backlight2Duration):
class Backlight3 (line 394) | class Backlight3(settings.Setting):
class HiResScroll (line 406) | class HiResScroll(settings.Setting):
class LowresMode (line 417) | class LowresMode(settings.Setting):
class HiresSmoothInvert (line 426) | class HiresSmoothInvert(settings.Setting):
class HiresSmoothResolution (line 435) | class HiresSmoothResolution(settings.Setting):
class HiresMode (line 448) | class HiresMode(settings.Setting):
class PointerSpeed (line 459) | class PointerSpeed(settings.Setting):
class ThumbMode (line 470) | class ThumbMode(settings.Setting):
class ThumbInvert (line 481) | class ThumbInvert(settings.Setting):
function profile_change (line 491) | def profile_change(device, profile_sector):
class OnboardProfiles (line 502) | class OnboardProfiles(settings.Setting):
class rw_class (line 513) | class rw_class:
method __init__ (line 514) | def __init__(self, feature):
method read (line 518) | def read(self, device):
method write (line 526) | def write(self, device, data_bytes):
class validator_class (line 535) | class validator_class(settings_validator.ChoicesValidator):
method build (line 537) | def build(cls, setting_class, device):
class ReportRate (line 547) | class ReportRate(settings.Setting):
class validator_class (line 565) | class validator_class(settings_validator.ChoicesValidator):
method build (line 567) | def build(cls, setting_class, device):
class ExtendedReportRate (line 580) | class ExtendedReportRate(settings.Setting):
class validator_class (line 597) | class validator_class(settings_validator.ChoicesValidator):
method build (line 599) | def build(cls, setting_class, device):
class DivertCrown (line 610) | class DivertCrown(settings.Setting):
class CrownSmooth (line 619) | class CrownSmooth(settings.Setting):
class DivertGkeys (line 628) | class DivertGkeys(settings.Setting):
class rw_class (line 635) | class rw_class(settings.FeatureRW):
method __init__ (line 636) | def __init__(self, feature):
method read (line 639) | def read(self, device): # no way to read, so just assume not diverted
class ScrollRatchet (line 643) | class ScrollRatchet(settings.Setting):
class SmartShift (line 653) | class SmartShift(settings.Setting):
class rw_class (line 663) | class rw_class(settings.FeatureRW):
method __init__ (line 667) | def __init__(self, feature, read_fnid, write_fnid):
method read (line 670) | def read(self, device):
method write (line 680) | def write(self, device, data_bytes):
class SmartShiftEnhanced (line 695) | class SmartShiftEnhanced(SmartShift):
class ScrollRatchetEnhanced (line 700) | class ScrollRatchetEnhanced(ScrollRatchet):
class ScrollRatchetTorque (line 705) | class ScrollRatchetTorque(settings.Setting):
class rw_class (line 714) | class rw_class(settings.FeatureRW):
method write (line 715) | def write(self, device, data_bytes):
class validator_class (line 723) | class validator_class(settings_validator.RangeValidator):
method build (line 725) | def build(cls, setting_class, device):
class ReprogrammableKeys (line 741) | class ReprogrammableKeys(settings.Settings):
class rw_class (line 755) | class rw_class:
method __init__ (line 756) | def __init__(self, feature):
method read (line 760) | def read(self, device, key):
method write (line 765) | def write(self, device, key, data_bytes):
class validator_class (line 771) | class validator_class(settings_validator.ChoicesMapValidator):
method build (line 773) | def build(cls, setting_class, device):
class DpiSlidingXY (line 783) | class DpiSlidingXY(settings.RawXYProcessing):
method __init__ (line 784) | def __init__(
method activate_action (line 794) | def activate_action(self):
method setNewDpi (line 804) | def setNewDpi(self, newDpiIdx):
method displayNewDpi (line 810) | def displayNewDpi(self, newDpiIdx):
method press_action (line 817) | def press_action(self, key): # start tracking
method release_action (line 825) | def release_action(self): # adjust DPI and stop tracking
method move_action (line 837) | def move_action(self, dx, dy):
class MouseGesturesXY (line 855) | class MouseGesturesXY(settings.RawXYProcessing):
method activate_action (line 856) | def activate_action(self):
method initialize_data (line 861) | def initialize_data(self):
method press_action (line 867) | def press_action(self, key):
method release_action (line 874) | def release_action(self):
method move_action (line 885) | def move_action(self, dx, dy):
method key_action (line 900) | def key_action(self, key):
method push_mouse_event (line 908) | def push_mouse_event(self):
class DivertKeys (line 922) | class DivertKeys(settings.Settings):
class rw_class (line 932) | class rw_class:
method __init__ (line 933) | def __init__(self, feature):
method read (line 937) | def read(self, device, key):
method write (line 942) | def write(self, device, key, data_bytes):
class validator_class (line 948) | class validator_class(settings_validator.ChoicesMapValidator):
method __init__ (line 949) | def __init__(self, choices, key_byte_count=2, byte_count=1, mask=0x01):
method prepare_write (line 952) | def prepare_write(self, key, new_value):
method build (line 964) | def build(cls, setting_class, device):
function produce_dpi_list (line 990) | def produce_dpi_list(feature, function, ignore, device, direction):
class AdjustableDpi (line 1016) | class AdjustableDpi(settings.Setting):
class validator_class (line 1024) | class validator_class(settings_validator.ChoicesValidator):
method build (line 1026) | def build(cls, setting_class, device):
method validate_read (line 1034) | def validate_read(self, reply_bytes): # special validator to use de...
class ExtendedAdjustableDpi (line 1043) | class ExtendedAdjustableDpi(settings.Setting):
method write_key_value (line 1057) | def write_key_value(self, key, value, save=True):
class validator_class (line 1065) | class validator_class(settings_validator.ChoicesMapValidator):
method build (line 1067) | def build(cls, setting_class, device):
method validate_read (line 1085) | def validate_read(self, reply_bytes): # special validator to read e...
method prepare_write (line 1099) | def prepare_write(self, new_value, current_value=None): # special p...
class SpeedChange (line 1119) | class SpeedChange(settings.Setting):
class rw_class (line 1133) | class rw_class(settings.ActionSettingRW):
method press_action (line 1134) | def press_action(self): # switch sensitivity
class validator_class (line 1148) | class validator_class(settings_validator.ChoicesValidator):
method build (line 1150) | def build(cls, setting_class, device):
class DisableKeyboardKeys (line 1158) | class DisableKeyboardKeys(settings.BitFieldSetting):
class validator_class (line 1167) | class validator_class(settings_validator.BitFieldValidator):
method build (line 1169) | def build(cls, setting_class, device):
class Multiplatform (line 1175) | class Multiplatform(settings.Setting):
class validator_class (line 1199) | class validator_class(settings_validator.ChoicesValidator):
method build (line 1201) | def build(cls, setting_class, device):
class DualPlatform (line 1232) | class DualPlatform(settings.Setting):
class ChangeHost (line 1245) | class ChangeHost(settings.Setting):
class validator_class (line 1254) | class validator_class(settings_validator.ChoicesValidator):
method build (line 1256) | def build(cls, setting_class, device):
class Gesture2Gestures (line 1356) | class Gesture2Gestures(settings.BitFieldWithOffsetAndMaskSetting):
class validator_class (line 1366) | class validator_class(settings_validator.BitFieldWithOffsetAndMaskVali...
method build (line 1368) | def build(cls, setting_class, device, om_method=None):
class Gesture2Divert (line 1373) | class Gesture2Divert(settings.BitFieldWithOffsetAndMaskSetting):
class validator_class (line 1383) | class validator_class(settings_validator.BitFieldWithOffsetAndMaskVali...
method build (line 1385) | def build(cls, setting_class, device, om_method=None):
class Gesture2Params (line 1390) | class Gesture2Params(settings.LongSettings):
class validator_class (line 1404) | class validator_class(settings_validator.MultipleRangeValidator):
method build (line 1406) | def build(cls, setting_class, device):
class MKeyLEDs (line 1415) | class MKeyLEDs(settings.BitFieldSetting):
class rw_class (line 1431) | class rw_class(settings.FeatureRW):
method __init__ (line 1432) | def __init__(self, feature):
method read (line 1435) | def read(self, device): # no way to read, so just assume off
class validator_class (line 1438) | class validator_class(settings_validator.BitFieldValidator):
method build (line 1440) | def build(cls, setting_class, device):
class MRKeyLED (line 1446) | class MRKeyLED(settings.Setting):
class rw_class (line 1458) | class rw_class(settings.FeatureRW):
method __init__ (line 1459) | def __init__(self, feature):
method read (line 1462) | def read(self, device): # no way to read, so just assume off
class PersistentRemappableAction (line 1469) | class PersistentRemappableAction(settings.Settings):
class rw_class (line 1482) | class rw_class:
method __init__ (line 1483) | def __init__(self, feature):
method read (line 1487) | def read(self, device, key):
method write (line 1491) | def write(self, device, key, data_bytes):
class validator_class (line 1496) | class validator_class(settings_validator.ChoicesMapValidator):
method build (line 1498) | def build(cls, setting_class, device):
method validate_read (line 1518) | def validate_read(self, reply_bytes, key):
class Sidetone (line 1530) | class Sidetone(settings.Setting):
class Equalizer (line 1540) | class Equalizer(settings.RangeFieldSetting):
class validator_class (line 1548) | class validator_class(settings_validator.PackedRangeValidator):
method build (line 1550) | def build(cls, setting_class, device):
class ADCPower (line 1569) | class ADCPower(settings.Setting):
class BrightnessControl (line 1582) | class BrightnessControl(settings.Setting):
method __init__ (line 1590) | def __init__(self, device, rw, validator):
class rw_class (line 1596) | class rw_class(settings.FeatureRW):
method read (line 1597) | def read(self, device, data_bytes=b""):
method write (line 1604) | def write(self, device, data_bytes):
class validator_class (line 1612) | class validator_class(settings_validator.RangeValidator):
method build (line 1614) | def build(cls, setting_class, device):
class LEDControl (line 1626) | class LEDControl(settings.Setting):
class LEDZoneSetting (line 1642) | class LEDZoneSetting(settings.Setting):
method setup (line 1655) | def setup(cls, device, read_fnid, write_fnid, suffix):
method build (line 1675) | def build(cls, device):
class RGBControl (line 1679) | class RGBControl(settings.Setting):
class RGBEffectSetting (line 1690) | class RGBEffectSetting(LEDZoneSetting):
method build (line 1697) | def build(cls, device):
class PerKeyLighting (line 1701) | class PerKeyLighting(settings.Settings):
method read (line 1709) | def read(self, cached=True):
method write (line 1719) | def write(self, map, save=True):
method write_key_value (line 1752) | def write_key_value(self, key, value, save=True):
class rw_class (line 1761) | class rw_class(settings.FeatureRWMap):
class validator_class (line 1764) | class validator_class(settings_validator.ChoicesMapValidator):
method build (line 1766) | def build(cls, setting_class, device):
class ForceSensing (line 1784) | class ForceSensing(settings_new.Settings):
method build (line 1797) | def build(cls, device):
class HapticLevel (line 1812) | class HapticLevel(settings.Setting):
class rw_class (line 1821) | class rw_class(settings.FeatureRW):
method __init__ (line 1822) | def __init__(self, feature):
method read (line 1825) | def read(self, device, data_bytes=b""):
method write (line 1832) | def write(self, device, data_bytes):
method build (line 1841) | def build(cls, device):
class PlayHapticWaveForm (line 1855) | class PlayHapticWaveForm(settings.Setting):
class validator_class (line 1865) | class validator_class(settings_validator.ChoicesValidator):
method build (line 1867) | def build(cls, setting_class, device):
class SettingsProtocol (line 1943) | class SettingsProtocol(Protocol):
method name (line 1945) | def name(self):
method label (line 1949) | def label(self):
method description (line 1953) | def description(self):
method feature (line 1957) | def feature(self):
method register (line 1961) | def register(self):
method kind (line 1965) | def kind(self):
method min_version (line 1969) | def min_version(self):
method persist (line 1973) | def persist(self):
method rw_options (line 1977) | def rw_options(self):
method validator_class (line 1981) | def validator_class(self):
method validator_options (line 1985) | def validator_options(self):
method build (line 1989) | def build(cls, device):
method val_to_string (line 1992) | def val_to_string(self, value):
method choices (line 1996) | def choices(self):
method range (line 2000) | def range(self):
method _pre_read (line 2003) | def _pre_read(self, cached, key=None):
method read (line 2006) | def read(self, cached=True):
method _pre_write (line 2009) | def _pre_write(self, save=True):
method update (line 2012) | def update(self, value, save=True):
method write (line 2015) | def write(self, value, save=True):
method acceptable (line 2018) | def acceptable(self, args, current):
method compare (line 2021) | def compare(self, args, current):
method apply (line 2024) | def apply(self):
method __str__ (line 2027) | def __str__(self):
function check_feature (line 2031) | def check_feature(device, settings_class: SettingsProtocol) -> None | bo...
function check_feature_settings (line 2050) | def check_feature_settings(device, already_known) -> bool:
function check_feature_setting (line 2101) | def check_feature_setting(device, setting_name: str) -> settings.Setting...
FILE: lib/logitech_receiver/settings_validator.py
function bool_or_toggle (line 15) | def bool_or_toggle(current: bool | str, new: bool | str) -> bool:
class Kind (line 33) | class Kind(IntEnum):
class Validator (line 44) | class Validator:
method build (line 46) | def build(cls, setting_class, device, **kwargs) -> Validator:
method to_string (line 50) | def to_string(cls, value) -> str:
method compare (line 53) | def compare(self, args, current):
class BooleanValidator (line 59) | class BooleanValidator(Validator):
method __init__ (line 68) | def __init__(
method validate_read (line 112) | def validate_read(self, reply_bytes):
method prepare_write (line 148) | def prepare_write(self, new_value, current_value=None):
method acceptable (line 183) | def acceptable(self, args, current):
class BitFieldValidator (line 190) | class BitFieldValidator(Validator):
method __init__ (line 195) | def __init__(self, options, byte_count=None):
method to_string (line 203) | def to_string(self, value) -> str:
method validate_read (line 210) | def validate_read(self, reply_bytes):
method prepare_write (line 220) | def prepare_write(self, new_value):
method get_options (line 228) | def get_options(self):
method acceptable (line 231) | def acceptable(self, args, current):
method compare (line 240) | def compare(self, args, current):
class BitFieldWithOffsetAndMaskValidator (line 249) | class BitFieldWithOffsetAndMaskValidator(Validator):
method __init__ (line 255) | def __init__(self, options, om_method=None, byte_count=None):
method prepare_read (line 285) | def prepare_read(self):
method prepare_read_key (line 293) | def prepare_read_key(self, key):
method validate_read (line 302) | def validate_read(self, reply_bytes_dict):
method prepare_write (line 316) | def prepare_write(self, new_value):
method get_options (line 337) | def get_options(self):
method acceptable (line 340) | def acceptable(self, args, current):
method compare (line 349) | def compare(self, args, current):
class ChoicesValidator (line 358) | class ChoicesValidator(Validator):
method __init__ (line 366) | def __init__(self, choices=None, byte_count=None, read_skip_byte_count...
method to_string (line 384) | def to_string(self, value) -> str:
method validate_read (line 387) | def validate_read(self, reply_bytes):
method prepare_write (line 393) | def prepare_write(self, new_value, current_value=None):
method choice (line 403) | def choice(self, value):
method acceptable (line 417) | def acceptable(self, args, current):
class ChoicesMapValidator (line 422) | class ChoicesMapValidator(ChoicesValidator):
method __init__ (line 425) | def __init__(
method to_string (line 468) | def to_string(self, value) -> str:
method validate_read (line 475) | def validate_read(self, reply_bytes, key):
method prepare_key (line 489) | def prepare_key(self, key):
method prepare_write (line 492) | def prepare_write(self, key, new_value):
method acceptable (line 500) | def acceptable(self, args, current):
method compare (line 509) | def compare(self, args, current):
class RangeValidator (line 518) | class RangeValidator(Validator):
method build (line 529) | def build(cls, setting_class, device, **kwargs):
method __init__ (line 534) | def __init__(self, min_value=0, max_value=255, byte_count=1, read_skip...
method validate_read (line 547) | def validate_read(self, reply_bytes):
method prepare_write (line 553) | def prepare_write(self, new_value, current_value=None):
method acceptable (line 561) | def acceptable(self, args, current):
method compare (line 566) | def compare(self, args, current):
class HeteroValidator (line 575) | class HeteroValidator(Validator):
method build (line 579) | def build(cls, setting_class, device, **kwargs):
method __init__ (line 582) | def __init__(self, data_class=None, options=None, readable=True):
method validate_read (line 589) | def validate_read(self, reply_bytes):
method prepare_write (line 594) | def prepare_write(self, new_value, current_value=None):
method acceptable (line 598) | def acceptable(self, args, current): # should this actually do some c...
class PackedRangeValidator (line 602) | class PackedRangeValidator(Validator):
method __init__ (line 611) | def __init__(
method validate_read (line 628) | def validate_read(self, reply_bytes):
method prepare_write (line 638) | def prepare_write(self, new_values):
method acceptable (line 649) | def acceptable(self, args, current):
method compare (line 654) | def compare(self, args, current):
class MultipleRangeValidator (line 659) | class MultipleRangeValidator(Validator):
method __init__ (line 662) | def __init__(self, items, sub_items):
method prepare_read_item (line 671) | def prepare_read_item(self, item):
method validate_read_item (line 674) | def validate_read_item(self, reply_bytes, item):
method prepare_write (line 692) | def prepare_write(self, value):
method prepare_write_item (line 715) | def prepare_write_item(self, item, value):
method acceptable (line 728) | def acceptable(self, args, current):
method compare (line 743) | def compare(self, args, current):
FILE: lib/logitech_receiver/special_keys.py
class Task (line 340) | class Task(IntEnum):
method __str__ (line 592) | def __str__(self):
class CIDGroupBit (line 596) | class CIDGroupBit(IntEnum):
class CidGroup (line 607) | class CidGroup(IntEnum):
class HorizontalScroll (line 1224) | class HorizontalScroll(IntEnum):
function persistent_keys (line 1267) | def persistent_keys(action_ids):
FILE: lib/solaar/cli/__init__.py
function _create_parser (line 34) | def _create_parser():
function _receivers (line 111) | def _receivers(dev_path=None):
function _receivers_and_devices (line 125) | def _receivers_and_devices(dev_path=None):
function _find_receiver (line 143) | def _find_receiver(receivers, name):
function _find_device (line 152) | def _find_device(receivers, name):
function run (line 192) | def run(cli_args=None, hidraw_path=None):
FILE: lib/solaar/cli/config.py
function _print_setting (line 29) | def _print_setting(s, verbose=True):
function _print_setting_keyed (line 52) | def _print_setting_keyed(s, key, verbose=True):
function to_int (line 81) | def to_int(s):
function select_choice (line 88) | def select_choice(value, choices, setting, key):
function select_toggle (line 119) | def select_toggle(value, setting, key=None):
function select_range (line 135) | def select_range(value, setting):
function run (line 146) | def run(receivers, args, _find_receiver, find_device):
function set (line 220) | def set(dev, setting: SettingsProtocol, args, save):
FILE: lib/solaar/cli/pair.py
function run (line 27) | def run(receivers, args, find_receiver, _ignore):
FILE: lib/solaar/cli/probe.py
function run (line 26) | def run(receivers, args, find_receiver, _ignore):
FILE: lib/solaar/cli/profiles.py
function run (line 25) | def run(receivers, args, find_receiver, find_device):
FILE: lib/solaar/cli/show.py
function _print_receiver (line 37) | def _print_receiver(receiver):
function _battery_text (line 70) | def _battery_text(level) -> str:
function _battery_line (line 79) | def _battery_line(dev):
function _print_device (line 92) | def _print_device(dev, num=None):
function run (line 316) | def run(devices, args, find_receiver, find_device):
FILE: lib/solaar/cli/unpair.py
function run (line 18) | def run(receivers, args, find_receiver, find_device):
FILE: lib/solaar/configuration.py
function _load (line 46) | def _load():
function _parse_config (line 70) | def _parse_config(loaded_config, config_path):
function _device_entry_from_config_dict (line 96) | def _device_entry_from_config_dict(data, discard_derived_properties):
function save (line 126) | def save(defer=False):
function do_save (line 146) | def do_save():
function _convert_json (line 160) | def _convert_json(json_dict):
class _DeviceEntry (line 182) | class _DeviceEntry(dict):
method __init__ (line 183) | def __init__(self, **kwargs):
method __setitem__ (line 186) | def __setitem__(self, key, value):
method update (line 190) | def update(self, name, wpid, serial, modelId, unitId):
method get_sensitivity (line 202) | def get_sensitivity(self, name):
method set_sensitivity (line 205) | def set_sensitivity(self, name, value):
function device_representer (line 212) | def device_representer(dumper, data):
function named_int_representer (line 219) | def named_int_representer(dumper, data):
function persister (line 232) | def persister(device):
function attach_to (line 268) | def attach_to(device):
FILE: lib/solaar/custom_logger.py
class CustomLogger (line 4) | class CustomLogger(logging.Logger):
method debug (line 10) | def debug(self, msg, *args, **kwargs):
method info (line 14) | def info(self, msg, *args, **kwargs):
method warning (line 18) | def warning(self, msg, *args, **kwargs):
method error (line 22) | def error(self, msg, *args, **kwargs):
method critical (line 26) | def critical(self, msg, *args, **kwargs):
FILE: lib/solaar/dbus.py
function _suspend_or_resume (line 44) | def _suspend_or_resume(suspend):
function watch_suspend_resume (line 55) | def watch_suspend_resume(
function watch_bluez_connect (line 80) | def watch_bluez_connect(serial, callback=None):
FILE: lib/solaar/gtk.py
function _require (line 45) | def _require(module, os_package, gi=None, gi_package=None, gi_version=No...
function create_parser (line 59) | def create_parser():
function _parse_arguments (line 110) | def _parse_arguments():
function _handlesig (line 147) | def _handlesig(signl, stack):
function main (line 159) | def main():
FILE: lib/solaar/i18n.py
function _find_locale_path (line 32) | def _find_locale_path(locale_domain: str) -> str:
function set_locale_to_system_default (line 43) | def set_locale_to_system_default() -> None:
FILE: lib/solaar/listener.py
function _ghost (line 62) | def _ghost(device):
class SolaarListener (line 68) | class SolaarListener(listener.EventsListener):
method __init__ (line 71) | def __init__(self, receiver, status_changed_callback):
method has_started (line 77) | def has_started(self):
method has_stopped (line 89) | def has_stopped(self):
method _status_changed (line 105) | def _status_changed(self, device, alert=None, reason=None):
method _notifications_handler (line 149) | def _notifications_handler(self, n):
method __str__ (line 231) | def __str__(self):
function _process_bluez_dbus (line 235) | def _process_bluez_dbus(device: Device, path, dictionary: dict, signature):
function _cleanup_bluez_dbus (line 249) | def _cleanup_bluez_dbus(device: Device):
function _start (line 258) | def _start(device_info: DeviceInfo):
function start_all (line 280) | def start_all():
function stop_all (line 287) | def stop_all():
function ping_all (line 302) | def ping_all(resuming=False):
function setup_scanner (line 333) | def setup_scanner(status_changed_callback: Callable, setting_changed_cal...
function _process_add (line 342) | def _process_add(device_info: DeviceInfo, retry):
function _process_receiver_event (line 363) | def _process_receiver_event(action, device_info):
FILE: lib/solaar/tasks.py
class TaskRunner (line 31) | class TaskRunner(Thread):
method __init__ (line 32) | def __init__(self, name):
method __call__ (line 38) | def __call__(self, function, *args, **kwargs):
method stop (line 42) | def stop(self):
method run (line 46) | def run(self):
FILE: lib/solaar/ui/__init__.py
class GtkSignal (line 52) | class GtkSignal(Enum):
function _startup (line 58) | def _startup(app, startup_hook, use_tray, show_window):
function _activate (line 68) | def _activate(app):
function _command_line (line 76) | def _command_line(app, command_line):
function _shutdown (line 91) | def _shutdown(_app, shutdown_hook):
function run_loop (line 99) | def run_loop(
function _status_changed (line 124) | def _status_changed(device, alert, reason, refresh=False):
function status_changed (line 144) | def status_changed(device, alert=Alert.NONE, reason=None, refresh=False):
function setting_changed (line 148) | def setting_changed(device, setting_class, vals):
FILE: lib/solaar/ui/about/about.py
function show (line 22) | def show(_=None, model=None, view=None):
FILE: lib/solaar/ui/about/model.py
function _get_current_year (line 27) | def _get_current_year() -> int:
class AboutModel (line 31) | class AboutModel:
method get_version (line 32) | def get_version(self) -> str:
method get_description (line 35) | def get_description(self) -> str:
method get_copyright (line 38) | def get_copyright(self) -> str:
method get_authors (line 41) | def get_authors(self) -> List[str]:
method get_translators (line 46) | def get_translators(self) -> List[str]:
method get_credit_sections (line 62) | def get_credit_sections(self) -> List[Tuple[str, List[str]]]:
method get_website (line 83) | def get_website(self):
FILE: lib/solaar/ui/about/presenter.py
class AboutViewProtocol (line 24) | class AboutViewProtocol(Protocol):
method init_ui (line 25) | def init_ui(self) -> None:
method update_version_info (line 28) | def update_version_info(self, version: str) -> None:
method update_description (line 31) | def update_description(self, comments: str) -> None:
method update_copyright (line 34) | def update_copyright(self, copyright_text: str) -> None:
method update_authors (line 37) | def update_authors(self, authors: list[str]) -> None:
method update_translators (line 40) | def update_translators(self, translators: list[str]) -> None:
method update_website (line 43) | def update_website(self, website):
method update_credits (line 46) | def update_credits(self, credit_sections: list[tuple[str, list[str]]])...
method show (line 49) | def show(self) -> None:
class Presenter (line 53) | class Presenter:
method __init__ (line 54) | def __init__(self, model: AboutModel, view: AboutViewProtocol) -> None:
method update_version_info (line 58) | def update_version_info(self) -> None:
method update_credits (line 62) | def update_credits(self) -> None:
method update_description (line 66) | def update_description(self) -> None:
method update_copyright (line 70) | def update_copyright(self) -> None:
method update_authors (line 74) | def update_authors(self) -> None:
method update_translators (line 78) | def update_translators(self) -> None:
method update_website (line 82) | def update_website(self) -> None:
method run (line 86) | def run(self) -> None:
FILE: lib/solaar/ui/about/view.py
class GtkSignal (line 26) | class GtkSignal(Enum):
class AboutView (line 30) | class AboutView:
method __init__ (line 31) | def __init__(self) -> None:
method init_ui (line 34) | def init_ui(self) -> None:
method update_version_info (line 42) | def update_version_info(self, version: str) -> None:
method update_description (line 45) | def update_description(self, comments: str) -> None:
method update_copyright (line 48) | def update_copyright(self, copyright_text: str):
method update_authors (line 51) | def update_authors(self, authors: List[str]) -> None:
method update_credits (line 54) | def update_credits(self, credit_sections: List[Tuple[str, List[str]]])...
method update_translators (line 58) | def update_translators(self, translators: List[str]) -> None:
method update_website (line 62) | def update_website(self, website):
method show (line 66) | def show(self) -> None:
method handle_close (line 69) | def handle_close(self, event) -> None:
FILE: lib/solaar/ui/action.py
class GtkSignal (line 28) | class GtkSignal(Enum):
function make_image_menu_item (line 32) | def make_image_menu_item(label, icon_name, function, *args):
function make (line 47) | def make(name, label, function, stock_id=None, *args):
function make_toggle (line 57) | def make_toggle(name, label, function, stock_id=None, *args):
function pair (line 66) | def pair(window, receiver):
function unpair (line 79) | def unpair(window, device):
FILE: lib/solaar/ui/common.py
class ErrorReason (line 34) | class ErrorReason(Enum):
function _create_error_text (line 40) | def _create_error_text(reason: ErrorReason, object_) -> Tuple[str, str]:
function _error_dialog (line 70) | def _error_dialog(reason: ErrorReason, object_):
function error_dialog (line 80) | def error_dialog(reason: ErrorReason, object_):
function start_async (line 87) | def start_async():
function stop_async (line 93) | def stop_async():
function ui_async (line 99) | def ui_async(function, *args, **kwargs):
FILE: lib/solaar/ui/config_panel.py
class GtkSignal (line 41) | class GtkSignal(Enum):
function _read_async (line 52) | def _read_async(setting, force_read, sbox, device_is_online, sensitive):
function _write_async (line 64) | def _write_async(setting, value, sbox, sensitive=True, key=None):
class ComboBoxText (line 85) | class ComboBoxText(Gtk.ComboBoxText):
method get_value (line 86) | def get_value(self):
method set_value (line 89) | def set_value(self, value):
class Scale (line 93) | class Scale(Gtk.Scale):
method get_value (line 94) | def get_value(self):
class Control (line 98) | class Control:
method __init__ (line 99) | def __init__(self, **kwargs):
method init (line 103) | def init(self, sbox, delegate):
method changed (line 107) | def changed(self, *args):
method update (line 111) | def update(self):
method layout (line 114) | def layout(self, sbox, label, change, spinner, failed):
class ToggleControl (line 124) | class ToggleControl(Gtk.Switch, Control):
method __init__ (line 125) | def __init__(self, sbox, delegate=None):
method set_value (line 130) | def set_value(self, value):
method get_value (line 134) | def get_value(self):
class SliderControl (line 138) | class SliderControl(Gtk.Scale, Control):
method __init__ (line 139) | def __init__(self, sbox, delegate=None):
method set_value (line 149) | def set_value(self, value):
method get_value (line 154) | def get_value(self):
method changed (line 157) | def changed(self, *args):
method do_change (line 164) | def do_change(self):
function _create_choice_control (line 169) | def _create_choice_control(sbox, delegate=None, choices=None):
class ChoiceControlLittle (line 177) | class ChoiceControlLittle(Gtk.ComboBoxText, Control):
method __init__ (line 178) | def __init__(self, sbox, delegate=None, choices=None):
method get_value (line 186) | def get_value(self):
method set_value (line 189) | def set_value(self, value):
method get_choice (line 193) | def get_choice(self):
method set_choices (line 197) | def set_choices(self, choices):
class ChoiceControlBig (line 203) | class ChoiceControlBig(Gtk.Entry, Control):
method __init__ (line 204) | def __init__(self, sbox, delegate=None, choices=None):
method get_value (line 226) | def get_value(self):
method set_value (line 230) | def set_value(self, value):
method get_choice (line 234) | def get_choice(self):
method set_choices (line 238) | def set_choices(self, choices):
method changed (line 241) | def changed(self, *args):
method activate (line 248) | def activate(self, *_args):
method select (line 253) | def select(self, _completion, model, iter):
class MapChoiceControl (line 260) | class MapChoiceControl(Gtk.HBox, Control):
method __init__ (line 261) | def __init__(self, sbox, delegate=None):
method get_value (line 275) | def get_value(self):
method set_value (line 280) | def set_value(self, value):
method map_populate_value_box (line 289) | def map_populate_value_box(self, key_choice):
method map_value_notify_key (line 298) | def map_value_notify_key(self, *_args):
method update (line 303) | def update(self):
class MultipleControl (line 311) | class MultipleControl(Gtk.ListBox, Control):
method __init__ (line 312) | def __init__(self, sbox, change, button_label="...", delegate=None):
method layout (line 333) | def layout(self, sbox, label, change, spinner, failed):
method toggle_display (line 341) | def toggle_display(self, *_args):
class MultipleToggleControl (line 353) | class MultipleToggleControl(MultipleControl):
method setup (line 354) | def setup(self, setting):
method toggle_notify (line 375) | def toggle_notify(self, switch, _active):
method set_value (line 383) | def set_value(self, value):
class MultipleRangeControl (line 401) | class MultipleRangeControl(MultipleControl):
method setup (line 402) | def setup(self, setting):
method changed (line 455) | def changed(self, control, item, sub_item):
method _write (line 462) | def _write(self, control, item, sub_item):
method set_value (line 470) | def set_value(self, value):
class PackedRangeControl (line 496) | class PackedRangeControl(MultipleRangeControl):
method setup (line 497) | def setup(self, setting):
method changed (line 515) | def changed(self, control, item):
method _write (line 522) | def _write(self, control, item):
method set_value (line 530) | def set_value(self, value):
class HeteroKeyControl (line 549) | class HeteroKeyControl(Gtk.HBox, Control):
method __init__ (line 550) | def __init__(self, sbox, delegate=None):
method get_value (line 584) | def get_value(self):
method set_value (line 598) | def set_value(self, value):
method setup_visibles (line 615) | def setup_visibles(self, id_):
method changed (line 623) | def changed(self, control):
method _write (line 632) | def _write(self, control):
function _change_click (line 651) | def _change_click(button, sbox):
function _change_icon (line 671) | def _change_icon(allowed, icon):
function _create_sbox (line 678) | def _create_sbox(s, _device):
function _update_setting_item (line 733) | def _update_setting_item(sbox, value, is_online=True, sensitive=True, nu...
function _disable_listbox_highlight_bg (line 751) | def _disable_listbox_highlight_bg(lb):
function create (line 763) | def create():
function update (line 778) | def update(device, is_online=None):
function clean (line 811) | def clean(device):
function destroy (line 823) | def destroy():
function change_setting (line 829) | def change_setting(device, setting, values):
function _change_setting (line 835) | def _change_setting(device, setting, values):
function record_setting (line 844) | def record_setting(device, setting, values):
function _record_setting (line 849) | def _record_setting(device, setting_class, values):
FILE: lib/solaar/ui/desktop_notifications.py
function notifications_available (line 29) | def notifications_available():
function init (line 56) | def init():
function uninit (line 69) | def uninit():
function alert (line 76) | def alert(reason, icon=None):
function show (line 97) | def show(dev, reason=None, icon=None, progress=None):
function init (line 131) | def init():
function uninit (line 134) | def uninit():
function alert (line 138) | def alert(reason):
function show (line 141) | def show(dev, reason=None):
FILE: lib/solaar/ui/diversion_rules.py
class GtkSignal (line 59) | class GtkSignal(Enum):
function create_all_settings (line 71) | def create_all_settings(all_settings: list[Setting]) -> dict[str, list[S...
class RuleComponentWrapper (line 93) | class RuleComponentWrapper(GObject.GObject):
method __init__ (line 94) | def __init__(self, component, level=0, editable=False):
method display_left (line 100) | def display_left(self):
method display_right (line 111) | def display_right(self):
method display_icon (line 116) | def display_icon(self):
method __component_ui (line 123) | def __component_ui(self):
function _create_close_dialog (line 127) | def _create_close_dialog(window: Gtk.Window) -> Gtk.MessageDialog:
function _create_selected_rule_edit_panel (line 148) | def _create_selected_rule_edit_panel() -> Gtk.Grid:
function _populate_model (line 164) | def _populate_model(
class AllowedActions (line 195) | class AllowedActions:
function allowed_actions (line 206) | def allowed_actions(m: Gtk.TreeStore, it: Gtk.TreeIter) -> AllowedActions:
class ActionMenu (line 238) | class ActionMenu:
method __init__ (line 239) | def __init__(
method create_menu_event_button_released (line 251) | def create_menu_event_button_released(self, v, e):
method get_insert_menus (line 300) | def get_insert_menus(self, m, it, enabled_actions: AllowedActions):
method menu_do_flatten (line 327) | def menu_do_flatten(self, _mitem, m, it):
method _menu_flatten (line 346) | def _menu_flatten(self, m, it):
method _menu_do_insert (line 352) | def _menu_do_insert(self, _mitem, m, it, new_c, below=False):
method _menu_do_insert_new (line 374) | def _menu_do_insert_new(self, _mitem, m, it, cls, initial_value, below...
method _menu_insert (line 378) | def _menu_insert(self, m, it, below=False):
method _menu_create_rule (line 440) | def _menu_create_rule(self, m, it, below=False) -> Gtk.MenuItem:
method menu_do_delete (line 446) | def menu_do_delete(self, _mitem, m, it):
method _menu_delete (line 460) | def _menu_delete(self, m, it) -> Gtk.MenuItem:
method menu_do_negate (line 466) | def menu_do_negate(self, _mitem, m, it):
method _menu_negate (line 482) | def _menu_negate(self, m, it) -> Gtk.MenuItem:
method menu_do_wrap (line 488) | def menu_do_wrap(self, _mitem, m, it, cls):
method _menu_wrap (line 506) | def _menu_wrap(self, m, it) -> Gtk.MenuItem:
method menu_do_copy (line 522) | def menu_do_copy(self, _mitem: Gtk.MenuItem, m: Gtk.TreeStore, it: Gtk...
method menu_do_cut (line 529) | def menu_do_cut(self, _mitem, m, it):
method _menu_cut (line 536) | def _menu_cut(self, m, it):
method menu_do_paste (line 542) | def menu_do_paste(self, _mitem, m, it, below=False):
method _menu_paste (line 552) | def _menu_paste(self, m, it, below=False):
method _menu_copy (line 558) | def _menu_copy(self, m, it):
class DiversionDialog (line 565) | class DiversionDialog:
method __init__ (line 566) | def __init__(self, action_menu):
method _closing (line 619) | def _closing(self, window: Gtk.Window, e: Gdk.Event):
method _reload_yaml_file (line 635) | def _reload_yaml_file(self):
method _save_yaml_file (line 646) | def _save_yaml_file(self):
method _create_top_panel (line 652) | def _create_top_panel(self):
method _create_model (line 691) | def _create_model(self):
method _create_view_columns (line 699) | def _create_view_columns(self):
method on_update (line 715) | def on_update(self):
method _selection_changed (line 721) | def _selection_changed(self, selection):
method _event_key_pressed (line 732) | def _event_key_pressed(self, v, e):
method _event_button_released (line 805) | def _event_button_released(self, v, e):
method update_devices (line 808) | def update_devices(self):
class CompletionEntry (line 814) | class CompletionEntry(Gtk.Entry):
method __init__ (line 815) | def __init__(self, values, *args, **kwargs):
method add_completion_to_entry (line 820) | def add_completion_to_entry(cls, entry, values):
class SmartComboBox (line 836) | class SmartComboBox(Gtk.ComboBox):
method __init__ (line 862) | def __init__(
method new_model (line 897) | def new_model(cls):
method set_all_values (line 904) | def set_all_values(self, all_values, visible_fn=(lambda value: True)):
method _include (line 932) | def _include(self, model, idx, value, visible, *names):
method get_value (line 944) | def get_value(self, invalid_as_str=True, accept_hidden=True):
method _find_idx (line 970) | def _find_idx(self, search):
method set_value (line 983) | def set_value(self, value, accept_invalid=True):
method show_only (line 1002) | def show_only(self, only, include_new=False):
class DeviceInfo (line 1020) | class DeviceInfo:
method __post_init__ (line 1026) | def __post_init__(self):
method id (line 1033) | def id(self) -> str:
method identifiers (line 1037) | def identifiers(self) -> list[str]:
method display_name (line 1041) | def display_name(self) -> str:
method matches (line 1044) | def matches(self, search: str) -> bool:
method update (line 1047) | def update(self, device: DeviceInfo) -> None:
class DeviceInfoFactory (line 1055) | class DeviceInfoFactory:
method create_device_info (line 1057) | def create_device_info(cls, device) -> DeviceInfo:
class AllDevicesInfo (line 1063) | class AllDevicesInfo:
method __init__ (line 1064) | def __init__(self):
method __iter__ (line 1068) | def __iter__(self):
method __getitem__ (line 1071) | def __getitem__(self, search):
method refresh (line 1078) | def refresh(self):
class UnsupportedRuleComponentUI (line 1099) | class UnsupportedRuleComponentUI(RuleComponentUI):
method create_widgets (line 1102) | def create_widgets(self):
method collect_value (line 1107) | def collect_value(self):
method right_label (line 1111) | def right_label(cls, component):
class RuleUI (line 1115) | class RuleUI(RuleComponentUI):
method create_widgets (line 1118) | def create_widgets(self):
method collect_value (line 1121) | def collect_value(self):
method left_label (line 1125) | def left_label(cls, component):
method icon_name (line 1129) | def icon_name(cls):
class AndUI (line 1133) | class AndUI(RuleComponentUI):
method create_widgets (line 1136) | def create_widgets(self):
method collect_value (line 1139) | def collect_value(self):
method left_label (line 1143) | def left_label(cls, component):
class OrUI (line 1147) | class OrUI(RuleComponentUI):
method create_widgets (line 1150) | def create_widgets(self):
method collect_value (line 1153) | def collect_value(self):
method left_label (line 1157) | def left_label(cls, component):
class LaterUI (line 1161) | class LaterUI(RuleComponentUI):
method create_widgets (line 1166) | def create_widgets(self):
method show (line 1179) | def show(self, component, editable):
method collect_value (line 1184) | def collect_value(self):
method left_label (line 1188) | def left_label(cls, component):
method right_label (line 1192) | def right_label(cls, component):
class NotUI (line 1196) | class NotUI(RuleComponentUI):
method create_widgets (line 1199) | def create_widgets(self):
method collect_value (line 1202) | def collect_value(self):
method left_label (line 1206) | def left_label(cls, component):
class ActionUI (line 1210) | class ActionUI(RuleComponentUI):
method icon_name (line 1214) | def icon_name(cls):
function _from_named_ints (line 1218) | def _from_named_ints(v, all_values):
class SetValueControlKinds (line 1225) | class SetValueControlKinds(Enum):
class SetValueControl (line 1232) | class SetValueControl(Gtk.HBox):
method __init__ (line 1233) | def __init__(self, on_change, *args, accept_toggle=True, **kwargs):
method _changed (line 1265) | def _changed(self, widget, *args):
method _hide_all (line 1283) | def _hide_all(self):
method get_value (line 1287) | def get_value(self):
method set_value (line 1298) | def set_value(self, value):
method make_toggle (line 1333) | def make_toggle(self):
method make_range (line 1338) | def make_range(self, minimum, maximum):
method make_range_with_key (line 1344) | def make_range_with_key(self, items, labels=None):
method make_choice (line 1356) | def make_choice(self, values, extra=None):
method make_unsupported (line 1369) | def make_unsupported(self):
class _DeviceUI (line 1375) | class _DeviceUI:
method show (line 1378) | def show(self, component, editable):
method create_widgets (line 1385) | def create_widgets(self):
method update_devices (line 1406) | def update_devices(self):
method _update_device_list (line 1409) | def _update_device_list(self):
method collect_value (line 1413) | def collect_value(self):
method right_label (line 1421) | def right_label(cls, component):
class ActiveUI (line 1426) | class ActiveUI(_DeviceUI, ConditionUI):
method left_label (line 1431) | def left_label(cls, component):
class DeviceUI (line 1435) | class DeviceUI(_DeviceUI, ConditionUI):
method left_label (line 1440) | def left_label(cls, component):
class HostUI (line 1444) | class HostUI(ConditionUI):
method create_widgets (line 1447) | def create_widgets(self):
method show (line 1457) | def show(self, component, editable):
method collect_value (line 1462) | def collect_value(self):
method left_label (line 1466) | def left_label(cls, component):
method right_label (line 1470) | def right_label(cls, component):
class _SettingWithValueUI (line 1474) | class _SettingWithValueUI:
method create_widgets (line 1480) | def create_widgets(self):
method _all_choices (line 1544) | def _all_choices(cls, setting): # choice and map-choice
method _setting_attributes (line 1577) | def _setting_attributes(cls, setting_name, device=None):
method _changed_device (line 1597) | def _changed_device(self, *args):
method _changed_setting (line 1610) | def _changed_setting(self, *args):
method _changed_key (line 1618) | def _changed_key(self, *args):
method update_devices (line 1625) | def update_devices(self):
method _update_device_list (line 1628) | def _update_device_list(self):
method _update_setting_list (line 1632) | def _update_setting_list(self, device=None):
method _update_key_list (line 1637) | def _update_key_list(self, setting_name, device=None):
method _update_value_list (line 1671) | def _update_value_list(self, setting_name, device=None, key=None):
method _on_update (line 1700) | def _on_update(self, *_args):
method _update_validation (line 1704) | def _update_validation(self):
method show (line 1728) | def show(self, component, editable):
method collect_value (line 1746) | def collect_value(self):
method right_label (line 1762) | def right_label(cls, component):
class SetUI (line 1804) | class SetUI(_SettingWithValueUI, ActionUI):
method show (line 1810) | def show(self, component, editable):
method _on_update (line 1814) | def _on_update(self, *_args):
class SettingUI (line 1820) | class SettingUI(_SettingWithValueUI, ConditionUI):
method show (line 1826) | def show(self, component, editable):
method _on_update (line 1830) | def _on_update(self, *_args):
function update_devices (line 1868) | def update_devices():
function show_window (line 1876) | def show_window(model: Gtk.TreeStore):
FILE: lib/solaar/ui/icons.py
function _init_icon_paths (line 34) | def _init_icon_paths():
function battery (line 54) | def battery(level=None, charging=False):
function _first_res (line 65) | def _first_res(val, pairs):
function _battery_icon_name (line 69) | def _battery_icon_name(level, charging):
function lux (line 83) | def lux(level=None):
function device_icon_set (line 92) | def device_icon_set(name="_", kind=None):
function device_icon_file (line 112) | def device_icon_file(name, kind=None, size=LARGE_SIZE):
function device_icon_name (line 117) | def device_icon_name(name, kind=None):
function icon_file (line 126) | def icon_file(name, size=LARGE_SIZE):
FILE: lib/solaar/ui/pair_window.py
class GtkSignal (line 37) | class GtkSignal(Enum):
function create (line 42) | def create(receiver):
function prepare (line 86) | def prepare(receiver):
function check_lock_state (line 100) | def check_lock_state(assistant, receiver, count=2):
function _check_lock_state (line 107) | def _check_lock_state(assistant, receiver, count):
function _pairing_failed (line 136) | def _pairing_failed(assistant, receiver, error):
function _pairing_succeeded (line 142) | def _pairing_succeeded(assistant, receiver, device):
function _finish (line 148) | def _finish(assistant, receiver):
function _show_passcode (line 163) | def _show_passcode(assistant, receiver, passkey):
function _create_assistant (line 190) | def _create_assistant(receiver, ok, finish, title, text):
function _create_success_page (line 217) | def _create_success_page(assistant, device):
function _create_failure_page (line 246) | def _create_failure_page(assistant, error) -> None:
function _create_page (line 261) | def _create_page(assistant, kind, header=None, icon_name=None, text=None...
FILE: lib/solaar/ui/rule_actions.py
class GtkSignal (line 32) | class GtkSignal(Enum):
class ActionUI (line 38) | class ActionUI(RuleComponentUI):
method icon_name (line 42) | def icon_name(cls):
class KeyPressUI (line 46) | class KeyPressUI(ActionUI):
method create_widgets (line 50) | def create_widgets(self):
method _create_field (line 73) | def _create_field(self):
method _create_del_btn (line 81) | def _create_del_btn(self):
method _clicked_add (line 88) | def _clicked_add(self, _btn):
method _clicked_del (line 94) | def _clicked_del(self, _btn, pos):
method _on_update (line 101) | def _on_update(self, *args):
method show (line 112) | def show(self, component, editable=True):
method collect_value (line 130) | def collect_value(self):
method left_label (line 137) | def left_label(cls, component):
method right_label (line 141) | def right_label(cls, component):
class MouseScrollUI (line 145) | class MouseScrollUI(ActionUI):
method create_widgets (line 150) | def create_widgets(self):
method __parse (line 173) | def __parse(cls, v):
method show (line 180) | def show(self, component, editable=True):
method collect_value (line 186) | def collect_value(self):
method left_label (line 190) | def left_label(cls, component):
method right_label (line 194) | def right_label(cls, component):
class MouseClickUI (line 201) | class MouseClickUI(ActionUI):
method create_widgets (line 208) | def create_widgets(self):
method show (line 235) | def show(self, component, editable=True):
method collect_value (line 246) | def collect_value(self):
method left_label (line 255) | def left_label(cls, component):
method right_label (line 259) | def right_label(cls, component):
class ExecuteUI (line 263) | class ExecuteUI(ActionUI):
method create_widgets (line 266) | def create_widgets(self):
method _create_field (line 278) | def _create_field(self):
method _create_del_btn (line 286) | def _create_del_btn(self):
method _clicked_add (line 294) | def _clicked_add(self, *_args):
method _clicked_del (line 299) | def _clicked_del(self, _btn, pos):
method show (line 306) | def show(self, component, editable=True):
method collect_value (line 323) | def collect_value(self):
method left_label (line 327) | def left_label(cls, component):
method right_label (line 331) | def right_label(cls, component):
FILE: lib/solaar/ui/rule_base.py
function norm (line 26) | def norm(s):
class CompletionEntry (line 30) | class CompletionEntry(Gtk.Entry):
method __init__ (line 31) | def __init__(self, values, *args, **kwargs):
method add_completion_to_entry (line 36) | def add_completion_to_entry(cls, entry, values):
class RuleComponentUI (line 52) | class RuleComponentUI(abc.ABC):
method __init__ (line 55) | def __init__(self, panel, on_update: Callable = None):
method create_widgets (line 64) | def create_widgets(self) -> dict:
method show (line 67) | def show(self, component, editable=True):
method collect_value (line 72) | def collect_value(self) -> Any:
method ignore_changes (line 76) | def ignore_changes(self):
method _on_update (line 81) | def _on_update(self, *_args):
method _show_widgets (line 89) | def _show_widgets(self, editable):
method left_label (line 97) | def left_label(cls, component) -> str:
method right_label (line 101) | def right_label(cls, _component) -> str:
method icon_name (line 105) | def icon_name(cls) -> str:
method _remove_panel_items (line 108) | def _remove_panel_items(self):
method update_devices (line 112) | def update_devices(self): # noqa: B027
FILE: lib/solaar/ui/rule_conditions.py
class GtkSignal (line 30) | class GtkSignal(Enum):
class ConditionUI (line 38) | class ConditionUI(RuleComponentUI):
method icon_name (line 42) | def icon_name(cls):
class ProcessUI (line 46) | class ProcessUI(ConditionUI):
method create_widgets (line 49) | def create_widgets(self):
method show (line 59) | def show(self, component, editable=True):
method collect_value (line 64) | def collect_value(self):
method left_label (line 68) | def left_label(cls, component):
method right_label (line 72) | def right_label(cls, component):
class MouseProcessUI (line 76) | class MouseProcessUI(ConditionUI):
method create_widgets (line 79) | def create_widgets(self):
method show (line 89) | def show(self, component, editable=True):
method collect_value (line 94) | def collect_value(self):
method left_label (line 98) | def left_label(cls, component):
method right_label (line 102) | def right_label(cls, component):
class FeatureUI (line 106) | class FeatureUI(ConditionUI):
method create_widgets (line 120) | def create_widgets(self):
method show (line 136) | def show(self, component, editable=True):
method collect_value (line 144) | def collect_value(self):
method _on_update (line 147) | def _on_update(self, *args):
method left_label (line 153) | def left_label(cls, component):
method right_label (line 157) | def right_label(cls, component):
class ReportUI (line 161) | class ReportUI(ConditionUI):
method create_widgets (line 166) | def create_widgets(self):
method show (line 178) | def show(self, component, editable=True):
method collect_value (line 183) | def collect_value(self):
method left_label (line 187) | def left_label(cls, component):
method right_label (line 191) | def right_label(cls, component):
class ModifiersUI (line 195) | class ModifiersUI(ConditionUI):
method create_widgets (line 198) | def create_widgets(self):
method show (line 214) | def show(self, component, editable=True):
method collect_value (line 220) | def collect_value(self):
method left_label (line 224) | def left_label(cls, component):
method right_label (line 228) | def right_label(cls, component):
class KeyUI (line 232) | class KeyUI(ConditionUI):
method create_widgets (line 236) | def create_widgets(self):
method show (line 257) | def show(self, component, editable=True):
method collect_value (line 266) | def collect_value(self):
method _on_update (line 270) | def _on_update(self, *args):
method left_label (line 276) | def left_label(cls, component):
method right_label (line 280) | def right_label(cls, component):
class KeyIsDownUI (line 284) | class KeyIsDownUI(ConditionUI):
method create_widgets (line 288) | def create_widgets(self):
method show (line 303) | def show(self, component, editable=True):
method collect_value (line 308) | def collect_value(self):
method _on_update (line 311) | def _on_update(self, *args):
method left_label (line 317) | def left_label(cls, component):
method right_label (line 321) | def right_label(cls, component):
class TestUI (line 325) | class TestUI(ConditionUI):
method create_widgets (line 328) | def create_widgets(self):
method show (line 355) | def show(self, component, editable=True):
method collect_value (line 364) | def collect_value(self):
method _on_update (line 372) | def _on_update(self, *args):
method _change_status_icon (line 376) | def _change_status_icon(self):
method left_label (line 381) | def left_label(cls, component):
method right_label (line 385) | def right_label(cls, component):
class TestBytesElement (line 390) | class TestBytesElement:
class TestBytesMode (line 398) | class TestBytesMode:
class TestBytesUI (line 404) | class TestBytesUI(ConditionUI):
method create_widgets (line 432) | def create_widgets(self):
method show (line 466) | def show(self, component, editable=True):
method collect_value (line 480) | def collect_value(self):
method _only_mode (line 484) | def _only_mode(self, mode_id):
method _on_update (line 493) | def _on_update(self, *args):
method left_label (line 506) | def left_label(cls, component):
method right_label (line 510) | def right_label(cls, component):
class MouseGestureUI (line 517) | class MouseGestureUI(ConditionUI):
method create_widgets (line 531) | def create_widgets(self):
method _create_field (line 545) | def _create_field(self):
method _create_del_btn (line 555) | def _create_del_btn(self):
method _clicked_add (line 562) | def _clicked_add(self, _btn):
method _clicked_del (line 567) | def _clicked_del(self, _btn, pos):
method _on_update (line 574) | def _on_update(self, *args):
method show (line 585) | def show(self, component, editable=True):
method collect_value (line 603) | def collect_value(self):
method left_label (line 607) | def left_label(cls, component):
method right_label (line 611) | def right_label(cls, component):
FILE: lib/solaar/ui/tray.py
class GtkSignal (line 46) | class GtkSignal(Enum):
function _create_menu (line 51) | def _create_menu(quit_handler):
function _scroll (line 70) | def _scroll(tray_icon, event, direction=None):
function _icon_file (line 160) | def _icon_file(icon_name):
function _create (line 168) | def _create(menu):
function _hide (line 183) | def _hide(indicator):
function _show (line 186) | def _show(indicator):
function _update_tray_icon (line 189) | def _update_tray_icon():
function attention (line 206) | def attention(reason=None):
function _create (line 215) | def _create(menu):
function _hide (line 229) | def _hide(icon):
function _show (line 232) | def _show(icon):
function _update_tray_icon (line 235) | def _update_tray_icon():
function _blink (line 252) | def _blink(count):
function attention (line 264) | def attention(reason=None):
function _generate_tooltip_lines (line 271) | def _generate_tooltip_lines():
function _generate_description_lines (line 279) | def _generate_description_lines():
function _pick_device_with_lowest_battery (line 302) | def _pick_device_with_lowest_battery():
function _add_device (line 322) | def _add_device(device):
function _remove_device (line 351) | def _remove_device(index):
function _add_receiver (line 364) | def _add_receiver(receiver):
function _remove_receiver (line 374) | def _remove_receiver(receiver):
function _update_menu_item (line 385) | def _update_menu_item(index, device):
function init (line 412) | def init(_quit_handler):
function destroy (line 421) | def destroy():
function update (line 433) | def update(device=None):
FILE: lib/solaar/ui/window.py
class Column (line 60) | class Column(IntEnum):
class GtkSignal (line 79) | class GtkSignal(Enum):
function _new_button (line 85) | def _new_button(label, icon_name=None, icon_size=_NORMAL_BUTTON_ICON_SIZ...
function _create_receiver_panel (line 103) | def _create_receiver_panel():
function _create_device_panel (line 122) | def _create_device_panel():
function _create_details_panel (line 159) | def _create_details_panel():
function _create_buttons_box (line 174) | def _create_buttons_box():
function _create_empty_panel (line 214) | def _create_empty_panel():
function _create_info_panel (line 222) | def _create_info_panel():
function _create_tree (line 249) | def _create_tree(model):
function _create_window_layout (line 299) | def _create_window_layout():
function _create (line 347) | def _create(delete_action):
function _find_selected_device (line 368) | def _find_selected_device():
function _find_selected_device_id (line 374) | def _find_selected_device_id():
function _device_selected (line 382) | def _device_selected(selection):
function _receiver_row (line 395) | def _receiver_row(receiver_path, receiver=None):
function _device_row (line 422) | def _device_row(receiver_path, device_number, device=None):
function select (line 473) | def select(receiver_path, device_number=None):
function _hide (line 487) | def _hide(w, _ignore=None):
function popup (line 497) | def popup(trigger=None, receiver_path=None, device_id=None):
function toggle (line 504) | def toggle(trigger=None):
function _update_details (line 511) | def _update_details(button):
function _update_receiver_panel (line 598) | def _update_receiver_panel(receiver, panel, buttons, full=False):
function _update_device_panel (line 659) | def _update_device_panel(device, panel, buttons, full=False):
function _update_info_panel (line 752) | def _update_info_panel(device, full=False):
function init (line 807) | def init(show_window, hide_on_close):
function destroy (line 821) | def destroy(_ignore1=None, _ignore2=None):
function update (line 835) | def update(device, need_popup=False, refresh=False):
function update_device (line 882) | def update_device(device, item, selected_device_id, need_popup, full=Fal...
function find_device (line 914) | def find_device(serial):
FILE: setup.py
function _data_files (line 30) | def _data_files():
FILE: tests/hid_parser/test_data.py
function test_consumer (line 5) | def test_consumer():
function test_button (line 11) | def test_button():
FILE: tests/hidapi/test_hidapi.py
function test_find_paired_node (line 11) | def test_find_paired_node():
FILE: tests/logitech_receiver/fake_hidpp.py
function open_path (line 35) | def open_path(path: Optional[str]) -> int:
function ping (line 41) | def ping(responses, handle, devnumber, long_message=False):
function request (line 47) | def request(
class Response (line 67) | class Response:
function replace_number (line 76) | def replace_number(responses, number): # change the devnumber for a lis...
function adjust_responses_index (line 80) | def adjust_responses_index(index, responses): # change index-4 response...
class Device (line 378) | class Device:
method __post_init__ (line 404) | def __post_init__(self):
method request (line 428) | def request(self, id, *params, no_reply=False, long_message=False, pro...
method ping (line 437) | def ping(self, handle=None, devnumber=None, long_message=False):
method handle_notification (line 441) | def handle_notification(self, handle):
method changed (line 444) | def changed(self, *args, **kwargs):
method set_battery_info (line 447) | def set_battery_info(self, *args, **kwargs):
method status_string (line 450) | def status_string(self):
function match_requests (line 454) | def match_requests(number, responses, call_args_list):
FILE: tests/logitech_receiver/test_base.py
function test_product_information (line 28) | def test_product_information(usb_id, expected_name, expected_receiver_ki...
function test_filter_receivers_known (line 39) | def test_filter_receivers_known():
function test_filter_receivers_unknown (line 49) | def test_filter_receivers_unknown():
function test_filter_products_of_interest (line 73) | def test_filter_products_of_interest(product_id, bus, hidpp_short, hidpp...
function test_match (line 90) | def test_match():
function test_make_notification (line 110) | def test_make_notification(report_id, sub_id, address, valid_notification):
function test_get_next_sw_id (line 127) | def test_get_next_sw_id():
function test_request_errors (line 143) | def test_request_errors(
function test_ping_errors (line 181) | def test_ping_errors(simulated_error: Hidpp10Error, expected_result):
FILE: tests/logitech_receiver/test_base_usb.py
function test_ensure_known_receivers_mappings_are_valid (line 7) | def test_ensure_known_receivers_mappings_are_valid():
function test_get_receiver_info (line 12) | def test_get_receiver_info():
function test_get_receiver_info_unknown_device_fails (line 28) | def test_get_receiver_info_unknown_device_fails():
FILE: tests/logitech_receiver/test_common.py
function test_crc16 (line 9) | def test_crc16():
function test_named_int (line 18) | def test_named_int():
function test_named_int_comparison (line 26) | def test_named_int_comparison():
function test_named_int_comparison_exception (line 42) | def test_named_int_comparison_exception():
function test_named_int_conversions (line 49) | def test_named_int_conversions():
function test_named_int_yaml (line 56) | def test_named_int_yaml():
function test_named_ints (line 68) | def test_named_ints():
function test_named_ints_fallback (line 101) | def test_named_ints_fallback():
function test_named_ints_list (line 110) | def test_named_ints_list():
function test_named_ints_range (line 118) | def test_named_ints_range():
function test_named_ints_flag_names (line 135) | def test_named_ints_flag_names(code, expected_flags):
function test_flag_names (line 152) | def test_flag_names(code, expected_flags):
function test_named_ints_setitem (line 163) | def test_named_ints_setitem():
function test_named_ints_other (line 179) | def test_named_ints_other():
function test_unsorted_named_ints (line 192) | def test_unsorted_named_ints():
function test_strhex (line 212) | def test_strhex(bytes_input, expected_output):
function test_bytest2int (line 218) | def test_bytest2int():
function test_int2bytes (line 227) | def test_int2bytes():
function test_kw_exception (line 236) | def test_kw_exception():
function test_battery (line 259) | def test_battery(status, expected_level, expected_ok, expected_charging,...
function test_battery_2 (line 269) | def test_battery_2():
FILE: tests/logitech_receiver/test_desktop_notifications.py
function test_init (line 8) | def test_init():
function test_uninit (line 14) | def test_uninit():
class MockDevice (line 18) | class MockDevice(mock.Mock):
method close (line 21) | def close():
function test_show (line 25) | def test_show():
FILE: tests/logitech_receiver/test_device.py
class LowLevelInterfaceFake (line 32) | class LowLevelInterfaceFake:
method __init__ (line 33) | def __init__(self, responses=None):
method open_path (line 36) | def open_path(self, path) -> int:
method find_paired_node (line 39) | def find_paired_node(self, receiver_path: str, index: int, timeout: int):
method request (line 42) | def request(self, response, *args, **kwargs):
method ping (line 46) | def ping(self, response, *args, **kwargs):
method close (line 50) | def close(self, *args, **kwargs):
class DeviceInfoStub (line 55) | class DeviceInfoStub:
function test_create_device (line 83) | def test_create_device(device_info, responses, expected_success):
function test_device_name (line 100) | def test_device_name(device_info, responses, expected_codename, expected...
function test_device_info (line 130) | def test_device_info(device_info, responses, handle, _name, _codename, n...
class FakeReceiver (line 147) | class FakeReceiver:
method device_codename (line 152) | def device_codename(self, number):
method __contains__ (line 155) | def __contains__(self, dev):
function test_device_receiver (line 195) | def test_device_receiver(number, pairing_info, responses, handle, _name,...
function test_device_ids (line 244) | def test_device_ids(number, info, responses, handle, unitId, modelId, ta...
class FakeDevice (line 261) | class FakeDevice(device.Device): # a fully functional Device but its HI...
method __init__ (line 262) | def __init__(self, responses, *args, **kwargs):
function test_device_complex (line 281) | def test_device_complex(device_info, responses, protocol, led, keys, rem...
function test_device_settings (line 319) | def test_device_settings(device_info, responses, protocol, p, persister,...
function test_device_battery (line 349) | def test_device_battery(device_info, responses, protocol, expected_batte...
FILE: tests/logitech_receiver/test_diversion.py
function rule_config (line 14) | def rule_config():
function test_load_rule_config (line 40) | def test_load_rule_config(rule_config):
function test_diversion_rule (line 62) | def test_diversion_rule():
function test_key_is_down (line 89) | def test_key_is_down():
function test_feature (line 95) | def test_feature():
function test_process_notification (line 117) | def test_process_notification(feature, data):
FILE: tests/logitech_receiver/test_hidpp10.py
class Response (line 19) | class Response:
class Device (line 26) | class Device:
method request (line 35) | def request(self, id, params=None, no_reply=False):
function test_read_register (line 78) | def test_read_register(device, register, param, expected_result, mocker):
function test_write_register (line 96) | def test_write_register(device, register, param, expected_result, mocker):
function device_charge (line 105) | def device_charge(name, response):
function device_status (line 116) | def device_status(name, response):
function test_hidpp10_get_battery (line 184) | def test_hidpp10_get_battery(device, expected_result, expected_register):
function test_hidpp10_get_firmware (line 206) | def test_hidpp10_get_firmware(device, expected_firmwares):
function test_set_3leds (line 230) | def test_set_3leds(device, level, charging, warning, p1, p2, mocker):
function test_set_3leds_missing (line 239) | def test_set_3leds_missing(device, mocker):
function test_get_notification_flags (line 248) | def test_get_notification_flags(device):
function test_set_notification_flags (line 254) | def test_set_notification_flags(mocker):
function test_set_notification_flags_bad (line 266) | def test_set_notification_flags_bad(mocker):
function test_notification_flag_str (line 291) | def test_notification_flag_str(flag_bits, expected_names):
function test_get_device_features (line 299) | def test_get_device_features():
function test_get_register (line 314) | def test_get_register(device, register, expected_result):
function test_get_configuration_pending_flags (line 327) | def test_get_configuration_pending_flags(device, expected_result):
function test_set_configuration_pending_flags (line 340) | def test_set_configuration_pending_flags(device, expected_result):
function test_pairing_error (line 346) | def test_pairing_error():
FILE: tests/logitech_receiver/test_hidpp20_complex.py
function test_FeaturesArray_check (line 54) | def test_FeaturesArray_check(device, expected_result, expected_count):
function test_FeaturesArray_get_feature (line 74) | def test_FeaturesArray_get_feature(device, expected0, expected1, expecte...
function test_FeaturesArray_enumerate (line 113) | def test_FeaturesArray_enumerate(device, expected_result):
function test_FeaturesArray_setitem (line 121) | def test_FeaturesArray_setitem():
function test_FeaturesArray_delitem (line 132) | def test_FeaturesArray_delitem():
function test_FeaturesArray_getitem (line 143) | def test_FeaturesArray_getitem(device, expected0, expected1, expected2, ...
function test_reprogrammable_key_key (line 165) | def test_reprogrammable_key_key(device, index, cid, task_id, flags, defa...
function test_reprogrammable_key_v4_key (line 222) | def test_reprogrammable_key_v4_key(
function test_reprogrammable_key_v4_query (line 251) | def test_reprogrammable_key_v4_query(responses, index, mapped_to, remapp...
function test_reprogrammable_key_v4_set (line 273) | def test_reprogrammable_key_v4_set(responses, index, diverted, persisten...
function test_remappable_action (line 326) | def test_remappable_action(r, index, cid, actionId, remapped, mask, stat...
function test_KeysArrayV4_index_error (line 371) | def test_KeysArrayV4_index_error(device, index):
function test_KeysArrayV4_query_key (line 382) | def test_KeysArrayV4_query_key(device, index, top, cid):
function test_KeysArrayV4__getitem (line 400) | def test_KeysArrayV4__getitem(device, count, index, cid, task_id, flags,...
function test_KeysArrayV4_index (line 418) | def test_KeysArrayV4_index(key, index):
function test_keys_array_v4_key (line 454) | def test_keys_array_v4_key(key, expected_index, expected_mapped_to, expe...
function test_KeysArrayPersistent_index_error (line 471) | def test_KeysArrayPersistent_index_error(device, index):
function test_KeysArrayPersistent_key (line 489) | def test_KeysArrayPersistent_key(responses, key, index, mapped_to, capab...
function test_SubParam (line 508) | def test_SubParam(id, length, minimum, maximum, widget, min, max, wid, s...
function test_gesture (line 527) | def test_gesture(device, low, high, next_index, next_diversion_index, na...
function test_Gesture_set (line 551) | def test_Gesture_set(responses, gest, enabled, diverted, set_result, uns...
function test_param (line 571) | def test_param(responses, prm, id, index, size, value, default_value, wr...
function test_spec (line 596) | def test_spec(responses, id, s, byte_count, expected_value, expected_str...
function test_Gestures (line 609) | def test_Gestures():
function test_Backlight (line 647) | def test_Backlight():
function test_LEDEffectSetting (line 675) | def test_LEDEffectSetting(hex, ID, color, speed, period, intensity, ramp...
function test_LEDEffectInfo (line 716) | def test_LEDEffectInfo(feature, function, response, ID, capabilities, pe...
function test_LEDZoneInfo (line 735) | def test_LEDZoneInfo(feature, function, offset, effect_function, respons...
function test_LEDZoneInfo_to_command (line 759) | def test_LEDZoneInfo_to_command(responses, setting, expected_command):
function test_LED_RGB_EffectsInfo (line 782) | def test_LED_RGB_EffectsInfo(feature, cls, responses, readable, count, c...
function test_button_bytes (line 805) | def test_button_bytes(hex, expected_behavior, sector, address, typ, val,...
function test_onboard_profile_bytes (line 885) | def test_onboard_profile_bytes(hex, name, sector, enabled, buttons, gbut...
function test_onboard_profiles_device (line 906) | def test_onboard_profiles_device(responses, name, count, buttons, gbutto...
FILE: tests/logitech_receiver/test_hidpp20_simple.py
function test_get_firmware (line 29) | def test_get_firmware():
function test_get_ids (line 44) | def test_get_ids():
function test_get_kind (line 55) | def test_get_kind():
function test_get_name (line 65) | def test_get_name():
function test_get_friendly_name (line 78) | def test_get_friendly_name():
function test_get_battery_status (line 91) | def test_get_battery_status():
function test_get_battery_voltage (line 103) | def test_get_battery_voltage():
function test_get_battery_unified (line 115) | def test_get_battery_unified():
function test_get_adc_measurement (line 126) | def test_get_adc_measurement():
function test_get_battery (line 138) | def test_get_battery():
function test_get_battery_none (line 150) | def test_get_battery_none():
function test_get_mouse_pointer_info (line 172) | def test_get_mouse_pointer_info():
function test_get_vertical_scrolling_info (line 186) | def test_get_vertical_scrolling_info():
function test_get_hi_res_scrolling_info (line 195) | def test_get_hi_res_scrolling_info():
function test_get_pointer_speed_info (line 205) | def test_get_pointer_speed_info():
function test_get_lowres_wheel_status (line 214) | def test_get_lowres_wheel_status():
function test_get_hires_wheel (line 223) | def test_get_hires_wheel():
function test_get_new_fn_inversion (line 242) | def test_get_new_fn_inversion():
function mock_gethostname (line 252) | def mock_gethostname(mocker):
function test_get_host_names (line 276) | def test_get_host_names(responses, expected_result, mock_gethostname):
function test_set_host_name (line 307) | def test_set_host_name(responses, expected_result):
function test_get_onboard_mode (line 315) | def test_get_onboard_mode():
function test_set_onboard_mode (line 324) | def test_set_onboard_mode():
function test_get_polling_rate (line 346) | def test_get_polling_rate(
function test_get_remaining_pairing (line 357) | def test_get_remaining_pairing():
function test_config_change (line 366) | def test_config_change():
function test_decipher_battery_status (line 375) | def test_decipher_battery_status():
function test_decipher_battery_voltage (line 386) | def test_decipher_battery_voltage():
function test_decipher_battery_unified (line 397) | def test_decipher_battery_unified():
function test_decipher_adc_measurement (line 407) | def test_decipher_adc_measurement():
function test_feature_flag_names (line 437) | def test_feature_flag_names(code, expected_flags):
function test_led_zone_locations (line 450) | def test_led_zone_locations(code, expected_name):
function test_estimate_battery_level_percentage (line 481) | def test_estimate_battery_level_percentage(millivolt, expected_percentage):
FILE: tests/logitech_receiver/test_notifications.py
class MockLowLevelInterface (line 15) | class MockLowLevelInterface:
method open_path (line 16) | def open_path(self, path):
method find_paired_node_wpid (line 19) | def find_paired_node_wpid(self, receiver_path: str, index: int):
method ping (line 22) | def ping(self, handle, number, long_message=False):
method request (line 25) | def request(self, handle, devnumber, request_id, *params, **kwargs):
method find_paired_node (line 28) | def find_paired_node(self, receiver_path: str, index: int, timeout: int):
method close (line 31) | def close(self, device_handle) -> None:
function test_process_receiver_notification (line 54) | def test_process_receiver_notification(sub_id, notification_data, expect...
function test_process_device_notification (line 73) | def test_process_device_notification(hidpp_notification, expected):
function test_process_dj_notification (line 90) | def test_process_dj_notification(hidpp_notification, expected):
function test_process_hidpp10_custom_notification (line 106) | def test_process_hidpp10_custom_notification(hidpp_notification, expected):
function test_process_hidpp10_notification (line 129) | def test_process_hidpp10_notification(hidpp_notification, expected):
function test_process_feature_notification (line 273) | def test_process_feature_notification(mocker, hidpp_notification, feature):
function test_process_receiver_notification_invalid (line 282) | def test_process_receiver_notification_invalid(mocker):
function test_process_device_notification_extended (line 298) | def test_process_device_notification_extended(mocker, sub_id, notificati...
function test_handle_device_discovery (line 309) | def test_handle_device_discovery():
function test_handle_passkey_request (line 320) | def test_handle_passkey_request(mocker):
function test_handle_passkey_pressed (line 330) | def test_handle_passkey_pressed(mocker):
FILE: tests/logitech_receiver/test_receiver.py
function nano_recv (line 16) | def nano_recv():
class LowLevelInterfaceFake (line 22) | class LowLevelInterfaceFake:
method __init__ (line 23) | def __init__(self, responses=None):
method open_path (line 26) | def open_path(self, path):
method product_information (line 29) | def product_information(self, usb_id: int) -> dict:
method find_paired_node (line 32) | def find_paired_node(self, receiver_path: str, index: int, timeout: int):
method request (line 35) | def request(self, response, *args, **kwargs):
method ping (line 39) | def ping(self, response, *args, **kwargs):
method close (line 43) | def close(self, *args, **kwargs):
function test_get_kind_from_index (line 58) | def test_get_kind_from_index(index, expected_kind):
class DeviceInfo (line 69) | class DeviceInfo:
function test_receiver_factory_create_receiver (line 132) | def test_receiver_factory_create_receiver(device_info, responses, handle...
function test_receiver_factory_props (line 156) | def test_receiver_factory_props(device_info, responses, firmware, codena...
function test_receiver_factory_string (line 176) | def test_receiver_factory_string(device_info, responses, status_str, str...
function test_receiver_factory_no_device (line 192) | def test_receiver_factory_no_device(device_info, responses):
function test_notification_information_nano_receiver (line 208) | def test_notification_information_nano_receiver(nano_recv, address, data...
function test_extract_serial_number (line 225) | def test_extract_serial_number():
function test_extract_max_devices (line 233) | def test_extract_max_devices():
function test_extract_remaining_pairings (line 248) | def test_extract_remaining_pairings(response, expected_remaining_pairings):
function test_extract_codename (line 254) | def test_extract_codename():
function test_extract_power_switch_location (line 272) | def test_extract_power_switch_location(power_switch_byte, expected_locat...
function test_extract_connection_count (line 280) | def test_extract_connection_count():
function test_extract_wpid (line 288) | def test_extract_wpid():
function test_extract_polling_rate (line 296) | def test_extract_polling_rate():
function test_extract_device_kind (line 311) | def test_extract_device_kind(data, expected_device_kind):
FILE: tests/logitech_receiver/test_setting_templates.py
class Setup (line 37) | class Setup:
method __init__ (line 38) | def __init__(self, test, *params):
class RegisterTest (line 45) | class RegisterTest:
function test_register_template (line 89) | def test_register_template(test, mocker):
class FeatureTest (line 106) | class FeatureTest:
function mock_gethostname (line 495) | def mock_gethostname(mocker):
function test_simple_template (line 500) | def test_simple_template(test, mocker, mock_gethostname):
function test_key_template (line 770) | def test_key_template(test, mocker):
function test_SpeedChange_action (line 810) | def test_SpeedChange_action(responses, currentSpeed, newSpeed, mocker):
function test_check_feature_settings (line 828) | def test_check_feature_settings(test, mocker):
function test_check_feature_setting (line 849) | def test_check_feature_setting(test, mocker):
FILE: tests/logitech_receiver/test_settings_validator.py
function test_bool_or_toggle (line 22) | def test_bool_or_toggle(current, new, expected):
FILE: tests/solaar/test_gtk.py
function test_arg_parse (line 4) | def test_arg_parse():
function test_arg_parse_debug (line 16) | def test_arg_parse_debug():
function test_arg_parse_version (line 23) | def test_arg_parse_version():
FILE: tests/solaar/ui/test_about_dialog.py
function test_about_model (line 5) | def test_about_model():
function test_about_dialog (line 14) | def test_about_dialog(mocker):
FILE: tests/solaar/ui/test_common.py
function test_create_error_text (line 21) | def test_create_error_text(reason, expected_in_title, expected_in_text):
FILE: tests/solaar/ui/test_desktop_notifications.py
function test_init (line 8) | def test_init():
function test_uninit (line 14) | def test_uninit():
function test_alert (line 18) | def test_alert():
class MockDevice (line 23) | class MockDevice(mock.Mock):
method close (line 26) | def close():
function test_show (line 30) | def test_show():
FILE: tests/solaar/ui/test_i18n.py
function set_locale_de (line 11) | def set_locale_de():
function test_set_locale_to_system_default (line 21) | def test_set_locale_to_system_default(set_locale_de):
FILE: tests/solaar/ui/test_pair_window.py
class Device (line 20) | class Device:
class Receiver (line 26) | class Receiver:
method reset_pairing (line 34) | def reset_pairing(self):
method remaining_pairings (line 37) | def remaining_pairings(self, cache=True):
method set_lock (line 40) | def set_lock(self, value=False, timeout=0):
method discover (line 44) | def discover(self, cancel=False, timeout=30):
method pair_device (line 48) | def pair_device(self, pair=True, slot=0, address=b"\0\0\0\0\0\0", auth...
class Assistant (line 54) | class Assistant:
method is_drawable (line 58) | def is_drawable(self):
method next_page (line 61) | def next_page(self):
method set_page_complete (line 64) | def set_page_complete(self, page, b):
method commit (line 67) | def commit(self):
method append_page (line 70) | def append_page(self, page):
method remove_page (line 73) | def remove_page(self, page):
method set_page_type (line 76) | def set_page_type(self, page, type):
method destroy (line 79) | def destroy(self):
function test_create (line 95) | def test_create(receiver, lock_open, discovering, page_type):
function test_prepare (line 114) | def test_prepare(receiver, expected_result, expected_error):
function test_check_lock_state_drawable (line 122) | def test_check_lock_state_drawable(assistant, expected_result):
function test_check_lock_state (line 194) | def test_check_lock_state(receiver, count, expected_result):
function test_finish (line 224) | def test_finish(receiver, pair_device, set_lock, discover, error, mocker):
function test_create_failure_page (line 240) | def test_create_failure_page(error, mocker):
FILE: tests/solaar/ui/test_probe.py
class MockReceiver (line 9) | class MockReceiver:
method read_register (line 13) | def read_register(self, register, *args):
function test_run_register_errors (line 17) | def test_run_register_errors():
FILE: tests/test_keysyms/test_keysymdef.py
function test_keysymdef (line 4) | def test_keysymdef():
Condensed preview — 309 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,949K chars).
[
{
"path": ".coveragerc",
"chars": 279,
"preview": "[run]\nbranch = True\n\nsource =\n hid_parser\n hidapi\n keysyms\n logitech_receiver\n solaar\n\nomit =\n */tests"
},
{
"path": ".git-blame-ignore-revs",
"chars": 310,
"preview": "# yapf bulk change\n72a8d311bce64b1536c08e754d22bb91efb66460\n# isort bulk change\ne6369e0c3c240715a0a2daede6c3b225ed63cf60"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 2081,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Information**"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 997,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**In"
},
{
"path": ".github/workflows/checks.yml",
"chars": 279,
"preview": "name: checks\n\non: [push, pull_request]\n\njobs:\n pre-commit:\n runs-on: ubuntu-latest\n steps:\n - name: Checkout\n "
},
{
"path": ".github/workflows/gh-pages.yml",
"chars": 1006,
"preview": "name: Deploy to GitHub Pages\non:\n push:\n branches:\n - master\n\npermissions:\n contents: read\n pages: write\n id"
},
{
"path": ".github/workflows/tests.yml",
"chars": 2301,
"preview": "name: tests\n\non: [push, pull_request]\n\njobs:\n ubuntu-tests:\n runs-on: ubuntu-latest\n\n strategy:\n matrix:\n "
},
{
"path": ".gitignore",
"chars": 277,
"preview": "*.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/dis"
},
{
"path": ".pre-commit-config.yaml",
"chars": 473,
"preview": "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-bui"
},
{
"path": ".python-version",
"chars": 5,
"preview": "3.11\n"
},
{
"path": "CHANGELOG.md",
"chars": 44116,
"preview": "# 1.1.19\n\n* New Georgian translation\n* Remove test that doesn't work in older Pythons\n* Update help messages for CLI com"
},
{
"path": "COPYRIGHT",
"chars": 648,
"preview": "Copyright 2012, 2013\nDaniel Pavel <daniel.pavel@gmail.com>\n\n This program is free software: you can redistribute it a"
},
{
"path": "LICENSE.txt",
"chars": 18092,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 2, June 1991\n\n Copyright (C) 1989, 1991 Fr"
},
{
"path": "MANIFEST.in",
"chars": 151,
"preview": "include COPYRIGHT LICENSE.txt README.md CHANGELOG.md lib/solaar/version lib/solaar/commit\nrecursive-include rules.d *\nre"
},
{
"path": "Makefile",
"chars": 2086,
"preview": "UDEV_RULE_FILE = 42-logitech-unify-permissions.rules\nUDEV_RULES_SOURCE := rules.d/$(UDEV_RULE_FILE)\nUDEV_RULES_SOURCE_UI"
},
{
"path": "README.md",
"chars": 3283,
"preview": "# <img src=\"https://pwr-solaar.github.io/Solaar/img/solaar.svg\" width=\"60px\"/> Solaar\n\nSolaar is a Linux manager for man"
},
{
"path": "RELEASE.md",
"chars": 652,
"preview": "# Solaar releases\n\n## Please read before making a release\n\nWe support two type of releases: normal releases (ex. `1.0.0`"
},
{
"path": "RHEL.md",
"chars": 2739,
"preview": "# Solaar installation guide for RHEL, Rocky, AlmaLinux, and CentOS Stream\n\nThis guide covers manual installation and an "
},
{
"path": "Release_Notes.md",
"chars": 11242,
"preview": "# 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#"
},
{
"path": "bin/solaar",
"chars": 1422,
"preview": "#!/usr/bin/env python3\n# -*- python-mode -*-\n# -*- coding: UTF-8 -*-\n\n## Copyright (C) 2012-2013 Daniel Pavel\n##\n## Thi"
},
{
"path": "docs/.gitignore",
"chars": 84,
"preview": "# ignore documentation-specific files\n\n.jekyll-metadata\nGemfile\nGemfile.lock\n_site/\n"
},
{
"path": "docs/LICENSE.txt",
"chars": 17523,
"preview": "GNU GENERAL PUBLIC LICENSE\n\nVersion 2, June 1991\n\nCopyright (C) 1989, 1991 Free Software Foundation, Inc.\n<https://fsf.o"
},
{
"path": "docs/README.text",
"chars": 309,
"preview": "# Documentation Readme\n\nThis project's documentation is hosted using GitHub pages, which serves static pages using Jekyl"
},
{
"path": "docs/capabilities.md",
"chars": 17321,
"preview": "---\ntitle: Solaar Capabilities\nlayout: page\n---\n\n# Solaar Capabilities\n\n[**Solaar**][solaar] reports on and controls [Lo"
},
{
"path": "docs/debian.md",
"chars": 251,
"preview": "---\ntitle: Debian Repository\nlayout: page\n---\n\n# Debian repository\n\nSolaar is now part of the [official Debian repositor"
},
{
"path": "docs/devices/00README.txt",
"chars": 2444,
"preview": "Files in this directory are edited output from `solaar show` providing\ninformation about devices and receivers that Sola"
},
{
"path": "docs/devices/Bluetooth Multi-Device Keyboard K380 B342.txt",
"chars": 6092,
"preview": "Solaar version 1.1.4\n\n 1: Bluetooth Multi-Device Keyboard K380\n Device path : /dev/hidraw5\n USB id : 046"
},
{
"path": "docs/devices/Bolt Receiver C548.txt",
"chars": 287,
"preview": "Solaar version 1.1.4\n\nBolt Receiver\n Device path : /dev/hidraw8\n USB id : 046d:C548\n Serial : 3842363831"
},
{
"path": "docs/devices/Candy companion chip 405F.txt",
"chars": 1247,
"preview": " 7: Candy companion chip\n Device path : /dev/hidraw11\n Codename : Candy\n Kind : touchpad\n P"
},
{
"path": "docs/devices/Couch Mouse M515 4007.txt",
"chars": 1510,
"preview": "1: Couch Mouse M515\n Codename : M515\n Kind : mouse\n Wireless PID : 4007\n Protocol : HID++ 2.0\n "
},
{
"path": "docs/devices/Craft Advanced Keyboard 4066.txt",
"chars": 12370,
"preview": "Solaar version 1.1.4\n\n 2: Craft Advanced Keyboard\n Device path : /dev/hidraw4\n WPID : 4066\n Codena"
},
{
"path": "docs/devices/Craft Advanced Keyboard B350.txt",
"chars": 11924,
"preview": "Solaar version 1.1.4\n\n 1: Craft Advanced Keyboard\n Device path : /dev/hidraw5\n USB id : 046d:B350\n C"
},
{
"path": "docs/devices/ERGO M575 Trackball 4096.txt",
"chars": 4515,
"preview": "Solaar version 1.1.4\n\n 1: ERGO M575 Trackball\n Device path : /dev/hidraw5\n WPID : 4096\n Codename "
},
{
"path": "docs/devices/EX100 Receiver 27 Mhz C517.text",
"chars": 7156,
"preview": "solaar version 1.1.11-80-gdea496f\n\nEX100 Receiver 27 Mhz\n Device path : /dev/hidraw2\n USB id : 046d:C517\n Seri"
},
{
"path": "docs/devices/G Pro Wireless Gaming Mouse 4079.txt",
"chars": 2685,
"preview": "Solaar version 1.1.4rc1\n\n 1: G Pro Wireless Gaming Mouse\n Device path : /dev/hidraw10\n WPID : 4079\n "
},
{
"path": "docs/devices/G213 Prodigy Gaming Keyboard C366.txt",
"chars": 1565,
"preview": "Solaar version 1.1.5rc1\n\nUSB and Bluetooth Devices\n\n 1: G213 Prodigy Gaming Keyboard\n Device path : /dev/hidraw2\n "
},
{
"path": "docs/devices/G304 Lightspeed Wireless Gaming Mouse 4074.txt",
"chars": 2686,
"preview": "solaar version 1.1.8\n\n\n 1: G304 Lightspeed Wireless Gaming Mouse\n Device path : /dev/hidraw6\n WPID : 4"
},
{
"path": "docs/devices/G305 Lightspeed Wireless Gaming Mouse 4074.text",
"chars": 2689,
"preview": "solaar version 1.1.10\n\n 1: G305 Lightspeed Wireless Gaming Mouse\n Device path : /dev/hidraw7\n WPID : 4"
},
{
"path": "docs/devices/G502 Gaming Mouse C07D.text",
"chars": 1924,
"preview": "Solaar version 1.1.5\n\n 1: G502 Gaming Mouse\n Device path : /dev/hidraw1\n USB id : 046d:C07D\n Codenam"
},
{
"path": "docs/devices/G502 Lightspeed Wireless Gaming Mouse 407F.txt",
"chars": 3698,
"preview": "solaar version 1.1.12rc1\n\n 1: G502 Gaming Mouse\n Device path : /dev/hidraw20\n WPID : 407F\n Codenam"
},
{
"path": "docs/devices/G502 Proteus Spectrum Optical Mouse C332.txt",
"chars": 1684,
"preview": "solaar version 1.1.9\n\n2: G502 Proteus Spectrum Optical Mouse\nDevice path : /dev/hidraw4\nUSB id : 046d:C332\nCodena"
},
{
"path": "docs/devices/G502 SE Hero Gaming Mouse C08B.txt",
"chars": 1868,
"preview": "1: G502 SE Hero Gaming Mouse\n Device path : /dev/hidraw7\n USB id : 046d:C08B\n Codename : G502 Her"
},
{
"path": "docs/devices/G502 X C099.txt",
"chars": 2832,
"preview": "Solaar version 1.1.7\n\n 1: G502 X\n Device path : /dev/hidraw2\n USB id : 046d:C099\n Codename : G50"
},
{
"path": "docs/devices/G502 X PLUS 4099.txt",
"chars": 4630,
"preview": "solaar version 1.1.19-25-g7520c9cc\n\n 1: G502 X PLUS\n Device path : /dev/hidraw8\n WPID : 4099\n Code"
},
{
"path": "docs/devices/G515 LS TKL 40B4.text",
"chars": 6344,
"preview": "solaar version 1.1.13+dfsg-1\n\n 1: G515 LS TKL\n Device path : None\n WPID : 40B4\n Codename : G51"
},
{
"path": "docs/devices/G535 Wireless Gaming Headset 0AC4.txt",
"chars": 1025,
"preview": "solaar version 1.1.8\n\nUSB and Bluetooth Devices\n\n 1: G535 Wireless Gaming Headset\n Device path : /dev/hidraw2\n "
},
{
"path": "docs/devices/G600 Gaming Mouse C24A.txt",
"chars": 6613,
"preview": "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, "
},
{
"path": "docs/devices/G604 Wireless Gaming Mouse 4085.txt",
"chars": 3742,
"preview": "solaar version 03cfa128\n\n 1: G604 Wireless Gaming Mouse\n Device path : /dev/hidraw6\n WPID : 4085\n "
},
{
"path": "docs/devices/G613 Wireless Mechanical Gaming Keyboard 4065.txt",
"chars": 3687,
"preview": "solaar version 1.1.19-25-g7520c9cc\n\n 1: G613 Wireless Mechanical Gaming Keyboard\n Device path : None\n WPID "
},
{
"path": "docs/devices/G703 Wired-Wireless Gaming Mouse 4070.txt",
"chars": 1916,
"preview": " 1: G703 Wired/Wireless Gaming Mouse\n Codename : G703\n Kind : mouse\n Wireless PID : 4070\n P"
},
{
"path": "docs/devices/G733 Gaming Headset 0AB5.text",
"chars": 1912,
"preview": "Solaar version 1.1.19\n\nG733 Gaming Headset\n Device path : /dev/hidraw0\n USB id : 046d:0AB5\n Codename "
},
{
"path": "docs/devices/G733 Gaming Headset 0AFE.text",
"chars": 1826,
"preview": "solaar version 1.1.11\n\nG733 Gaming Headset\n Device path : /dev/hidraw3\n USB id : 046d:0AFE\n Codename "
},
{
"path": "docs/devices/G815 Mechanical Keyboard C33F.txt",
"chars": 2033,
"preview": "solaar version 1.1.9\n\n1: G815 Mechanical Keyboard\nDevice path : /dev/hidraw2\nUSB id : 046d:C33F\nCodename : G8"
},
{
"path": "docs/devices/G903 LIGHTSPEED Wireless Gaming Mouse 4087.txt",
"chars": 4787,
"preview": "solaar version 1.1.8rc3+git1940-4e7b6b3\n\n 1: G903 LIGHTSPEED Wireless Gaming Mouse w/ HERO\n Device path : /dev/hid"
},
{
"path": "docs/devices/G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard 408E.txt",
"chars": 4215,
"preview": "Solaar version 1.1.4\n\n 1: G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard\n Device path : None\n WPI"
},
{
"path": "docs/devices/G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD 407C.text",
"chars": 8075,
"preview": "solaar version 1.1.12rc1\n\n 1: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD\n Device path : None\n WPID :"
},
{
"path": "docs/devices/G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD C33E.text",
"chars": 4359,
"preview": "solaar version 1.1.10\n\nUSB and Bluetooth Devices\n\n 1: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD\n Device path : "
},
{
"path": "docs/devices/G915 WIRELESS RGB Mechanical Gaming Keyboard 407E.txt",
"chars": 3930,
"preview": "Solaar version 1.1.1\n\n 1: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD\n Device path : None\n WPID : 407"
},
{
"path": "docs/devices/G935 Gaming Headset 0A87.txt",
"chars": 1195,
"preview": "Solaar version 1.1.7\n\n 1: G935 Gaming Headset\n Device path : /dev/hidraw2\n USB id : 046d:0A87\n Coden"
},
{
"path": "docs/devices/Illuminated Keyboard C318.txt",
"chars": 349,
"preview": "solaar version 1.1.8-29-g0ae14c7\n\n 1: Illuminated Keyboard\n Device path : /dev/hidraw1\n USB id : 046d:C3"
},
{
"path": "docs/devices/Illuminated Living-Room Keyboard K830 4032.txt",
"chars": 1774,
"preview": "# Provided by Mikkel Munch Mortensen\n\n(solaar)\n 3: Illuminated Living-Room Keyboard K830\n Codename : K830\n "
},
{
"path": "docs/devices/K850 Performance Wireless Keyboard 4062.txt",
"chars": 8405,
"preview": "Solaar version 1.1.1\n\n 2: K850 Performance Wireless Keyboard\n Device path : /dev/hidraw2\n WPID : 4062\n"
},
{
"path": "docs/devices/K850 Performance Wireless Keyboard B34D.txt",
"chars": 9674,
"preview": "Solaar version 1.1.4\n\n 2: K850 Performance Wireless Keyboard\n Device path : /dev/hidraw1\n USB id : 046d:"
},
{
"path": "docs/devices/Keyboard K600 TV 4078.txt",
"chars": 12906,
"preview": "Solaar version 1.1.7\n\n 1: Keyboard K600 TV\n Device path : /dev/hidraw3\n WPID : 4078\n Codename "
},
{
"path": "docs/devices/LIFT For Business B033.txt",
"chars": 5377,
"preview": "solaar version 1.1.8\n\n 2: LIFT For Business\n Device path : None\n WPID : B033\n Codename : LIFT "
},
{
"path": "docs/devices/LIFT VERTICAL ERGONOMIC MOUSE B031.txt",
"chars": 5378,
"preview": "Solaar version 1.1.4\n\n 2: LIFT VERTICAL ERGONOMIC MOUSE\n Device path : None\n WPID : B031\n Codename"
},
{
"path": "docs/devices/Lightspeed Receiver C539.txt",
"chars": 430,
"preview": "Solaar version 1.1.4\n\nLightspeed Receiver\n Device path : /dev/hidraw8\n USB id : 046d:C539\n Serial : C146"
},
{
"path": "docs/devices/Lightspeed Receiver C53A.txt",
"chars": 456,
"preview": "Lightspeed Receiver\n Device path : /dev/hidraw9\n USB id : 046d:C53A\n Serial : 5B2B9A98\n Firmware : "
},
{
"path": "docs/devices/Lightspeed Receiver C53D.txt",
"chars": 403,
"preview": "Solaar version 1.1.3\n\nLightspeed Receiver\n Device path : /dev/hidraw2\n USB id : 046d:C53D\n Serial : C271"
},
{
"path": "docs/devices/Lightspeed Receiver C53F.txt",
"chars": 308,
"preview": "Lightspeed Receiver\n Device path : /dev/hidraw3\n USB id : 046d:C53F\n Serial :\n Firmware : 44.01.B00"
},
{
"path": "docs/devices/Lightspeed Receiver C541.txt",
"chars": 407,
"preview": "Solaar version 1.1.1\n\nLightspeed Receiver\n Device path : /dev/hidraw4\n USB id : 046d:C541\n Serial : 18E8"
},
{
"path": "docs/devices/Lightspeed Receiver C545.txt",
"chars": 419,
"preview": "Solaar version 1.1.4\n\nLightspeed Receiver\n Device path : /dev/hidraw5\n USB id : 046d:C545\n Serial : AD15"
},
{
"path": "docs/devices/Lightspeed Receiver C547.txt",
"chars": 379,
"preview": "Solaar version 1.1.3\n\nLightspeed Receiver\n Device path : /dev/hidraw6\n USB id : 046d:C547\n Serial : 9B34"
},
{
"path": "docs/devices/Logi Pop Keys B365.txt",
"chars": 8933,
"preview": "solaar version 1.1.8\n\nBolt Receiver\n Device path : /dev/hidraw2\n USB id : 046d:C548\n Serial : 3145434346"
},
{
"path": "docs/devices/Logitech G933 Gaming Wireless Headset 0A5B.txt",
"chars": 1965,
"preview": "solaar version 1.1.19-25-g7520c9cc\n\nLogitech G933 Gaming Wireless Headset\n Device path : /dev/hidraw4\n USB id "
},
{
"path": "docs/devices/Logitech PRO X Wireless Gaming Headset 0ABA.txt",
"chars": 1837,
"preview": "\n 1: Logitech PRO X Wireless Gaming Headset\n Device path : /dev/hidraw2\n USB id : 046d:0ABA\n Codenam"
},
{
"path": "docs/devices/M720 Triathlon Multi-Device Mouse 405E.txt",
"chars": 6132,
"preview": "Solaar version 1.1.1\n\n 1: M720 Triathlon Multi-Device Mouse\n Device path : /dev/hidraw1\n WPID : 405E\n "
},
{
"path": "docs/devices/M720 Triathlon Multi-Device Mouse B015.txt",
"chars": 7000,
"preview": "Solaar version 1.1.4\n\n 1: M720 Triathlon Multi-Device Mouse\n Device path : /dev/hidraw0\n USB id : 046d:B"
},
{
"path": "docs/devices/MX Anywhere 3 4090.txt",
"chars": 5680,
"preview": "Solaar version 1.1.4\n\n\n 1: MX Anywhere 3\n Device path : /dev/hidraw3\n WPID : 4090\n Codename : "
},
{
"path": "docs/devices/MX Anywhere 3 B025.txt",
"chars": 5462,
"preview": "Solaar version 1.1.4\n\n 1: MX Anywhere 3\n Device path : /dev/hidraw1\n USB id : 046d:B025\n Codename "
},
{
"path": "docs/devices/MX Anywhere 3 for Business B02D.txt",
"chars": 5636,
"preview": "solaar version 1.1.14\n\n 1: MX Anywhere 3 for Business\n Device path : None\n WPID : B02D\n Codename "
},
{
"path": "docs/devices/MX Ergo Multi-Device Trackball 406F.txt",
"chars": 7236,
"preview": "Solaar version 1.1.4\n\n 1: MX Ergo Multi-Device Trackball\n Device path : /dev/hidraw4\n WPID : 406F\n "
},
{
"path": "docs/devices/MX Keys Keyboard 408A.txt",
"chars": 10727,
"preview": "Solaar version 1.1.4\n\n 1: MX Keys Keyboard\n Device path : /dev/hidraw1\n WPID : 408A\n Codename "
},
{
"path": "docs/devices/MX Keys Keyboard B35B.txt",
"chars": 10347,
"preview": "Solaar version 1.1.4rc1\n\n 1: MX Keys Keyboard\n Device path : /dev/hidraw8\n USB id : 046d:B35B\n Coden"
},
{
"path": "docs/devices/MX Keys Mini B369.txt",
"chars": 7344,
"preview": "Solaar version 1.1.4\n\n 255: MX Keys Mini\n Device path : /dev/hidraw6\n USB id : 046d:B369\n Codename "
},
{
"path": "docs/devices/MX Keys S B378.text",
"chars": 9255,
"preview": "solaar version 1.1.10\n\n 1: MX Keys S\n Device path : None\n WPID : B378\n Codename : MX KEYS S\n "
},
{
"path": "docs/devices/MX Keys for Business B363.text",
"chars": 10179,
"preview": "Solaar version 1.1.5\n\n 1: MX Keys for Business\n Device path : None\n WPID : B363\n Codename : MX"
},
{
"path": "docs/devices/MX Master 3 Wireless Mouse 4082.txt",
"chars": 6309,
"preview": "Solaar version 1.1.4\n\n 1: MX Master 3 Wireless Mouse\n Device path : /dev/hidraw2\n WPID : 4082\n Cod"
},
{
"path": "docs/devices/MX Master 3 Wireless Mouse B023.txt",
"chars": 5982,
"preview": "Solaar version 1.1.4\n\n 1: MX Master 3 Wireless Mouse\n Device path : /dev/hidraw5\n USB id : 046d:B023\n "
},
{
"path": "docs/devices/MX Master 3 for Business B028.text",
"chars": 6697,
"preview": "solaar version 1.1.8\n\n 1: MX Master 3 for Business\n Device path : None\n WPID : B028\n Codename "
},
{
"path": "docs/devices/MX Master 3S B034.txt",
"chars": 6907,
"preview": "Solaar version 1.1.7\n\n 2: MX Master 3S\n Device path : None\n WPID : B034\n Codename : MX Master "
},
{
"path": "docs/devices/MX Mechanical B366.txt",
"chars": 14352,
"preview": "Solaar version 1.1.7\n\n 1: MX Mechanical\n Device path : None\n WPID : B366\n Codename : MX MCHNCL"
},
{
"path": "docs/devices/MX Mechanical Mini B367.txt",
"chars": 11843,
"preview": "Solaar version 1.1.4\n\n 1: MX Mechanical Mini\n Device path : None\n WPID : B367\n Codename : MX M"
},
{
"path": "docs/devices/MX Vertical Wireless Mouse 407B.txt",
"chars": 6203,
"preview": "Solaar version 1.1.3\n\n 2: MX Vertical Wireless Mouse\n Device path : /dev/hidraw5\n WPID : 407B\n Cod"
},
{
"path": "docs/devices/MX Vertical Wireless Mouse B020.txt",
"chars": 4926,
"preview": "Solaar version 1.1.3\n\n 1: MX Vertical Wireless Mouse\n Device path : /dev/hidraw0\n USB id : 046d:B020\n "
},
{
"path": "docs/devices/Marathon Mouse M705 101B.txt",
"chars": 2225,
"preview": "Solaar version 1.1.5\n\n 1: Marathon Mouse M705 (M-R0009)\n Device path : /dev/hidraw1\n WPID : 101B\n "
},
{
"path": "docs/devices/Marathon Mouse M705 406D.txt",
"chars": 9376,
"preview": " 3: Marathon Mouse M705 (M-R0073)\n Device path : /dev/hidraw3\n WPID : 406D\n Codename : M705 (M"
},
{
"path": "docs/devices/Multi Device Silent Mouse M585-M590 406B.txt",
"chars": 6931,
"preview": "Solaar version 1.1.7\n\n\n 2: Multi Device Silent Mouse M585/M590\n Device path : /dev/hidraw2\n WPID : 406"
},
{
"path": "docs/devices/Nano Receiver C52F.txt",
"chars": 229,
"preview": "Nano Receiver\n Device path : /dev/hidraw3\n USB id : 046d:c52f\n Serial : 6D0342C5\n Firmware : 30.00."
},
{
"path": "docs/devices/Nano Receiver C534.txt",
"chars": 367,
"preview": "Solaar version 1.1.4rc2\n\nNano Receiver\n Device path : /dev/hidraw1\n USB id : 046d:C534\n Serial : None\n "
},
{
"path": "docs/devices/Nano Receiver C535.txt",
"chars": 293,
"preview": "Solaar version 1.1.5\n\nNano Receiver\n Device path : /dev/hidraw5\n USB id : 046d:C535\n Serial : 1F3F94FC\n "
},
{
"path": "docs/devices/Number Pad N545 2006.txt",
"chars": 477,
"preview": "solaar version 1.1.8\n\n 3: Number Pad N545\n Device path : /dev/hidraw3\n WPID : 2006\n Codename :"
},
{
"path": "docs/devices/PRO X 2 40A9.text",
"chars": 3172,
"preview": "solaar version 1.1.10\n\nReceiver\n Device path : /dev/hidraw3\n USB id : 046d:C54D\n Serial : 8FF3BF7B\n F"
},
{
"path": "docs/devices/PRO X Wireless 4093.txt",
"chars": 2812,
"preview": "Solaar version 1.1.14\n\n 2: PRO X Wireless\n Device path : None\n WPID : 4093\n Codename : PRO X\n "
},
{
"path": "docs/devices/Rechargeable Trackpad T651 B00C.txt",
"chars": 1146,
"preview": "Solaar version 1.1.7\n\n 1: Rechargeable Trackpad T651\n Device path : /dev/hidraw9\n USB id : 046d:B00C\n "
},
{
"path": "docs/devices/Signature M550.text",
"chars": 4088,
"preview": "solaar version 1.1.19\n\n 1: Signature M550\n Device path : None\n WPID : B02B\n Codename : Logi M5"
},
{
"path": "docs/devices/Signature M650 L Mouse B02A.txt",
"chars": 4826,
"preview": "Solaar version 1.1.3\n\n 2: Signature M650 L Mouse\n Device path : None\n WPID : B02A\n Codename : "
},
{
"path": "docs/devices/Unifying Receiver C52B.txt",
"chars": 342,
"preview": "Solaar version 1.1.4\n\nUnifying Receiver\n Device path : /dev/hidraw0\n USB id : 046d:C52B\n Serial : E06621"
},
{
"path": "docs/devices/Wireless All-in-One Keyboard TK820 4102.txt",
"chars": 3930,
"preview": "Solaar version 1.1.1\n\n 1: Wireless All-in-One Keyboard TK820\n Device path : /dev/hidraw5\n WPID : 4102\n"
},
{
"path": "docs/devices/Wireless Illuminated Keyboard K800 2010.txt",
"chars": 2969,
"preview": " 2: Wireless Illuminated Keyboard K800\n Codename : K800\n Kind : keyboard\n Wireless PID : 2010\n "
},
{
"path": "docs/devices/Wireless Illuminated Keyboard K800 new 406E.txt",
"chars": 4135,
"preview": " 2: Wireless Illuminated Keyboard K800 new\n Codename : new\n Kind : keyboard\n Wireless PID : 406"
},
{
"path": "docs/devices/Wireless Keyboard 4075.txt",
"chars": 3090,
"preview": "Solaar version 1.1.4rc2\n\n 1: Wireless Keyboard\n Device path : /dev/hidraw2\n WPID : 4075\n Codename "
},
{
"path": "docs/devices/Wireless Keyboard Dell KB714 4015.txt",
"chars": 1774,
"preview": "Solaar version 1.1.6rc4\n\n 4: Wireless Keyboard Dell KB714\n Device path : /dev/hidraw6\n WPID : 4015\n "
},
{
"path": "docs/devices/Wireless Keyboard K220 4005.txt",
"chars": 2032,
"preview": " 2: Wireless Keyboard K220\n Codename : K220\n Kind : keyboard\n Wireless PID : 4005\n Protocol"
},
{
"path": "docs/devices/Wireless Keyboard K230 400D.txt",
"chars": 2486,
"preview": " 1: Wireless Keyboard K230\n Device path : /dev/hidraw5\n WPID : 400D\n Codename : K230\n Kind"
},
{
"path": "docs/devices/Wireless Keyboard K270(unifying) 4003.txt",
"chars": 1673,
"preview": " 2: Wireless Keyboard K270(unifying)\n Codename : K270(unifying)\n Kind : keyboard\n Wireless PID "
},
{
"path": "docs/devices/Wireless Keyboard K360 4004.txt",
"chars": 1389,
"preview": "Solaar version 1.1.4\n\n 2: Wireless Keyboard K360\n Device path : /dev/hidraw2\n WPID : 4004\n Codenam"
},
{
"path": "docs/devices/Wireless Keyboard K470 4075.txt",
"chars": 3217,
"preview": "Solaar version 1.1.7\n\n 1: Wireless Keyboard\n Device path : /dev/hidraw6\n WPID : 4075\n Codename "
},
{
"path": "docs/devices/Wireless Keyboard K520 2011.txt",
"chars": 442,
"preview": " 2: Wireless Keyboard K520\n Device path : /dev/hidraw5\n WPID : 2011\n Codename : K520\n Kind"
},
{
"path": "docs/devices/Wireless Keyboard MK270 4023.txt",
"chars": 1728,
"preview": "Solaar version 1.1.7\n\n 1: Wireless Keyboard MK270\n Device path : /dev/hidraw6\n WPID : 4023\n Codena"
},
{
"path": "docs/devices/Wireless Mobile Mouse MX Anywhere 2 4072.txt",
"chars": 3693,
"preview": " 2: Wireless Mobile Mouse MX Anywhere 2\n Codename : MX Anywhere 2\n Kind : mouse\n Wireless PID :"
},
{
"path": "docs/devices/Wireless Mobile Mouse MX Anywhere 2S 406A.txt",
"chars": 4870,
"preview": "Solaar version 1.1.3\n\n 2: Wireless Mobile Mouse MX Anywhere 2S\n Device path : None\n WPID : 406A\n C"
},
{
"path": "docs/devices/Wireless Mobile Mouse MX Anywhere 2S B01A.txt",
"chars": 5586,
"preview": "solaar version 1.1.9\n\n 1: Wireless Mobile Mouse MX Anywhere 2S\n Device path : /dev/hidraw1\n USB id : 046"
},
{
"path": "docs/devices/Wireless Mouse 4022.txt",
"chars": 1513,
"preview": " 2: Wireless Mouse\n Codename :\n Kind : mouse\n Wireless PID : 4022\n Protocol : HID++ 2.0"
},
{
"path": "docs/devices/Wireless Mouse Dell WM514 4029.txt",
"chars": 2257,
"preview": "Solaar version 1.1.6rc4\n\n 3: Wireless Mouse Dell WM514\n Device path : /dev/hidraw5\n WPID : 4029\n C"
},
{
"path": "docs/devices/Wireless Mouse M185 new 4054.txt",
"chars": 2987,
"preview": "Solaar version 1.1.4rc2\n\n 2: Wireless Mouse M185 new\n Device path : /dev/hidraw3\n WPID : 4054\n Code"
},
{
"path": "docs/devices/Wireless Mouse M185,M235,M310 4055.txt",
"chars": 3121,
"preview": "Solaar version 1.1.4\n\n 1: Wireless Mouse M185/M235/M310\n Device path : /dev/hidraw2\n WPID : 4055\n "
},
{
"path": "docs/devices/Wireless Mouse M185.text",
"chars": 2568,
"preview": "solaar show\nrules cannot access modifier keys in Wayland, accessing process only works on GNOME with Solaar Gnome extens"
},
{
"path": "docs/devices/Wireless Mouse M215 2nd Gen 401B.txt",
"chars": 1800,
"preview": "Solaar version 1.1.5\n\n 1: Wireless Mouse M215 2nd Gen\n Device path : None\n WPID : 401B\n Codename "
},
{
"path": "docs/devices/Wireless Mouse M310 M310t 4031.txt",
"chars": 1754,
"preview": " 1: Wireless Mouse M310/M310t\n Codename : M310/M310t\n Kind : mouse\n Wireless PID : 4031\n Pr"
},
{
"path": "docs/devices/Wireless Mouse M325 400A.txt",
"chars": 3419,
"preview": "\n 1: Wireless Mouse M325\n Device path : /dev/hidraw4\n WPID : 400A\n Codename : M325\n Kind "
},
{
"path": "docs/devices/Wireless Mouse M345 4017.txt",
"chars": 861,
"preview": "1: Wireless Mouse M345\n Codename : M345\n Kind : mouse\n Wireless PID : 4017\n Protocol : HID++ 2.0"
},
{
"path": "docs/devices/Wireless Mouse M510 1025.txt",
"chars": 505,
"preview": "Solaar version 1.1.4\n\n 1: Wireless Mouse M510\n Device path : /dev/hidraw2\n WPID : 1025\n Codename "
},
{
"path": "docs/devices/Wireless Mouse M510 4051.txt",
"chars": 2647,
"preview": " 1: Wireless Mouse M510\n Codename : M510v2\n Kind : mouse\n Wireless PID : 4051\n Protocol "
},
{
"path": "docs/devices/Wireless Mouse M525 4013.txt",
"chars": 1409,
"preview": " 1: Wireless Mouse M525\n Codename : M525\n Kind : mouse\n Wireless PID : 4013\n Protocol :"
},
{
"path": "docs/devices/Wireless Mouse M560 402D.txt",
"chars": 2154,
"preview": " 1: Wireless Mouse M560\n Codename : M560\n Kind : mouse\n Wireless PID : 402D\n Protocol :"
},
{
"path": "docs/devices/Wireless Mouse MX Anywhere 2 404A.txt",
"chars": 1781,
"preview": " 1: Wireless Mouse MX Anywhere 2\n Codename : MX Anywhere 2\n Kind : mouse\n Wireless PID : 404A\n "
},
{
"path": "docs/devices/Wireless Mouse MX Master 2S 4069.txt",
"chars": 6823,
"preview": "Solaar version 1.1.4\n\n 1: Wireless Mouse MX Master 2S\n Device path : /dev/hidraw1\n WPID : 4069\n Co"
},
{
"path": "docs/devices/Wireless Mouse MX Master 2S B019.txt",
"chars": 6264,
"preview": "Solaar version 1.1.3\n\n 1: Wireless Mouse MX Master 2S\n Device path : /dev/hidraw3\n USB id : 046d:B019\n "
},
{
"path": "docs/devices/Wireless Mouse MX Master 4041.txt",
"chars": 6432,
"preview": " 4: Wireless Mouse MX Master\n Device path : /dev/hidraw4\n WPID : 4041\n Codename : MX Master\n "
},
{
"path": "docs/devices/Wireless Mouse MX Master 4071.txt",
"chars": 6742,
"preview": "Solaar version 1.1.4\n\n 3: Wireless Mouse MX Master\n Device path : /dev/hidraw3\n WPID : 4071\n Coden"
},
{
"path": "docs/devices/Wireless Mouse MX Master B012.txt",
"chars": 6387,
"preview": "Solaar version 1.1.3\n\n 1: Wireless Mouse MX Master\n Device path : /dev/hidraw4\n USB id : 046d:B012\n "
},
{
"path": "docs/devices/Wireless Mouse Pebble M350 4080.txt",
"chars": 3863,
"preview": "Solaar version 1.1.4\n\n 2: Wireless Mouse Pebble M350\n Device path : /dev/hidraw2\n WPID : 4080\n Cod"
},
{
"path": "docs/devices/Wireless Multi-Device Keyboard K780 405B.txt",
"chars": 9870,
"preview": "Solaar version 1.1.7\n\n 1: Wireless Multi-Device Keyboard K780\n Device path : /dev/hidraw4\n WPID : 405B"
},
{
"path": "docs/devices/Wireless Rechargeable Touchpad T650 4101.txt",
"chars": 1779,
"preview": " 1: Wireless Rechargeable Touchpad T650\n Codename : T650\n Kind : touchpad\n Wireless PID : 4101\n"
},
{
"path": "docs/devices/Wireless Solar Keyboard K750 4002.txt",
"chars": 2117,
"preview": " 2: Wireless Solar Keyboard K750\n Codename : K750\n Kind : keyboard\n Wireless PID : 4002\n Pr"
},
{
"path": "docs/devices/Wireless Touch Keyboard K400 4024.txt",
"chars": 2931,
"preview": "\n 1: Wireless Touch Keyboard K400\n Codename : K400\n Kind : keyboard\n Wireless PID : 4024\n P"
},
{
"path": "docs/devices/Wireless Touch Keyboard K400 Plus 404D.txt",
"chars": 9764,
"preview": "Solaar version 1.1.4\n\n 1: Wireless Touch Keyboard K400 Plus\n Device path : /dev/hidraw2\n WPID : 404D\n "
},
{
"path": "docs/devices/Wireless Trackball M570 1028.txt",
"chars": 407,
"preview": " 1: Wireless Trackball M570\n Codename : M570\n Kind : mouse\n Wireless PID : 1028\n Protocol "
},
{
"path": "docs/devices/Zone Touch Mouse T400 4026.txt",
"chars": 2504,
"preview": " 1: Zone Touch Mouse T400\n Codename : T400\n Kind : mouse\n Wireless PID : 4026\n Protocol "
},
{
"path": "docs/devices/anywhere-mx.txt",
"chars": 2828,
"preview": "Receiver\nLZ301AR-DJ\nM/N:C-U0007\n(ltunify)\nSerial number: D1759614\nFirmware version: 012.001.00019\nBootloader version: BL"
},
{
"path": "docs/devices/mk700.txt",
"chars": 999,
"preview": "# Enabled Notifications\n# 10 - battery status\n# 02 + 01 - remap FN keys (multimedia + power buttons)\n>> ( 1.412) [10 0"
},
{
"path": "docs/devices/performance-mx.txt",
"chars": 1509,
"preview": "# Notifications (r1_bit0 = battery status?)\n<< ( 0.113) [10 01 8100 000000] '\\x10\\x01\\x81\\x00\\x00\\x00\\x00'\n>> ( 0.15"
},
{
"path": "docs/devices.md",
"chars": 8812,
"preview": "---\ntitle: Supported Devices\nlayout: page\n---\n\n# Supported receivers and devices\n\nSolaar only supports Logitech receiver"
},
{
"path": "docs/features.md",
"chars": 13406,
"preview": "---\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 i"
},
{
"path": "docs/hidpp-documentation.txt",
"chars": 134,
"preview": "Documentation on HID++ can be found in the Google drive directory\nhttps://drive.google.com/drive/folders/0BxbRzx7vEV7eWm"
},
{
"path": "docs/i18n.md",
"chars": 3540,
"preview": "---\ntitle: Translating Solaar\nlayout: page\n---\n\n# Translating Solaar\n\nFirst, make sure you have installed the `gettext` "
},
{
"path": "docs/implementation.md",
"chars": 16594,
"preview": "---\ntitle: Solaar Implementation\nlayout: page\n---\n\n# Solaar Implementation\n\nSolaar has three main components: code mostl"
},
{
"path": "docs/index.md",
"chars": 8438,
"preview": "---\ntitle: Solaar\nlayout: default\n---\n\n**Solaar** is a Linux manager for many Logitech keyboards, mice, and trackpads\nth"
},
{
"path": "docs/installation.md",
"chars": 6900,
"preview": "---\ntitle: Manual Installation\nlayout: page\n---\n\n# Installing from PyPI\n\nAn easy way to install the most recent release "
},
{
"path": "docs/issues.md",
"chars": 3780,
"preview": "---\ntitle: Known Issues\nlayout: page\n---\n\n# Known Issues\n\n- Some internal structures in Solaar have been updated to use "
},
{
"path": "docs/rules.md",
"chars": 18655,
"preview": "---\ntitle: Rule Processing of HID++ Notifications\nlayout: page\n---\n\n# Rule Processing of HID++ Notifications\nCreating an"
},
{
"path": "docs/uninstallation.md",
"chars": 721,
"preview": "---\ntitle: Uninstalling Solaar\nlayout: page\n---\n\n# Uninstalling Solaar\n\n## Uninstalling from Debian systems\n\nIf you inst"
},
{
"path": "docs/usage.md",
"chars": 8750,
"preview": "---\ntitle: Solaar GUI Usage\nlayout: page\n---\n\n# Solaar GUI Usage\n\nThe Solaar GUI (the usual way to run Solaar) is meant "
},
{
"path": "docs/usb.ids.txt",
"chars": 12179,
"preview": "#\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 "
},
{
"path": "lib/hid_parser/__init__.py",
"chars": 34400,
"preview": "# SPDX-License-Identifier: MIT\n\nfrom __future__ import annotations # noqa:F407\n\nimport functools\nimport struct\nimport s"
},
{
"path": "lib/hid_parser/data.py",
"chars": 57667,
"preview": "# SPDX-License-Identifier: MIT\n\nimport enum\n\nfrom typing import Any\nfrom typing import Dict\nfrom typing import List\nfrom"
},
{
"path": "lib/hidapi/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "lib/hidapi/common.py",
"chars": 397,
"preview": "from __future__ import annotations\n\nimport dataclasses\n\n\n@dataclasses.dataclass\nclass DeviceInfo:\n path: str\n bus_"
},
{
"path": "lib/hidapi/hidapi_impl.py",
"chars": 19043,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/hidapi/hidconsole.py",
"chars": 8417,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/hidapi/udev_impl.py",
"chars": 16020,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/keysyms/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "lib/keysyms/generate.py",
"chars": 1231,
"preview": "#!/usr/bin/env python3\n\"\"\"Extract key symbol encodings from X11 header files.\"\"\"\n\nfrom pathlib import Path\nfrom pprint i"
},
{
"path": "lib/keysyms/keysymdef.py",
"chars": 61816,
"preview": "# flake8: noqa\nkey_symbols = {\n \"0\": 48,\n \"1\": 49,\n \"2\": 50,\n \"3\": 51,\n \"3270_AltCursor\": 64784,\n \"327"
},
{
"path": "lib/logitech_receiver/__init__.py",
"chars": 985,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/logitech_receiver/base.py",
"chars": 25860,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/logitech_receiver/base_usb.py",
"chars": 7603,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/logitech_receiver/common.py",
"chars": 17148,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/So"
},
{
"path": "lib/logitech_receiver/descriptors.py",
"chars": 17946,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/logitech_receiver/desktop_notifications.py",
"chars": 4654,
"preview": "## Copyright (C) 2024 Solaar contributors\n##\n## This program is free software; you can redistribute it and/or modify\n## "
},
{
"path": "lib/logitech_receiver/device.py",
"chars": 26061,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/So"
},
{
"path": "lib/logitech_receiver/diversion.py",
"chars": 56734,
"preview": "## Copyright (C) 2020 Peter Patel-Schneider\n##\n## This program is free software; you can redistribute it and/or modify\n#"
},
{
"path": "lib/logitech_receiver/exceptions.py",
"chars": 1726,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/So"
},
{
"path": "lib/logitech_receiver/hidpp10.py",
"chars": 10630,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/logitech_receiver/hidpp10_constants.py",
"chars": 7978,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/So"
},
{
"path": "lib/logitech_receiver/hidpp20.py",
"chars": 84611,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/So"
},
{
"path": "lib/logitech_receiver/hidpp20_constants.py",
"chars": 9628,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/So"
},
{
"path": "lib/logitech_receiver/i18n.py",
"chars": 2212,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/logitech_receiver/listener.py",
"chars": 6551,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/So"
},
{
"path": "lib/logitech_receiver/notifications.py",
"chars": 24003,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/So"
},
{
"path": "lib/logitech_receiver/receiver.py",
"chars": 23098,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/So"
},
{
"path": "lib/logitech_receiver/settings.py",
"chars": 35839,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/logitech_receiver/settings_new.py",
"chars": 9510,
"preview": "## Copyright (C) 2025 Solaar contributors\n##\n## This program is free software; you can redistribute it and/or modify\n##"
},
{
"path": "lib/logitech_receiver/settings_templates.py",
"chars": 90702,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/logitech_receiver/settings_validator.py",
"chars": 29025,
"preview": "from __future__ import annotations\n\nimport logging\nimport math\n\nfrom enum import IntEnum\n\nfrom logitech_receiver import "
},
{
"path": "lib/logitech_receiver/special_keys.py",
"chars": 48470,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/solaar/__init__.py",
"chars": 1311,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/solaar/cli/__init__.py",
"chars": 7970,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
},
{
"path": "lib/solaar/cli/config.py",
"chars": 12867,
"preview": "## Copyright (C) 2012-2013 Daniel Pavel\n##\n## This program is free software; you can redistribute it and/or modify\n## i"
}
]
// ... and 109 more files (download for full content)
About this extraction
This page contains the full source code of the pwr-Solaar/Solaar GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 309 files (3.6 MB), approximately 947.4k tokens, and a symbol index with 2129 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.