Compare commits

...

975 Commits
0.8.4 ... 1.0.2

Author SHA1 Message Date
Peter F. Patel-Schneider
4a108b3ab7 release 1.0.2 2020-05-22 01:43:53 +01:00
Peter F. Patel-Schneider
fac6cd6840 po: minor fix to es translation file 2020-05-22 01:19:20 +01:00
Peter F. Patel-Schneider
edf610d235 doc: add usage document 2020-05-22 01:18:44 +01:00
Peter F. Patel-Schneider
dac9c1bd8e doc: minor improvements to index.md 2020-05-22 01:18:44 +01:00
Peter F. Patel-Schneider
352375aa9a doc: minor improvements to installation.md 2020-05-22 01:18:44 +01:00
Peter F. Patel-Schneider
44722560d2 release 1.0.2rc3 2020-05-17 18:39:31 +01:00
daviddavid
101e24c7bf Update again French translation
- by David Geiger <david.david@mageialinux-online.org>
2020-05-17 11:57:11 -04:00
Peter F. Patel-Schneider
b7e8e646b5 ui: don't complain for receivers in other seats 2020-05-17 11:55:01 -04:00
Peter F. Patel-Schneider
97fa7de28a devices: pass arguments through in feature_choices_dynamic 2020-05-17 11:51:38 -04:00
Peter F. Patel-Schneider
302720b0db ui: add --battery-icons=symbolic option to prefer symbolic icons 2020-05-17 16:29:14 +01:00
daviddavid
813c238704 Update French translation
- by David Geiger <david.david@mageialinux-online.org>
2020-05-14 09:36:32 -04:00
Peter F. Patel-Schneider
354c914bd2 docs: improve installation document 2020-05-13 11:48:06 -04:00
daviddavid
574aee0cc7 po formatting updates (for release 1.0.2rc2) 2020-05-13 15:37:57 +01:00
Peter F. Patel-Schneider
a3cdcf4cd1 git: add lib/solaar.egg-info/ to .gitignore 2020-05-13 15:35:35 +01:00
Peter F. Patel-Schneider
592ced0a53 release 1.0.2rc2 2020-05-10 23:11:37 +01:00
Peter F. Patel-Schneider
3a2593798e release: fix up RELEASE.md 2020-05-10 03:49:32 +01:00
Peter F. Patel-Schneider
67b7d46844 docs: update ChangeLog 2020-05-07 19:33:57 +01:00
Peter F. Patel-Schneider
5411e43b77 ui: use Solaar icon instead of missing battery icons 2020-05-07 19:33:57 +01:00
Peter F. Patel-Schneider
66dc0bd285 release: remove packaging directory as it is not maintained 2020-05-02 18:44:34 +01:00
Peter F. Patel-Schneider
f641554ed5 release: release candidates do not have hyphen before rc 2020-05-02 17:42:13 +01:00
Peter F. Patel-Schneider
beec4c2130 release: change version from 1.0.2-rc1 to 1.0.2rc2 2020-05-02 17:42:13 +01:00
Peter F. Patel-Schneider
f5bf488ffc docs: update ChangeLog for 1.0.2rc2 2020-05-02 17:42:13 +01:00
Steven Lilley
1deaa09142 devices: Add Pebble M350 mouse 2020-05-02 17:25:29 +01:00
Peter F. Patel-Schneider
88a0dfff6f ui: add environment variable to switch to symbolic battery icons in tray 2020-05-02 10:28:51 -04:00
Peter F. Patel-Schneider
f28da6e7c4 docs: add a short discussion of how battery icons work 2020-05-02 10:28:51 -04:00
Peter F. Patel-Schneider
5290980ac8 ui: only use standard battery icons 2020-05-02 10:28:51 -04:00
Peter F. Patel-Schneider
4d23d3abac device: heuristic inference of battery level when charging and no discharging information available 2020-05-02 09:58:24 -04:00
Peter F. Patel-Schneider
0c4e757cf9 docs: add K600 TV, M350 WPID 4080, and MX Keys to devices.md and improve wording in it 2020-05-02 09:26:01 -04:00
Peter F. Patel-Schneider
d487a0d889 ui: remove assert that updated receiver is still in window 2020-05-02 14:07:42 +01:00
Roshan Shariff
65824a4c08 ui: add 'desktop-entry' hint to indicate notification source.
GNOME requires that notifications have a 'desktop-entry' hint to be
able to filter notifications by application. See
https://wiki.gnome.org/Initiatives/GnomeGoals/NotificationSource.

Fixes pwr-Solaar/Solaar#734
2020-05-01 13:56:22 -04:00
tarxf
58a1c7ffb0 docs: dixed name typo for MX Master 2S 2020-04-25 02:38:02 +01:00
Peter F. Patel-Schneider
1f896d2b9e docs: add changing device features to long description of Solaar 2020-04-22 21:37:25 +01:00
Peter F. Patel-Schneider
377c954933 install: remove Daniels email from setup.py 2020-04-20 12:01:57 -04:00
Peter F. Patel-Schneider
4744ce47b2 install: update installation directions and remove outdated rules/install.sh 2020-04-20 12:01:57 -04:00
Peter F. Patel-Schneider
b01b74f2a8 install: install udev rule with pip 2020-04-20 12:01:57 -04:00
Peter F. Patel-Schneider
6282ae05e8 install: remove incorrect code for determining autostart directory from setup.py 2020-04-20 12:01:57 -04:00
Peter F. Patel-Schneider
b5e1f47c50 ui: add setuptools global install share directory to icon directories 2020-04-20 10:32:40 -04:00
Peter F. Patel-Schneider
8ffaeb112f devices: add four older devices 2020-04-20 15:26:37 +01:00
Peter F. Patel-Schneider
2189d4a35b receiver: add new macro for old receivers and use it to set max devices to 6 for C517 2020-04-20 15:26:37 +01:00
Jan Szenborn
706ee2990f Improve polish translations 2020-04-20 15:25:47 +01:00
Peter F. Patel-Schneider
06875fb9ab release: update remaining version 1.0.1 to 1.0.2-rc1 where needed 2020-04-20 15:22:30 +01:00
Peter F. Patel-Schneider
f6b0cc59ed ui: only use file path for tray icon if icon name is file in current directory 2020-04-20 15:21:19 +01:00
Peter F. Patel-Schneider
e3aacdbf05 receiver: don't check that device kind matches feature kind 2020-04-20 15:20:03 +01:00
Peter F. Patel-Schneider
45dc81b4c4 docs: update information on pre-built packages 2020-04-20 15:19:22 +01:00
Peter F. Patel-Schneider
0324fd9a1e ui: more flexible way to determine icon from battery level 2020-04-18 14:27:42 +01:00
Thomas Uhle
ca9f9b3447 ui: add support for Ayatana AppIndicator 2020-04-07 18:58:18 -04:00
Peter F. Patel-Schneider
624247d378 install: fix up errors when required packages not installed 2020-04-05 20:55:32 +01:00
Thomas Uhle
5f8dbdeb6d ui: fix tooltip description
The program's name is printed twice if AppIndicator is used and no receiver
is found because AppIndicator always adds the program's name as a title to
the tooltip.
2020-04-01 11:10:54 -04:00
Thomas Uhle
2bdb844557 ui: fix end of iterative calls to _blink()
Prepare _icon_before_attention for the next iteration by reinitializing it
at the end of the current iteration.
2020-04-01 11:10:54 -04:00
Thomas Uhle
422f336d70 ui: add missing parentheses to function call
Compare function's return value to AppIndicator3.IndicatorStatus.ATTENTION
instead of the function object reference.
2020-04-01 11:10:54 -04:00
Peter F. Patel-Schneider
563ef0d8ef receiver: remove extra argument in call when unpairing 2020-03-22 17:23:28 +00:00
Peter F. Patel-Schneider
3a85c4f64b UI: lookup attention icon filename directly to get around bug in libappindicator 2020-03-17 23:17:59 +00:00
Filipe Laíns
4056f5b9d3 release.sh: simplify script
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-03-16 21:59:41 +00:00
Filipe Laíns
442a7d18a5 release.sh: document release process
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-03-16 21:59:41 +00:00
Filipe Laíns
79be4b20d7 release.sh: don't throw github release creation error on dry run
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-03-16 21:59:41 +00:00
Filipe Laíns
b2f3b56c31 release 1.0.2-rc1
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-03-16 20:57:35 +00:00
Peter F. Patel-Schneider
072f932206 ui: handle devices and receivers with no firmware information 2020-03-16 20:55:18 +00:00
Filipe Laíns
d5a3a4fe7e release.sh: initial script
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-03-16 16:58:41 +00:00
Peter F. Patel-Schneider
a49b7938e0 receiver: Receiver C517 can have two paired devices 2020-03-16 16:04:16 +00:00
Peter F. Patel-Schneider
1eef88eb44 cli: handle receivers with no firmware information 2020-03-16 16:04:16 +00:00
Peter F. Patel-Schneider
eda1399330 cli: force unpairing attempt when using cli 2020-03-15 23:34:51 +00:00
Peter F. Patel-Schneider
8dbc4b5707 docs: Update ChangeLog 2020-03-15 23:33:47 +00:00
Peter F. Patel-Schneider
687a28d2c2 UI: lookup icon filenames directly to get around bug in libappindicator 2020-03-15 22:00:56 +00:00
Peter F. Patel-Schneider
f733390bd1 install: autostart .desktop file has --window=hide 2020-03-15 22:00:21 +00:00
Peter F. Patel-Schneider
ac6fa9643f UI: change default for --window to show 2020-03-15 22:00:21 +00:00
Peter F. Patel-Schneider
f28053a09a docs: improve documentation on required packages 2020-03-15 21:59:42 +00:00
gogogogi
49145ae272 translations: Update Croatian language translation
* Update Croatian language

* Update version
2020-03-15 16:30:00 -04:00
Peter F. Patel-Schneider
af26870e83 docs: use correct name of udev rules file in installation directions 2020-03-08 15:15:17 +00:00
Peter F. Patel-Schneider
007163a563 docs: update ChangeLog 2020-03-08 15:15:17 +00:00
Peter F. Patel-Schneider
a9acdbe47a receiver: add c537 nano receiver 2020-03-06 18:00:37 -05:00
Peter F. Patel-Schneider
955df30c7f upower: properly add signal receiver 2020-02-22 08:46:56 -05:00
Peter F. Patel-Schneider
23c0397764 listener: mark device as inactive after resume so that settings are correctly pushed 2020-02-22 08:46:56 -05:00
Peter F. Patel-Schneider
789f5f05c3 receiver: don't check features when device is not online 2020-02-22 08:46:56 -05:00
Peter F. Patel-Schneider
ea2c22c015 receiver: fix seldom-encountered bug for devices that have no features set up yet 2020-02-21 16:52:28 +00:00
Peter F. Patel-Schneider
1c09b9c45d upower: add in logind signals for suspend/resume 2020-02-21 16:52:28 +00:00
Peter F. Patel-Schneider
dd9626f7a4 docs: ask for git describe output if running a cloned version 2020-02-21 16:48:05 +00:00
Rijnhard Hessel
35909afb0d packaging: remove solaar-gnome3 package 2020-02-21 09:50:30 -05:00
Rijnhard Hessel
8e67bbbc11 receiver: add safety for non-compliant mouse features
receiver: safely handle errors with check_feature to allow device to be detected even if some features are inconsistent
2020-02-21 09:33:14 -05:00
Peter F. Patel-Schneider
a5813e4e23 packaging: remove last vestiges of python2 2020-02-20 19:49:38 +00:00
Peter F. Patel-Schneider
d439d43be6 docs: replace dummy URL for Solaar with real URL 2020-02-20 12:27:41 +00:00
Peter F. Patel-Schneider
11465f2b2a cli: add probe command to show receiver register information 2020-02-18 23:21:59 +00:00
Peter F. Patel-Schneider
079f2dacd4 docs: add information on --windows flag and rewrite other bits of index.md 2020-02-18 08:32:02 -05:00
Peter F. Patel-Schneider
7c6bd4202d receiver: use dictionary for expected message length checking; ignore messages with unknown report ids 2020-02-18 08:14:22 -05:00
Peter F. Patel-Schneider
1740a9a8c4 receiver: segregate and standardly handle DJ notifications separately - just ignore them all for now 2020-02-18 08:14:22 -05:00
Peter F. Patel-Schneider
0cadc3247e receiver: don't create notifications for movement and key reports 2020-02-18 08:14:22 -05:00
Peter F. Patel-Schneider
e23de2ee9f ui: add quit button to main window 2020-02-18 13:14:10 +00:00
Peter F. Patel-Schneider
8fb52a3f37 ui: don't show warning in pairing window for receivers with unlimited pairing 2020-02-18 12:19:45 +00:00
Peter F. Patel-Schneider
3edac85b90 ui: turn on window manager notifications again 2020-02-18 12:17:49 +00:00
Peter F. Patel-Schneider
64c76e51ef receiver,cli,ui: minor code cleanup 2020-02-17 11:53:39 +00:00
Peter F. Patel-Schneider
02cac598a0 receiver: all nano receivers re-pair but don't unpair 2020-02-17 11:53:39 +00:00
Peter F. Patel-Schneider
02a47b4003 install: adjust autostart desktop installation to use usual desktop file 2020-02-17 08:35:47 +00:00
Peter F. Patel-Schneider
4afe8c893b ui: add option to show the main window or run solaar without tray 2020-02-17 08:35:47 +00:00
Peter F. Patel-Schneider
5afa094175 ui: Add message about remaining pairings to pairing window when receiver has limited pairings 2020-02-17 08:34:53 +00:00
Peter F. Patel-Schneider
196705ba1f docs: fix information about receiver c534 2020-02-17 08:34:53 +00:00
Peter F. Patel-Schneider
4c46a999f7 gui: treat nano protocol disconnections correctly when pairing 2020-02-17 08:34:53 +00:00
Peter F. Patel-Schneider
7bd31c0d95 cli: complain when trying to unpair from a receiver that does not unpair 2020-02-17 08:34:53 +00:00
Peter F. Patel-Schneider
dc2a1adf26 ui: handle re-pairing receivers correctly when pairing 2020-02-17 08:34:53 +00:00
Peter F. Patel-Schneider
e89b50cdf2 cli: correct reporting for pairing with receivers that re-pair (i.e., c534) 2020-02-17 08:34:53 +00:00
Peter F. Patel-Schneider
d08e0a9574 cli: Show a positive response instead of an error when receiver pairs on already-used slot in CLI 2020-02-17 08:34:53 +00:00
Peter F. Patel-Schneider
22d37c4c1c ui: Better determination in GUI of when receiver may pair (still might be conservative) 2020-02-17 08:34:53 +00:00
Peter F. Patel-Schneider
546ccb7ac2 receiver: determine remaining pairings (if receiver has this) and display in solaar show and main window 2020-02-17 08:34:53 +00:00
Peter F. Patel-Schneider
1ab03d4c9f receiver: add check for bad results from getting the usb device 2020-02-16 22:16:37 +00:00
Peter F. Patel-Schneider
a6fcb75aa8 receiver: get receiver name from receiver information list 2020-02-16 22:16:37 +00:00
Peter F. Patel-Schneider
907c5ab075 receiver: change usb identification of receivers to dictionary to allow adding other fields, add receiver name to dictionary 2020-02-16 22:16:37 +00:00
Peter F. Patel-Schneider
515f994ab8 receiver: ignore disconnects of disconnected devices 2020-02-16 22:16:37 +00:00
Peter F. Patel-Schneider
25905c5d77 receiver: Show type of receiver in CLI show command 2020-02-16 22:16:37 +00:00
Peter F. Patel-Schneider
babf0f4ded receiver: Show serial number in stringify of receivers 2020-02-16 22:16:37 +00:00
Peter F. Patel-Schneider
41664b8e21 docs: update changelog to 11 February 2020 commits 2020-02-16 22:07:45 +00:00
svntjng
5c080a7831 docs: add supported feature for M330 2020-02-16 22:06:12 +00:00
Peter F. Patel-Schneider
5aa4fa0239 update version in docs/_config.yml to 1.0.1 2020-02-11 15:55:15 +00:00
Peter F. Patel-Schneider
4f4e610635 receiver: battery level 0 is unknown level 2020-02-10 18:44:28 +00:00
Peter F. Patel-Schneider
39791be440 doc: fix typos and improve some wording 2020-02-06 19:09:00 +01:00
Peter F. Patel-Schneider
2814350f9f doc: fix wording about supported Nano receivers 2020-02-06 19:09:00 +01:00
Peter F. Patel-Schneider
4a28b48275 doc: add paragraph on firmware 2020-02-06 19:09:00 +01:00
Peter F. Patel-Schneider
97474a21de doc: fix formatting, add receivers, change version 4.5 to 2.0 2020-02-06 19:09:00 +01:00
Peter F. Patel-Schneider
719106bf0f doc: solaar does keep track of device status 2020-02-06 19:09:00 +01:00
Peter F. Patel-Schneider
0a735a32ed doc: better documentation: devices and capabilities 2020-02-06 19:09:00 +01:00
Dmitriusan
bd26b9340d scripts/debian: switch to python3 2020-02-06 19:06:47 +01:00
Peter F. Patel-Schneider
f45ae5ffad solaar: use python3, not generic python 2020-02-06 17:37:10 +01:00
Peter F. Patel-Schneider
0520dde990 receiver: use None for serial number of c534 2020-02-04 22:04:43 +01:00
Peter F. Patel-Schneider
e53781ec6e install: autostart desktop file starts with tray only 2020-01-22 22:22:14 +00:00
Peter F. Patel-Schneider
1bc189e2fe ui: add --tray option to start without window visible 2020-01-22 22:22:14 +00:00
Peter F. Patel-Schneider
91bcfa28ea docs: minor changes to installation.md to eliminate python2 support 2020-01-21 21:51:35 +00:00
Filipe Laíns
64c1de32da setup.py: drop python 2 support
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-01-21 21:51:25 +00:00
Peter F. Patel-Schneider
56762b5494 device: move persister from Setting to _DeviceDescriptor to get around problem with settings discovered after startup 2020-01-21 03:23:25 +00:00
Peter F. Patel-Schneider
77e21a0b63 ui: fix crash when styles add padding by not setting 1-pixel columns; slightly better window layout; add style class to window 2020-01-21 03:11:35 +00:00
Peter F. Patel-Schneider
d6fa5269c5 ui: don't ignore offline devices when determining whether pairing is possible 2020-01-21 03:08:49 +00:00
Peter F. Patel-Schneider
0198d58dc7 hidpp20: fix error when showing battery
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-01-19 18:18:33 +00:00
Filipe Laíns
c30f0a79bd docs: features: add partly working and unsupported status
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-01-19 18:18:30 +00:00
Filipe Laíns
89ee83b906 docs: features: change checkmark style
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-01-19 18:18:11 +00:00
Filipe Laíns
0bef7b84f8 docs: features: make the table easier to maintain
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-01-19 18:18:08 +00:00
Filipe Laíns
c3e90bc73e docs: features: make the table readable in plain ascii
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-01-19 18:17:54 +00:00
Alex Cherkayev
814b7f30ba docs: features: added some missing feature names and list of implemented features
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2020-01-19 18:17:18 +00:00
Alex Cherkayev
8039c035a7 devices: Add new variant of K800 keyboard
docs: Add K800 new variant to supported
2020-01-12 16:11:03 +00:00
effective-light
430b70711b hidpp20: features: add BATTERY_VOLTAGE (0x1001) support
Signed-off-by: Filipe Laíns <lains@archlinux.org>

Co-authored-by: Filipe Laíns <lains@archlinux.org>
2020-01-12 16:05:21 +00:00
nightsky30
82915eea4b docs: update the USB IDs list 2019-12-29 14:46:59 +00:00
Peter F. Patel-Schneider
995544396c receiver: don't log messages with unknown report IDs 2019-12-26 16:10:48 +00:00
Peter F. Patel-Schneider
4678f52293 don't have window always be on top 2019-12-24 18:54:12 +00:00
Peter F. Patel-Schneider
26c5a5f9ba clarify license status; fix debian packaging copyight notice 2019-12-24 18:53:43 +00:00
Peter F. Patel-Schneider
c6ccc0638d devices: add M310 2019-12-24 12:49:00 +00:00
drupal-daffie
6ba8c6c3fc setup: use setuptools if available 2019-12-24 12:16:35 +00:00
Peter F. Patel-Schneider
9087f4187c docs: adjust documentation to new changes 2019-12-24 12:13:58 +00:00
drupal-daffie
673c81c096 docs: devices: add MX Master 2s 2019-12-16 15:33:50 +00:00
drupal-daffie
43bfa80753 docs: devices: add Mx Master 3 2019-12-16 12:03:03 +00:00
gogogogi
3884ce14d7 docs: readme: add new ppa 2019-12-14 21:22:25 +00:00
spaced
4fafd4f6be hidpp20: features: add very basic implementation of 0x1982 (Backlight 2)
Fixes #547
2019-12-12 18:56:08 +00:00
Chris Rainey
0bec0e02b1 docd: devices: add M330 2019-12-10 23:36:31 +00:00
Filipe Laíns
59c0367283 github: add issue templates 2019-12-01 21:48:57 +00:00
marcelkarger
63f523dac6 po: update German translation 2019-11-30 23:14:32 +00:00
Heimen Stoffels
4822975acb po: added Dutch translation 2019-11-30 23:13:26 +00:00
Chad Condon
c389c9c2b7 ur: repair low resolution smooth scrolling 2019-11-30 23:12:07 +00:00
KTB
76e70799aa Update devices.md for Anywhere MX 2 - R/W DPI
Simple doc update to show that Solaar supports changing DPI for the Logitech Anywhere MX 2.
2019-10-20 23:55:02 +01:00
Tom Swartz
2a94cc9233 Fix typos in docs 2019-10-20 23:53:45 +01:00
Tom Swartz
ae9e862f19 Fix typos in comments 2019-10-20 23:53:45 +01:00
Tom Swartz
12f4e187d6 Fix typos in logging, output 2019-10-20 23:53:45 +01:00
Filipe Laíns
51dd2a5d28 notifications: add missing protocol names
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2019-10-20 23:19:34 +01:00
Alex Cherkayev
6981555804 notifications: fix battery status notification parsing
Fix indicator tooltip (duplicate Solaar line, python list instead of battery status).
2019-08-20 09:40:39 +02:00
spaced
3583759d3a devices: basic support for craft keyboard
* basic support for craft keyboard
* fix issue where _(status) throws exception because namedInt with UTF8.decode
2019-08-20 09:39:11 +02:00
david_david
c92a889b68 po: formatting updates
* po formatting updates

- Update French translation by David Geiger <david.david@mageialinux-online.org>
- Update version into setup.py file

* Update version in fr.po
2019-08-20 09:37:15 +02:00
Peter Wu
b9fb005c9c docs: Deduplicate README contents, use a symlink
docs/index.md and README.md are almost identical, except for some paths
and the metadata table on top of the file. Use absolute paths to the
website to avoid breaking links, and symlink README.md.
2019-08-20 09:36:16 +02:00
Zachary Cook
a06ea6de11 data: fix icon theme for battery level
It was previously assigning levels 1-89 to caution and 90+ to full, which was unintended due to the floor division by 100
2019-08-20 09:35:31 +02:00
Andreas Schneider
a868b477e1 Fix reading and storing DPI in config settings
Fixes #328
Fixes #356
Fixes #545
2019-08-20 09:24:22 +02:00
spaced
c799e038de added to list of supported devices 2019-08-20 09:23:38 +02:00
spaced
8468be2126 add doc for silent mouse M585/M590 2019-08-20 09:23:38 +02:00
spaced
1ff9c3a40b support for silent mouse M585/M590 2019-08-20 09:23:38 +02:00
Chris Johnston
9b201f6b0d copy updated README content 2019-07-27 15:56:53 +01:00
Chris Johnston
afda6f9f66 remove all google analytics stuff from page templates 2019-07-27 15:56:53 +01:00
Chris Johnston
5cc0b8854d update config.yml for new repo path 2019-07-27 15:56:53 +01:00
Chris Johnston
f88951c56d Squash previous changes and rebase master branch
Set theme jekyll-theme-slate

update _config.yml

move some files around

add an index file

delete files that will no longer be needed

include jekyll front matter

Update the index page layout to use updated template

re-create the page layout from the updated template

add a favicon

remove manual gh pages build script

use master branch docs/ folder instead

add favicon to default layout

move layouts and includes back because of restriction with gh pages

testing: move index back into project root

move everything under docs, including config.yml

dont put the favicon in _includes

Fix building locally, fix logo

- resize the original logo document so that it doesn't have extra whitespace
- style the logo to match the original page
- fix issue when building locally, repo format was incorrect

Ignore files that are specific to documentation

add a readme that describes how to build the docs

remove downloads, since installation instructions are provided elsewhere

fix broken links in index page

fix the page header on all non-index pages

use site.baseurl for images

fix urls when on testing site with baseurl
2019-07-27 15:56:53 +01:00
Filipe Laíns
2aab7f71fd release 1.0.1
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2019-07-26 16:55:51 +01:00
Filipe Laíns
6376980213 udev: fix c52b + MX Master
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2019-07-26 17:50:13 +02:00
Filipe Laíns
1bb08d011d base-usb: add new Lightspeed receiver
used in the G305

Signed-off-by: Filipe Laíns <lains@archlinux.org>
2019-07-26 15:23:55 +01:00
Filipe Laíns
966c55e69d base-usb: fix non-unifying for linux 5.2
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2019-07-26 15:18:24 +01:00
Filipe Laíns
6b14004a6f udev: fix writting to the device
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2019-07-26 15:10:59 +01:00
Daehyeok Mun
7a4f7bbb84 docs: fix broken github.io link to new repo url
Signed-off-by: Daehyeok Mun <daehyeok@gmail.com>
2019-07-26 15:38:16 +02:00
Matthias Fulz
155e2f8c40 fix: #531 #537. Better handling of EPIPE during hid write. 2019-07-26 15:35:21 +02:00
Filipe Laíns
6a1968beff release 1.0.0
Signed-off-by: Filipe Laíns <lains@archlinux.org>
2019-07-26 14:33:16 +01:00
Filipe Laíns
f4557233f1 base-usb: add support for Lightspeed receivers
They way we are currently identifying the type of a receiver (unifying,
nano, lightspeed) in the Receiver class is pretty bad. The correct
approach would be to specify the receiver type name string in
base_usb.py.

Signed-off-by: Filipe Laíns <lains@archlinux.org>
2019-07-16 11:10:03 +02:00
muzena
a597b81f5a Update Croatian translation 2019-07-14 23:57:15 +01:00
Peter Wu
a587ae65d1 Merge pull request #477 from doctor64/pointer_info_show
Added status info print and rename some functions
2019-06-29 18:08:52 +02:00
Peter Wu
6522b5fef0 Merge pull request #514 from pdecat/fix-zh_TW
Fix zh_TW translation (nplural=1)
2019-06-29 18:05:49 +02:00
Peter Wu
7f78f0c580 Merge pull request #515 from pdecat/fix-icon-dep
Add gnome-icon-theme as an acceptable dependency for icons
2019-06-29 18:05:14 +02:00
Peter Wu
127a8053d8 Merge pull request #521 from kacpi2442/master
Added basic support for Lenovo dongle,
https://download.lenovo.com/consumer/options/lenovo_n50_wireless_optical_mouse.pdf
2019-06-29 18:04:25 +02:00
Patrick Decat
6c0acee645 Fix UnicodeDecodeError with ngettext and python2 2019-06-29 18:01:54 +02:00
nicolas
60c52eb13f Name for K780
“Multi-Device” and not “Solar”
2019-06-29 17:59:44 +02:00
Benoit Hanotte
8bac8d68f4 Add MX Master settings
Add the same settings to the logitech MX Master as the one from the MX
Master 2 (scroll wheel DPI, smart scoll sensitivity).
2019-06-29 17:57:02 +02:00
Maarti
087a5d2c42 Update of the installation instructions for Debian (#490)
Solaar is available on official Debian repository and the old repo link
`https://pwr.github.io/Solaar/packages/` is dead and causes `404 Not
Found` error and `The repository 'http://pwr.github.io/Solaar/packages
./ Release' does not have a Release file.` error when doing `apt update`
so I updated the installation instructions.
2019-06-29 17:56:07 +02:00
kacpi2442
481511b6c2 Added basic support for Lenovo dongle 2019-04-15 15:40:40 +02:00
Patrick Decat
21d98294bd Add gnome-icon-theme as an acceptable dependency for icons 2019-03-26 15:46:14 +01:00
Patrick Decat
ebbb54758b Fix zh_TW translation (nplural=1) 2019-03-26 15:12:44 +01:00
Peter Wu
c07c115ee3 Avoid collision for wpid 4055 (M185 vs M235)
Hopefully use of a slash does not cause issues. M505 already uses slash
in its codename.

Fixes #499
2019-01-30 16:58:00 +01:00
Peter Dave Hello
8c02320795 docs/devices: Add m235 device information 2019-01-30 16:55:24 +01:00
Markus Heiser
932164458a icons: add application icons from repo's $git-toplevel/share/solaar/
Add application path from the repository to the search paths.

When you Install a project in editable mode (i.e. setuptools "develop mode")
from a local project path, the application path is ``./share``, relative to
git's top level folder. Add this path at the end of search path::

  echo "$(git rev-parse --show-toplevel)/share"
2019-01-30 12:38:54 +01:00
Markus Heiser
de79bf1b5c gtk.main(): make source more readable + comment about cli & gui 2019-01-30 12:38:54 +01:00
Markus Heiser
5944103aef setup.py: fix install_requires and add comment about OS packages 2019-01-30 12:38:54 +01:00
Markus Heiser
ab4226e066 setup.py: fix ModuleNotFoundError: No module named 'solaar'
Fix the "chicken or the egg" problem: while installing solaar, setup.py tries to
import solaar. This will only work if solaar already is installed before. On
first time installation a import exception is raised.::

$ pip install git+https://github.com/pwr/Solaar.git
Collecting git+https://github.com/pwr/Solaar.git
  Cloning https://github.com/pwr/Solaar.git to /tmp/pip-req-build-xzyoskf5
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-req-build-xzyoskf5/setup.py", line 11, in <module>
        from solaar import NAME, __version__
    ModuleNotFoundError: No module named 'solaar'
2019-01-30 12:38:54 +01:00
Peter Dave Hello
a66121db0d Optimize PNG images losslessly with zopflipng (#484)
11 images recompressed as below:

jekyll/images/bg_hr.png              | Bin 943 -> 96 bytes
jekyll/images/blacktocat.png         | Bin 1428 -> 432 bytes
jekyll/images/icon_download.png      | Bin 1162 -> 230 bytes
jekyll/images/sprite_download.png    | Bin 16799 -> 14650 bytes
share/solaar/icons/light_000.png     | Bin 1750 -> 1657 bytes
share/solaar/icons/light_020.png     | Bin 1942 -> 1895 bytes
share/solaar/icons/light_040.png     | Bin 1578 -> 1461 bytes
share/solaar/icons/light_060.png     | Bin 2442 -> 2319 bytes
share/solaar/icons/light_080.png     | Bin 1910 -> 1803 bytes
share/solaar/icons/light_100.png     | Bin 2376 -> 2249 bytes
share/solaar/icons/light_unknown.png | Bin 1108 -> 1007 bytes
2019-01-30 12:36:20 +01:00
Peter Dave Hello
eacfdea37f Add zh_TW Traditional translation po file (#485) 2019-01-30 12:35:35 +01:00
Peter Dave Hello
68b1f4e413 Update Data of Wireless Mouse M235 (#486) 2019-01-30 12:35:20 +01:00
CD Athuraliya
947035a7b7 Add K400 Plus (#492) 2019-01-30 12:30:36 +01:00
Xaver Maierhofer
e54134cda9 Update arch package information (#496) 2019-01-30 12:29:58 +01:00
Beni Cherniavsky-Paskin
1609c3e98a Display "K400 Plus" rather than just "Plus" (#483) 2018-12-30 18:19:38 +01:00
Alex Cherkayev
ed9aa76547 Added status info on features MOUSE_POINTER, VERTICAL_SCROLLING, HI_RES_SCROLLING, POINTER_SPEED and LOWRES_WHEEL to solaar show.
Renamed functions for HI_RES_SCROLLING and LOWRES_WHEEL features for consistency.
2018-11-20 16:29:38 +02:00
Danny
b8529030e6 setup.py: detect "--prefix=" correctly. (#433) 2018-08-15 18:46:50 +02:00
Peter Wu
1412a07899 Merge pull request #440 from nostrad/master
Improve trackball support
2018-08-15 15:14:08 +02:00
Mattias Jernberg
f79ad67ea7 Add trackball for all settings that mice have 2018-08-13 18:44:16 +02:00
Mattias Jernberg
dd8018a4d5 Prepare for allowing multiple device kinds in settings 2018-08-13 18:44:16 +02:00
Mattias Jernberg
350784eb70 Print an error message when assertion fails 2018-08-13 18:36:52 +02:00
Peter Wu
f0fc63e5b7 Merge pull request #295 from cschreib/master
Added support for MintX icon set (for Linux Mint integration)
2018-08-13 11:33:10 +02:00
Peter Wu
51375d4510 Merge pull request #454 from lopsided98/tree-scroll-fix
Fix device tree GUI hierarchy (Closes #453).
2018-08-12 12:22:50 +02:00
Ben Wolsieffer
2c0ea34694 Fix device tree GUI hierarchy. 2018-08-11 16:24:15 -04:00
Peter Wu
867edf8516 Merge pull request #146 from tristianc/master
Added border around tree view.
2018-08-11 17:55:37 +02:00
Peter Wu
dcd1a88250 Merge pull request #390 from Toshik1978/master
Added Logitech K375s support
2018-08-11 16:36:13 +02:00
Peter Wu
8f95dd323d Merge pull request #410 from lckarssen/add-mx-ergo
Update devices.md with MX Ergo trackball
2018-08-11 16:27:29 +02:00
Peter Wu
336b778398 Merge pull request #452 from lopsided98/hidpp-4.5-fixes
Fix errors related to sleep and power on/off (especially HID++ >=2.0 devices).

Closes #414 by @SonicFrog who originally came up with a similar fix for the connection notice.
2018-08-11 16:26:25 +02:00
Peter Wu
572c7f5e59 Merge pull request #450 from lopsided98/new-m705
Add support for new version of M705 (M-R0073).
2018-08-11 16:11:37 +02:00
Peter Wu
6b12b7935f Merge pull request #428 from Lin-Buo-Ren/patch-add-mk240-nano-information
Information and comments regarding Logitech MK240 NANO Combo
2018-08-11 16:06:08 +02:00
Peter Wu
ade2fbacec Merge pull request #399 from Valantin/patch-1
Add MX Master 2S descriptor
2018-08-11 16:03:18 +02:00
Ben Wolsieffer
a59368f3e7 Fix issues with HID++ >= 2.0 devices (particularly related to sleep).
* Don't assume 0x41 messages only occur when a device is first paired
    (prevents errors when waking from sleep or turning a device on)
  * Delay reads/writes when a device is powered on, to prevent broken pipe
    errors (hacky solution).
  * Don't clear status when a device connects, preventing settings from being
    cleared when a device sleeps or is turned off.
  * Fix typos.
2018-08-10 23:15:37 -04:00
Jason Tibbitts
d021d87656 Python 3.7 compatibility fixes
This fixes the python 3.7 incompatibilities arising from 'async'
becoming a reserved word.

The file lib/solaar/async.py is renamed to asks.py.  I picked the name
because it defines the TaskRunner class and it's the best I could come
up in fifteen seconds.

The async function in solar/ui/__init__.py is renamed to ui_async, and
the various imports of that function are changed to match.

Without this patch it doesn't build at all.  I am running with this
patch applied and everything appears to work as expected.

Signed-off-by: Jason Tibbitts <tibbs@math.uh.edu>
2018-08-07 12:51:32 -04:00
Ben Wolsieffer
5d0d353c74 Add support for new version of M705 (M-R0073). 2018-08-05 00:10:59 -04:00
林博仁(Buo-ren, Lin)
e00d680fc9 Information and comments regarding Logitech MK240 NANO Combo
Signed-off-by: 林博仁(Buo-ren, Lin) <Buo.Ren.Lin@gmail.com>
2018-04-12 14:15:47 +08:00
Peter Wu
59b7285fdf Merge pull request #412 from aimylios/aimylios-fedora
Update link to Fedora package in README.md
2018-02-02 16:20:47 +01:00
aimylios
988bdc2c8d Update link to Fedora package in README.md
The "Fedora Package DB" is not updated any more, refer to the new "Fedora Packages" instead.
2018-01-14 12:15:38 +01:00
Peter Wu
1a67b33860 Merge pull request #382 from mchehab/fix_solaar_start_issues
Fix solaar start issues
2018-01-12 18:11:45 +01:00
Lennart C. Karssen
d43bffc9d9 Update devices.md with MX Ergo trackball
This commit adds the Logitech MX Ergo to the list of supported devices.
2018-01-04 16:52:23 +01:00
Roberto Valentini
f8079f4f9d Add MX Master 2S descriptor
Add descriptor for MX Master 2S to support High Resolution Wheel, correct charge level and DPI configuration
2017-11-16 14:53:27 +01:00
Anton Krivenko
47e7f997d5 Added Logitech K375s support 2017-10-14 22:08:40 +03:00
Peter Wu
8c0cf9fe9b Merge pull request #342 from jrbenito/MK270-desc
Mk270 Combo information and descritptors
2017-09-26 23:16:58 +01:00
Peter Wu
fa8bd83ba3 Merge pull request #387 from ryantig/patch-1
Minor installation.md edit; gpasswd cmd
2017-09-26 23:13:59 +01:00
ryantig
697fb999b4 Minor installation.md edit; gpasswd cmd
Add '-a' after gpasswd to add USER to group plugdev.
Per: ➜ gpasswd --help
Usage: gpasswd [option] GROUP

Options:
  -a, --add USER                add USER to GROUP
  -d, --delete USER             remove USER from GROUP
  -h, --help                    display this help message and exit
  -Q, --root CHROOT_DIR         directory to chroot into
  -r, --remove-password         remove the GROUP's password
  -R, --restrict                restrict access to GROUP to its members
  -M, --members USER,...        set the list of members of GROUP
  -A, --administrators ADMIN,...
                                set the list of administrators for GROUP
Except for the -A and -M options, the options cannot be combined.
2017-09-26 09:23:35 -07:00
Josenivaldo Benito Jr
aeb943fc9e Descriptor for K270 and M185
This K270 is the non unifying version and we know that it has, at
least, one variation (unifying) out there.

M185 mouse is also older, as per PR #337 there is at least two newer
versions of this mouse.

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2017-09-25 14:57:11 -03:00
Josenivaldo Benito Jr
434af009cb Information regarding MK270 combo
This combo is composed by K270 keyboard (non unifying version) and M185
mouse. Both paired to a nano receiver with PID c534.

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2017-09-25 14:55:47 -03:00
Peter Wu
cc010cb653 Merge pull request #385 from mchehab/pt-br-translation
Update pt_BR translation
2017-09-21 01:52:22 +01:00
Mauro Carvalho Chehab
e450e959a6 Update pt_BR translation
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2017-09-20 21:48:08 -03:00
Peter Wu
10f3421021 Merge pull request #345 from jrbenito/M510_v4.5
Add M510 (new version) to descriptors
2017-09-21 00:30:31 +01:00
Peter Wu
8eba60d617 Merge pull request #360 from lasers/remove-dead-links
Remove dead links
2017-09-21 00:25:11 +01:00
Peter Wu
e3d658ea10 Merge pull request #351 from mchehab/mx_anywhere2-v5
Mx anywhere2 v5
2017-09-21 00:16:15 +01:00
Peter Wu
ef1c051e10 Merge pull request #383 from skarmoutsosv/skarmoutsosv-patch-1
Update el.po
2017-09-21 00:11:04 +01:00
Peter Wu
bc566718b4 Merge pull request #384 from michal2229/master
Updated Polish translation
2017-09-21 00:09:05 +01:00
Michal B
22719f21fc Updated Polish translation 2017-09-19 20:00:43 +02:00
Vangelis Skarmoutsos
c51daa922c Update el.po 2017-09-11 21:02:14 +03:00
Mauro Carvalho Chehab
632d8804be listener: don't add elements if queue is full
When Solaar is loaded, if a large number of events happen,
it will lose the register events, as the queue size is too
small (16). So, check if the queue is full, in order to
avoid losing those important events.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2017-09-11 10:36:12 -03:00
Mauro Carvalho Chehab
a4b7194490 listener: fix device registration logic
The "already_known" var actually doesn't track if the device was
already registered or not.

That causes race issues at Solaar, causing it to sometimes not
detect a device.

Change the logic to always call register_new_device if the
corresponding events happen, and updating already_known
to reflect it.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2017-09-11 10:34:23 -03:00
Mauro Carvalho Chehab
ea80c6d639 ui: notify.py: disable python Notify extension
For whatever reason, this doesn't work on Fedora 26:

06:47:05,925    DEBUG [ReceiverListener:hidraw1] logitech_receiver.base: (13) => r[20 02 0100 0000000000000000000000]
06:47:05,925    DEBUG [ReceiverListener:hidraw1] logitech_receiver.notifications: <PairedDevice(2,2011,K520)> (1.0) custom notification Notification(2,01,00,000000000$
06:47:05,925  WARNING [ReceiverListener:hidraw1] logitech_receiver.notifications: <PairedDevice(2,2011,K520)>: unrecognized Notification(2,01,00,000000000000000000000$
06:47:08,806    ERROR [MainThread] solaar.ui.notify: showing <Notify.Notification object at 0x7f82c2484640 (NotifyNotification at 0x556fa0fc5a40)>
Traceback (most recent call last):
  File "./devel/solaar/lib/solaar/ui/notify.py", line 145, in show
    n.show()
Error: g-io-error-quark: Error calling StartServiceByName for org.freedesktop.Notifications: Timeout was reached (24)


So, disable it.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2017-09-11 07:02:48 -03:00
Mauro Carvalho Chehab
a01e4b2efe hidpp20.py: handle gracefully errors at REPROG_CONTROLS_V4
At least with Anywhere Mouse MX 2, one reprogrammed key
fails to read:

    ERROR [MainThread] logitech_receiver.base: (3) device 3 error on feature request {0829}: 2 = invalid argument

That causes "solaar show" to crash.  Instead, let's handle
errors there gracefully, reporting it as:

         7: unknown:00C3              , default: unknown:009C                => unknown:00C3
             virtual, pos:0, group:4, gmask:0

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2017-09-10 22:53:19 -03:00
Mauro Carvalho Chehab
801bdfa224 Remove the hid++ high-res wheel notification
The best is to make the logitech-hidpp driver to switch to
hid++ notification mode when it starts. As we don't want users
to mangle with it, let's remove support from it.

PS.: I opted to keep this as a separate patch. This way, if
anyone needs to add support for it, in order to debug the
driver, it is just a matter of reverting this patch.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2017-09-10 21:49:18 -03:00
Mauro Carvalho Chehab
410d100dc6 Add notification for high-resolution Wheel events
The event at address 0 is only produced while in HID++ mode.

The rachet event (address 0x10) happens on both HID and
HID++ modes.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2017-09-10 21:49:18 -03:00
Mauro Carvalho Chehab
7078750a3f MX Anywhere2: Correct feature Smooth Scrool
Set wrongly to HI_RES_SCROLLING. Correct it to HIRES_WHEEL as reported
by MX Anywhere2.

relates to #283

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2017-09-10 21:49:18 -03:00
Mauro Carvalho Chehab
360c92f6b0 Add support for CLI show to display High Res Wheel settings
Add support for the high resolution wheel found on MX Anywhere 2.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2017-09-10 21:44:30 -03:00
lasers
2377fef3a8 Remove dead links 2017-07-24 03:44:00 -05:00
Peter Wu
684afa871e Merge pull request #337 from doctor64/m185
Basic support for M185 mouse
2017-07-17 00:08:19 +02:00
Peter Wu
dd2f884504 Merge pull request #354 from luzfcb/patch-1
update ubuntu solaar package informations
2017-04-16 12:20:27 +02:00
Fábio C. Barrionuevo da Luz
9dd05bb727 update ubuntu solaar package informations 2017-04-10 21:26:23 -03:00
Alex Cherkayev
e96a0fbfbb Add docs on both variants of Logitech M185 2017-03-21 18:03:07 +02:00
Alex Cherkayev
f9618dd0ab Add M185 keys reporting using REPROG CONTROLS V4 in cli
Add smooth scrolling using LOWRES_WHEEL
Add mouse speed selection using POINTER_SPEED
2017-03-21 18:02:59 +02:00
Alex Cherkayev
db0656967b Add basic 0xc534 receiver and M185 mouse support
Fix connection notification protocol for M185
Fixes from review
2017-03-21 18:00:44 +02:00
Peter Wu
53ec751cf1 Merge pull request #343 from jrbenito/K270-unifying
Wireless Keyboard K270 unifying
2017-03-21 00:07:26 +01:00
Peter Wu
45cc161cc7 Merge pull request #344 from jrbenito/MK520
MK520 Combo - Documentation
2017-03-21 00:02:52 +01:00
Peter Wu
1ccd2d1856 Merge pull request #346 from jrbenito/MK220-mouse
MK220 Combo descriptor for Mouse M150 and new docs
2017-03-20 23:58:49 +01:00
Josenivaldo Benito Jr
d9d37edc2f MK220 Combo descriptor for Mouse M150 and new docs
Thanks to @FabioBeneditto for providing information.

Depends on #337

fixes #222

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2017-03-10 10:47:23 -03:00
Josenivaldo Benito Jr
ae405871fb Add M510 (new version) to descriptors
Depends on #337

fixes #279

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2017-03-08 19:48:23 -03:00
Josenivaldo Benito Jr
f4700f07ce MK520 Combo
Wireless Keyboard K520
Wireless Mouse M310

Fully functional on Solaar at this point.

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2017-03-08 18:59:36 -03:00
Josenivaldo Benito Jr
d2d19a615d Wireless Keyboard K270 unifying
Descriptor and docs for K270 unifying version.

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2017-03-08 16:23:30 -03:00
Peter Wu
c36cc506b6 Merge pull request #327 from david-geiger/master
Update French translation
2017-01-03 12:27:22 +01:00
daviddavid
7180693f89 Update French translation
- by David Geiger <david.david@mageialinux-online.org>
2016-12-31 16:43:44 +01:00
Peter Wu
aa08356823 Merge pull request #144 from DJm00n/master
Russian translation added.
2016-12-23 15:16:06 +01:00
Dimitriy Ryazantcev
197ff7365d Add Russian translation 2016-12-21 00:18:01 +02:00
Dimitriy Ryazantcev
a0c6a6ce59 Update l10n pot template 2016-12-21 00:18:01 +02:00
Dimitriy Ryazantcev
934ecb821d Update l10n strings in code 2016-12-21 00:18:01 +02:00
Peter Wu
f0cf949336 Merge pull request #322 from jrbenito/anywhere2
Anywhere MX 2 device information and descriptor
2016-12-20 21:29:10 +01:00
Peter Wu
ecd245e8dc Merge pull request #317 from jrbenito/m560-devinfo
M560 device info contributed by @mhalano
2016-12-03 02:19:04 +01:00
Peter Wu
f65f000d38 Merge pull request #319 from jrbenito/k780
K780 add descriptor support and device information
2016-12-03 02:03:35 +01:00
Josenivaldo Benito Jr
3b60f205f7 K780 add descriptor support and device information
Device information provided by @faassen
Tests provided by @ralphdd

relates to #298

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2016-11-30 14:38:44 -02:00
Josenivaldo Benito Jr
d6c93cfcfe Anywhere MX 2 device information and descriptor
Information from mouse Anywhere MX 2 as provided by @fropeter
Descriptor for mouse based on dump provided

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2016-11-30 14:24:50 -02:00
Josenivaldo Benito Jr
cbd71f9d24 M510 HID++ V4.5 information
Dump from M510, newer version which uses HID++ V4.5 instead of V1.0.
Wireless PID 4051

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2016-11-30 14:07:42 -02:00
Josenivaldo Benito Jr
45d5119a5a M560 device info contributed by @mhalano
Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2016-11-30 14:07:27 -02:00
Peter Wu
773cb7f45f Merge pull request #312 from jrbenito/rules
Add receiver to udev rules
2016-11-29 02:16:36 +01:00
Josenivaldo Benito Jr
d74e3a9b92 Add receivers to udev rules
Sync lib/logitech_receiver/base_usb.py PIDs with udev rules

Fixes #125

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2016-11-24 09:54:24 -02:00
Peter Wu
fe1fba7ac6 Merge pull request #316 from david-geiger/master
Add French translation on desktop file and update maintainer in README.
2016-11-24 11:09:46 +01:00
daviddavid
4e20ef61c8 Add French translation on desktop file
- update README.md
2016-11-23 20:38:30 +01:00
Peter Wu
a750b32d14 Merge pull request #313 from jrbenito/doc
Update installation to point correct rules file
2016-11-23 13:46:27 +01:00
Josenivaldo Benito Jr
69006c48c6 Update installation to point correct rules file
Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2016-11-23 09:55:07 -02:00
Peter Wu
b12d03dfe3 Merge pull request #311 from jrbenito/nanoDocs
README nano receiver broken link
2016-11-22 23:46:00 +01:00
Peter Wu
ddbf93fb24 Merge pull request #309 from jrbenito/pt-br
pt-br: Improve translations
2016-11-22 23:22:23 +01:00
Josenivaldo Benito Jr
65c55b789c README nano receiver broken link
Fixes #261

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2016-11-22 11:37:40 -02:00
Josenivaldo Benito Jr
d83530bee3 pt-br: Improve translations
Some pt-br translation where ambiguous or too missing 'not' statement.
Add original translator, Mr. Drovetto, to the documentation.

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2016-11-21 17:25:22 -02:00
Peter Wu
e6c02f5c52 Merge pull request #303 from jrbenito/UTF8
UTF-8 file paths error on python 2
2016-11-18 22:22:11 +01:00
Josenivaldo Benito Jr
122d76d061 UTF-8 file paths error on python 2
Python 2 needs UTF-8 decode since it uses 'ascii' decode by default.
Python 3 might have problems converting back to UTF-8 in case of Unicode
surrogates

Signed-off-by: Josenivaldo Benito Jr <jrbenito@benito.qsl.br>
2016-11-18 15:00:20 -02:00
muzena
fb1442dbcb Add croatian translation 2016-11-15 16:34:20 +01:00
muzena
0b8141f092 Logitech G700 and G700s Gaming mouse support 2016-11-14 16:39:23 +01:00
Peter Wu
137c32262b Merge pull request #242 from drovetto/master
Added brazilian portuguese translation
2016-11-10 13:20:25 +01:00
Peter Wu
7c726738b1 Merge pull request #185 from zipperten/patch-4
Update sv.po
2016-11-10 13:19:35 +01:00
Peter Wu
2570f584b9 Merge pull request #228 from berte/master
add turkish translation file
2016-11-10 13:07:29 +01:00
Peter Wu
4c1f568fab Merge pull request #141 from ghost
Italian translations
2016-11-10 13:04:42 +01:00
Peter Wu
27bd71253e Merge pull request #129 from Tomin1/finnish
Finnish translations
2016-11-10 12:57:06 +01:00
Jhonny Oliveira
9a9a82016f Add support to G700 Gaming Mouse receiver 2016-11-10 12:25:54 +01:00
Jhonny Oliveira
aa03cef61f Add support to MK320 mouse and keyboard combo 2016-11-08 09:17:02 +01:00
Peter Wu
c14e30b6f5 Fix crash when AppIndicator3 is unavailable
Convert ValueError to an ImportError (hack!) to allow the fallback code
to function.

Fixes https://github.com/pwr/Solaar/pull/276
2016-11-06 19:50:32 +01:00
cschreib
b5d43cdc3c Added support for MintX icon set (for Linux Mint integration) 2016-10-22 13:49:50 +02:00
Peter Wu
1edd8a577b Merge pull request #290 from verybadsoldier/invert-online-bit
Fixes #289.
2016-10-03 01:58:51 +02:00
vbs
358e0958bb fixed wrong interpretation of bit 6 of the notification byte which indicates if the link could be established (bit cleared) or not (bit set)
https://lekensteyn.nl/files/logitech/logitech_hidpp10_specification_for_Unifying_Receivers.pdf
2016-09-17 18:05:03 +02:00
Peter Wu
fa5fba796b Merge pull request #263 from MagicFab/patch-1
Update es.po
2016-09-04 22:02:38 +02:00
Peter Wu
ce215228f3 Merge pull request #277 from wsargent/patch-1
Use HTTPS for github based repositories
2016-08-09 15:02:03 +02:00
Peter Wu
28e43395ab Merge pull request #259 from javitonino/support-mx-master
Support mx master
2016-07-24 23:09:28 +02:00
Will Sargent
e09231c05a Use HTTPS for github based repositories
Github Pages support HTTPS natively, so it's better for security to default to that.
2016-07-12 09:02:28 -07:00
Javier Torres
f29de0f3dd Update docs: mx master supports smart shift 2016-06-09 19:46:03 +02:00
Javier Torres
ba540338e2 Add smart shift feature for MX master 2016-06-09 19:46:03 +02:00
Javier Torres
2442fee341 Add support for range features in GUI 2016-06-09 19:46:03 +02:00
Javier Torres
bbadd3e755 Add support for range features in CLI 2016-06-09 19:46:03 +02:00
Javier Torres
2fdce2f938 Add range features 2016-06-09 19:46:03 +02:00
Javier Torres
f1fad2d16b Add range validator 2016-06-09 19:46:03 +02:00
Peter Wu
8a5700b44e Merge pull request #270 from cjmayo/appindicator
Fix: "AppIndicator3 was imported without specifying a version first"
2016-05-21 19:28:19 +02:00
Chris Mayo
e046455a05 Fix: "AppIndicator3 was imported without specifying a version first"
PyGIWarning: AppIndicator3 was imported without specifying a version
first. Use gi.require_version('AppIndicator3', '0.1') before import to
ensure that the right version gets loaded.
2016-05-03 20:20:46 +01:00
Peter Wu
ddbc27486c Merge pull request #136 from erik-smit/gobject_not_allow_None
Fixes a TypeError on older GObject libraries (as evident with Ubuntu 12.04 and OpenSUSE 12.3).
2016-04-17 14:11:15 +02:00
Peter Wu
2041007b38 Merge branch 'features'
Automatically detect FN swap feature and DPI adjustment on some newer
devices. DPI adjustment partially addresses support for the MX Master
(#208), Smart shift is still missing.
2016-04-17 12:43:15 +02:00
Fabian Rodriguez
7b7e17819e Fixed "Hardware" following comments 2016-04-01 07:55:13 -04:00
Fabian Rodriguez
f855cd60e1 Update es.po
MIssing spaces, small terms corrections, typos
2016-03-31 19:22:55 -04:00
Peter Wu
883ed9549d Fix DPI list assertion 2016-03-25 00:06:00 +01:00
Peter Wu
d1858f747b Assume 7 words for the DPI list response
HID++ 2.0 responses are 20 bytes, once you strip the 4 byte common
header and 1 byte sensorIdx, you have 15 bytes left. Since DPI values
are 16-bit words, only 14 bytes should be used.
2016-03-24 16:59:05 +01:00
Peter Wu
aa7d1b6410 Skip sensorIdx in getSensorDpiList response 2016-03-24 15:13:06 +01:00
Peter Wu
bc3a98ddb2 Merge pull request #258 from cjmayo/gentoo
readme Gentoo link updated with official package
2016-03-24 14:58:34 +01:00
Peter Wu
5b01f375e0 Merge pull request #254 from emerham/master
Adding Logitech mx 1100 cordless laser mouse to discriptors
2016-03-24 14:56:55 +01:00
Peter Wu
dd2755909d cli/config: fix error message
Attempt to fix:

    $ bin/solaar config master dpi higher
    solaar: error: coercing to Unicode: need string or buffer, int found

The DPI choices are integers, therefore cast it to a str.
2016-03-18 12:27:16 +01:00
Peter Wu
b052ab9ef0 Fix thinko in Adjustable DPI setting
There are three bytes forming the parameter, the sensor ID is the MSB,
not LSB.
2016-03-18 12:14:15 +01:00
Peter Wu
9c768d60a1 Add full support for adjustable DPI
Feature 0x2201 as used by the MX Master. Valid DPI values are read
directly from the device. Based on Logitech specifications.
2016-03-15 23:37:39 +01:00
Matthew Brabham
d1d0ab85ff Updated mouse device settings and deffinition. Added docs for the MX 1100 2016-03-14 13:05:05 -07:00
Peter Wu
e1eee2e078 Fix "Gtk was imported without specifying a version first"
Fixes the following warnings:

    sys:1: PyGIWarning: Gtk was imported without specifying a version first. Use gi.require_version('Gtk', '3.0') before import to ensure that the right version gets loaded.
    sys:1: PyGIWarning: Notify was imported without specifying a version first. Use gi.require_version('Notify', '0.7') before import to ensure that the right version gets loaded.
2016-03-14 11:33:05 +01:00
Peter Wu
5c38f90cd6 Merge branch 'issue/199'
Fixes #136.
2016-03-14 11:10:49 +01:00
Peter Wu
45d49b9de8 settings: fix Python 3 compat for boolean values
As observed for the fn-swap setting.
2016-03-14 01:48:56 +01:00
Peter Wu
4ccb8ab26d Merge pull request #257 from hobarrera/subtle-critical-battery-notification
Don't open a main window when battery is critical
2016-03-14 00:36:26 +01:00
Peter Wu
ab162583e4 cli: do not die on missing description
The DPI setting has no description, do not try to display it.
2016-03-13 23:59:21 +01:00
Chris Mayo
e25b47aa1c readme Gentoo link updated with official package 2016-03-05 16:27:16 +00:00
Hugo Osvaldo Barrera
63a98819a6 Don't open a main window when battery is critical
The main window suddenly opening when a battery is critical is very
disruptive. It can pop up on all sort of undesirable scenarios.

Rather than catch users of guard, merely show a notification that the
battery is critical.
2016-02-19 03:25:55 -03:00
Peter Wu
27d3d80d30 Merge pull request #256 from SlySven/add_m175DestinguishingDetails
add: wpid for M175 to distinguish between it and M185 wireless mouse (Fixes #255)
2016-02-11 18:30:02 +01:00
Stephen Lyons
478381a994 add: wpid for M 175 to distinguish between it and M185 wireless mouse
I own the former and wanted to correct this detail which caused the wrong
model to be shown in GUI.

Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2016-02-10 19:09:25 +00:00
Matthew Brabham
51a15a960f Adding Logitech mx 1100 cordless laser mouse to discriptors 2016-01-26 11:04:47 -08:00
Peter Wu
92967eed23 Merge pull request #249 from mulkieran/master-pyudev
Fix some bugs in udev.get_indexed_string.
2016-01-13 15:24:51 +01:00
Peter Wu
57338303e8 Merge pull request #239 from marcbelmont/patch-1
Add setting for K400 Plus keyboard

devices.md was updated in #174
2016-01-09 12:37:35 +01:00
Peter Wu
e735ce10f0 Merge pull request #174 from IrvinPoe/patch-1
Update devices.md with K400 Touch
2016-01-09 12:36:27 +01:00
mulhern
d75b6d2f2b Fix some bugs in udev.get_indexed_string.
* from_device_number raises an exception if no device found, rather than
returning None. So, instead of checking the result, catch the exception.
* Use Attributes.get() method instead of checking containment and using the
index operator. This is really the only correct way, see rhbz#1267584.

Effect of the changes:
Previously, if no device was found this method would raise an exception.
Now it returns None instead.
Previously this method read the value of the attribute corresponding to key
twice, once via 'key in attributes' and again when accessing the key.
Now, it just reads it the one time.

Reason for noticing all these problems:
In pyudev-0.18 the Attributes class is fixed, and no longer has the []
operator or __contains__ method or other methods which require a total
mapping. This patch fixes several bugs while simultaneously avoiding these
removed operators.

Signed-off-by: mulhern <amulhern@redhat.com>
2015-12-23 09:22:48 -05:00
sadj
bd1470dad7 Added brazilian portuguese translation. 2015-10-08 18:52:14 -03:00
Marc Belmont
15f97681ef Add setting for K400 Plus keyboard
The new_fn_swap works on the K400 Plus model.
2015-08-24 19:01:21 +02:00
Behzat
7075ce910a add turkish translation file 2015-07-16 22:07:38 +03:00
Peter Wu
5ba816dd38 [WIP] Support MX Master with DPI adjustment support (#208)
It's not known whether the DPI ranges can be queried, so let's set
hard-code some values for now. Step size is 200. Does this need to
be changed?

TODO: need a capture of whether this is really a read function.
2015-05-31 15:53:26 +02:00
Peter Wu
a515cc3860 Auto-detect FN swap feature for newer devices 2015-05-31 10:56:57 +02:00
Peter Wu
73344cbf26 Simplify feature checking
Make mapping features to settings more readable. No functional changes.
2015-05-31 10:38:49 +02:00
Peter Wu
cf27328d13 Merge branch 'updates'
Documentation updates.
2015-05-27 23:43:10 +02:00
Peter Wu
869f1e4791 doc/devices.md: add MX Master
Information from (IRC) xaver. See also #208.

Product page at http://www.logitech.com/product/mx-master
2015-05-27 23:40:58 +02:00
Peter Wu
e2d65a690e hidpp20: update features list
Based on SetPoint6.65.62_32.exe and Options_2.10.73.exe (features.xml,
defaults.xml, LogiOptionsMgr.exe).

The names are based on the named next to the feature ID. For duplicates,
_2 is appended to the name.

This commands helps parsing numbers from debug prints:

    strings LogiOptionsMgr.exe |
    sed -nr 's/.*(Feature[0-9a-fA-F]{4})/\1 /p' | sort |
    awk 'tolower(a)!=tolower($1){print"";a=$1}1;' | less -S
2015-05-27 23:20:43 +02:00
Peter Wu
3141f06472 Fix crash due to non-locatable icon names (#199) 2015-05-27 23:16:39 +02:00
Peter Wu
b88cf5a07b Ignore HID++ devices on Linux 3.19+
Additionally update the docuentation to reflect new module names.
2015-05-14 23:28:04 +02:00
Peter Wu
a344ad9867 docs: document Smooth Scrolling for more devices
Based on the HI_RES_SCROLLING feature (0x2120) in docs/devices/. Tested
with a M525.
2015-05-14 23:06:14 +02:00
CzBiX
76e327d2fa update docs for M325 2015-05-08 13:27:29 +08:00
CzBiX
0ae0ef195a support switch smooth scroll feature 2015-05-08 13:20:46 +08:00
Peter Wu
b1f74a1280 Merge pull request #213 from titanofold/add-M570
Add M570 Trackball device information
2015-04-24 09:39:37 +02:00
Aaron W. Swenson
30431fbfb8 Add M570 Trackball detail 2015-04-20 14:18:07 -04:00
Peter Wu
fb4c055fbf Merge pull request #193 from dmsc/master
Add support for MK220 mouse-keyboard combo device.
2015-03-07 18:12:21 +01:00
Daniel Serpell
3ea51fe1a2 Add support for MK220 mouse-keyboard combo device.
The MK220 receiver has usbid 046d:c52e, adding this id as a generic
receiver is enough to show the mouse and keyboard charge status.
2015-03-06 08:07:22 -03:00
Peter Wu
afd36764c2 Merge pull request #202 from decibyte/master
k830 support + support for NEW FN INVERSION
2015-03-06 11:45:53 +01:00
Mikkel Munch Mortensen
b694809394 Updates to dos for k830 keyboard. 2015-03-05 19:17:00 +01:00
Mikkel Munch Mortensen
66296265ba Descriptor for k830. 2015-03-05 19:15:12 +01:00
Mikkel Munch Mortensen
952495ce04 Support for NEW_FN_INVERSION. 2015-03-05 19:14:28 +01:00
Peter Wu
29eb377267 Merge pull request #203 from HugoJH/master
Added Spanish Translation
2015-03-05 15:04:45 +01:00
Hugo Jiménez Hernández
47345e1dcb Added Spanish Translation 2015-03-05 13:05:59 +00:00
Peter Wu
36fc6de760 Merge pull request #168 from jtsagata/master
Add Greek language translation
2015-03-05 13:07:25 +01:00
Peter Wu
6c0aca8c63 Merge pull request #170 from SubOptimal/translation
add german translation
2015-03-05 13:06:52 +01:00
Peter Wu
bd93689109 Merge pull request #171 from dirtycold/master
added Chinese (simplified) translation
2015-03-05 13:06:08 +01:00
Peter Wu
4e5d4853d6 Merge pull request #173 from stickster/master
Add Fedora package information to README.md
2015-03-05 13:05:37 +01:00
zipperten
bb2361a986 Update sv.po
minor changes
2014-10-23 09:49:05 +02:00
IrvinPoe
7c8d4815f0 Update devices.md
Add Nano receiver 046d:c52b in the supported devices, and FN swap works on K400.
2014-08-17 17:47:48 +02:00
Paul W. Frields
0f05589cd6 Add Fedora package information to README.md 2014-07-30 14:39:46 -04:00
ZH
21db60a14e fix compiling Chinese simplified translation 2014-07-13 15:13:10 +08:00
ZH
091c28ca8b added Chinese (simplified) translation 2014-07-13 10:13:17 +08:00
Frank Dietrich
9af353dd32 add german translation 2014-07-02 02:12:16 +02:00
Giannis Tsagatakis
981ff00ca3 Add Greek language translation 2014-06-13 14:32:57 +03:00
Daniel Pavel
ec0197df3d Merge pull request #154 from mmehnert/patch-1
Update TK820 compatibility information
2014-04-20 22:54:27 +03:00
mmehnert
2111107ff4 Update TK820 compatibility information 2014-04-19 14:50:21 +02:00
Tristin Celestin
2b08c5e0c9 Added border around tree view. 2014-01-01 21:45:44 -05:00
Daniel Pavel
cc8a6c4ab5 Merge pull request #134 from FrederikNS/patch-1
Added Smooth Scrolling to the Performance Mouse MX
2013-12-13 09:43:16 -08:00
Michele Olivo
437e17cf37 Added Italian translation 2013-12-13 18:09:46 +01:00
Daniel Pavel
22191d7d0c Merge pull request #139 from parkerlreed/patch-1
Update devices.md
2013-12-13 07:48:21 -08:00
parkerlreed
ba890c2d2e Update devices.md
Added a little bit of info for the M325
2013-12-02 10:46:47 -05:00
erik-smit
9a6cdd9cee TypeError: Argument 3 does not allow None as a value 2013-10-31 11:16:38 +01:00
Frederik Nordahl Sabroe
32324f3e66 Added Smooth Scrolling to the Performance Mouse MX
I tested solaar with my Performance Mouse MX, and the smooth scrolling worked like a charm, I just need to find a way to make the scrolling speed slower now.
System is Linux Mint 15.
2013-10-14 17:18:49 +02:00
Tomi Leppänen
ffe297b239 Merge branch 'finnish' of github.com:Tomin1/Solaar into finnish
Conflicts:
	po/fi.po
	po/solaar.pot
2013-09-29 16:37:33 +03:00
Tomi Leppänen
7fe5983f7c Fixed a bit Finnish translation.
Some fixes to Finnish translation.
A few strings were marked as fuzzy.
Run po-compile.sh.
2013-09-29 16:34:02 +03:00
Tomi Leppänen
d5f14bb5f8 Merge branch 'master' into finnish
Conflicts:
	po/solaar.pot - run po-compile.sh
2013-09-29 16:24:06 +03:00
Daniel Pavel
f3049ed451 Merge pull request #126 from slaveriq/master
Fixing a crash when level is type None
2013-09-25 10:08:09 -07:00
David Plassmann
8485494ea7 It should check for None specificly 2013-09-25 14:12:53 +02:00
David Plassmann
7a75813a84 level is returned as None in hidpp10.py when the performanceMX mouse is
charging. Since the battery state is unknown when beeing recharged it
will now return "N/A".
Before it would crash becasue level was None and could not be inserted
using %d.
2013-09-24 16:56:50 +02:00
Daniel Pavel
35830e3d50 Merge pull request #121 from Lekensteyn/doc-updates
Documentation updates: DJ pdf and devices
2013-09-04 16:56:46 -07:00
Tomi Leppänen
46fd4dac56 Merge branch 'master' into finnish
Conflicts:
	po/solaar.pot - Run tools/po-compile.sh
2013-09-01 12:21:51 +03:00
Peter Wu
ebd8635f84 docs/devices: add K750 (from Julien Danjou)
Received from Julien Danjou on the devkit mailing list.
2013-08-29 19:06:03 +02:00
Peter Wu
efbf43b472 docs/logitech: Add DJ receiver spec
docx files is taken from hidpp20 public folder[1] and was converted to
PDF format using:

    loffice --convert-to pdf ...docx
    qpdf --linearize orig.pdf ...pdf

Mirrored on https://lekensteyn.nl/files/logitech/.

 [1]: https://drive.google.com/#folders/0BxbRzx7vEV7eWmgwazJ3NUFfQ28
2013-08-27 18:06:29 +02:00
Peter Wu
8a6d8e2ed1 docs/devices/m525: add ltunify and solaar output 2013-08-27 18:06:29 +02:00
Peter Wu
bff99799ab docs/devices/t650: add reprogrammable keys 2013-08-27 18:06:29 +02:00
Peter Wu
1434b2a50d Update features and keys list
Updated to information available from SetPoint 6.61.15.
2013-08-27 17:55:45 +02:00
Daniel Pavel
c3fdbfb643 translate battery alerts (fixes #119) 2013-08-25 23:03:25 +03:00
Daniel Pavel
a9ebac264f po formatting updates 2013-08-25 01:34:27 +03:00
Daniel Pavel
60a591ab6b Merge pull request #114 from zipperten/patch-2
Update sv.po
2013-08-24 15:32:23 -07:00
Daniel Pavel
ab3a6b50d4 Merge pull request #118 from Lekensteyn/fixes
Regression fixes: --hidraw option, python3, hidpp10
2013-08-24 14:05:11 -07:00
Peter Wu
b193b39701 Fix missing reprogrammable keys
The assumption that the Features IDs are in increasing order does not
hold. This causes the feature check for REPROG CONTROLS (1B00) to fail,
therefore remove the micro-optimisation.

While at it, rename variables and document the functions better.
2013-08-23 21:33:45 +02:00
Daniel Pavel
806d67a72f Merge pull request #117 from Lekensteyn/doc-updates
docs: added T400, T650, Anywhere MX dumps
2013-08-21 13:12:23 -07:00
Peter Wu
9c465cd998 Fix wrong register name for illumination (hidpp10)
Broken since 9a2a28e, this causes a lot of exceptions for every move.
2013-08-21 21:47:24 +02:00
Peter Wu
024a71b618 solaar: add --hidraw option again
This options allows the devices list to be restricted which got removed
in:

    commit 3b75b69970
    Author: Daniel Pavel <daniel.pavel@gmail.com>
    Date:   Fri Aug 9 12:25:47 2013 +0200

        merged solaar-cli functionality into main solaar binary

solaar-cli is still busted, but since it is deprecated, it's probably
fine.
2013-08-21 21:47:24 +02:00
Peter Wu
f144816256 solaar-cli: fix argument parsing in Python 3 again
Fix from e3a887f36c, this got removed
in:

    commit 3b75b69970
    Author: Daniel Pavel <daniel.pavel@gmail.com>
    Date:   Fri Aug 9 12:25:47 2013 +0200

        merged solaar-cli functionality into main solaar binary
2013-08-21 21:47:24 +02:00
Peter Wu
f0eeea8625 docs/devicesmd: update with T400 and Anywhere MX 2013-08-21 21:45:04 +02:00
Peter Wu
72819b6130 docs/devices: add Anywhere MX mouse
Thanks to Nestor from Logitech for providing me this device.

This mouse has two buttons on the left, currently mapped to 8 (bottom
button) and 9 (top button).

Note: setting bit 1 of register 01 does odd things in KDE. I looked in
SetPoint 6.61.15 and could not find an option for "Side Scroll",
perhaps it is not applicable here?
2013-08-21 21:45:04 +02:00
Peter Wu
23e4f32e11 docs/devices: add T650 touchpad
Thanks to Nestor from Logitech for providing me this device.

The firmware on this touchpad features out-of-the-box tap-to-click
(no host software needed). The following features work with no
additional software (tested in Linux 3.11-rc6 with KDE 4.11):

- Left-click: single tap
- Middle-click ("scroll-wheel click"): three finger tap
- Right-click ("context menu"): two finger tap or tap in right corner
- Navigate left ("Back"): three finger slide to left
- Navigate right ("Forward"): three finger swipe to the right
- Scroll (up/down/right/left): slide with two fingers
- Move pointer (any direction): slide

Click and drag is also possible (for example, for selecting text or
moving windows with Super + right/left-click in KDE), just press harder
on the surface. Right click is in the bottom-right corner, left is
anywhere else.

Sliding with three fingers up acts if you pressed Super. Sliding with
three fingers down triggers a key press of Super + D (normally the
"Show Desktop" in MSWIN).

Not working as it requires additional software:

- Pinch-to-zoom.
- Four-finger gestures, likely needs to be controlled via features as
  there are no HID messages at all.
2013-08-21 21:45:04 +02:00
Peter Wu
243d1548dc docs/devices: add Zone Touch Mouse T400
Thanks to Nestor from Logitech for providing me this device.

User experience note: the upper part (covering two-third) of the middle
button is the "METRO START SCREEN" button, the smaller bottom part
provides the "middle mouse button" (MIDLLE BUTTON). This might be OK
for a desktop user, but it's awful if you have a big hand like me and
make much use of it for opening URLs in a new tab or pasting stuff.

On the other hand, the middle button can be remapped and there is both
horizontal and vertical scrolling functionality.
2013-08-21 21:45:04 +02:00
zipperten
c3bc56f306 Update sv.po
fix for paring lock notification.
2013-08-20 22:49:08 +02:00
Daniel Pavel
288c607069 Merge pull request #113 from david-geiger/patch-1
Ouch. Added 'solaar.cli' on setup.py files (line 74 "packages=").
2013-08-13 02:20:58 -07:00
david_david
55c307d0e5 added 'solaar.cli' on setup.py files (line 74 "packages=")
missing packages 'cli' from "/lib/solaar/" and needed for building package rpm.

[david@david ~]$ solaar -dd
Traceback (most recent call last):
  File "/usr/bin/solaar", line 43, in <module>
    import solaar.gtk
  File "/usr/lib/python2.7/site-packages/solaar/gtk.py", line 26, in <module>
    import solaar.cli as _cli
ImportError: No module named cli
2013-08-13 11:02:13 +02:00
Daniel Pavel
69febfcea5 don't rely on upower to check devices after wake-up (#111)
still use upower resume events to ping devices, just in case
the old behaviour is available with a command-line option
2013-08-12 15:22:34 +02:00
Daniel Pavel
9934755566 more translation fixes (#108) 2013-08-12 00:32:19 +02:00
Tomi Leppänen
a7561eaa9b Updated Finnish translation
Merge branch 'finnish' of github.com:Tomin1/Solaar into finnish

Conflicts:
	po/fi.po
2013-08-11 17:24:06 +03:00
Tomi Leppänen
689661169a Updated Finnish translation. 2013-08-11 17:22:40 +03:00
Tomi Leppänen
eac40abc3e Updated Finnish translation. 2013-08-11 16:56:30 +03:00
Tomi Leppänen
372e4e0949 Merge branch 'master' into finnish
Conflicts:
	po/solaar.pot - run tools/po-compile.sh
2013-08-11 16:48:12 +03:00
Daniel Pavel
e42f7f1393 jekyll configuration update 2013-08-09 12:29:02 +02:00
Daniel Pavel
3860d4a56b changelog update 2013-08-09 12:28:47 +02:00
Daniel Pavel
3b75b69970 merged solaar-cli functionality into main solaar binary 2013-08-09 12:25:47 +02:00
Daniel Pavel
a4f0eab855 updated descriptors with a few more devices 2013-08-08 22:44:23 +02:00
Daniel Pavel
f54ea27d97 updated translator credits in about dialog 2013-08-08 22:43:32 +02:00
Daniel Pavel
db48fe1b40 re-formatted translation files 2013-08-08 22:41:57 +02:00
Daniel Pavel
d0a0e902a7 added translator credits to i18n documentation 2013-08-08 22:38:59 +02:00
Daniel Pavel
95a6412d5c po-update.sh without arguments re-formats all translation files 2013-08-08 22:22:39 +02:00
Daniel Pavel
5faecbf4f3 some strings were untranslated; fixes #100 2013-08-08 21:50:04 +02:00
Daniel Pavel
5af1719384 tray: always pick the lowest battery, if the user hasn't already 2013-08-08 21:49:59 +02:00
Daniel Pavel
6a66370ffe scrolling over the tray icon switches among devices; fixes #101
It now works for the standard systray as well, not just the
appindicator.
2013-08-08 21:49:54 +02:00
Daniel Pavel
c0874220d2 don't str() translated device status; fixes #108 2013-08-08 21:49:50 +02:00
Daniel Pavel
9c67b1b494 debian packaging updates 2013-08-08 21:49:35 +02:00
Daniel Pavel
22656d5b82 use Gtk.Application properly 2013-08-08 21:49:35 +02:00
Daniel Pavel
d55963caba clean-up in usb IDs 2013-08-08 21:49:35 +02:00
Daniel Pavel
413cebe40f delay some UI initialization until necessary 2013-08-08 21:49:35 +02:00
Daniel Pavel
140ffae01a Merge pull request #106 from damsweb/master
Update fr.po to fix a few typo/mistakes
2013-08-08 07:12:01 -07:00
Daniel Pavel
68251777fb Merge pull request #107 from damsweb/patch-2
Update README.md to add Mageia
2013-08-08 06:29:21 -07:00
Damien Lallement
188b20a4f1 Update README.md to add Mageia 2013-08-07 16:43:46 +02:00
Damien Lallement
5fba1db11c Update fr.po to fix a few typo/mistakes
Fixing feminine words and fix bad translations for connection.
2013-08-07 14:47:46 +02:00
Daniel Pavel
21b1a722fc Merge pull request #102 from david-geiger/patch-1
Add French translation (fr.po) (pwr/Solaar#97)
2013-08-06 07:51:32 -07:00
Daniel Pavel
715c50685b Merge pull request #103 from zipperten/master
Added Swedich translation
2013-08-06 07:50:46 -07:00
Tomi Leppänen
dd0ba17351 The first version of Finnish translation.
I don't have much experience in translating, so I'd like my translations
to be reviewed by someone with more experience.
Some translations aren't that good. Especially I'd like to know if there
is any better or newer word for pairing in Finnish. Some problems I've
already marked in po/fi.po. I'd imagine that the longest texts need the
most fixing.
2013-08-05 19:47:03 +03:00
david_david
576dd4cdd4 Update fr.po
update "Last-Translator:"
2013-08-05 08:15:44 +02:00
david_david
a2a0380401 Update fr.po
#: lib/solaar/ui/about.py:49
#: lib/solaar/ui/window.py:640
2013-08-04 23:08:47 +02:00
david_david
f1a85f45bd Update fr.po 2013-08-04 11:51:53 +02:00
david_david
200cf48df4 Update fr.po 2013-08-04 11:50:24 +02:00
david_david
14b5993dc3 Create fr.po 2013-08-03 16:48:12 +02:00
david_david
585ba93588 Create fr.po 2013-08-03 16:44:30 +02:00
zipperten
e30a692a6e Added Swedich translation 2013-07-30 01:51:35 +02:00
Daniel Pavel
edc563e0e4 release 0.9.2 2013-07-24 11:40:54 +02:00
Daniel Pavel
969ca59948 translation credits: order languages alphabetically 2013-07-24 11:39:45 +02:00
Daniel Pavel
53abd22176 packaging: add compiled locale files 2013-07-24 11:06:58 +02:00
Daniel Pavel
f449b37bda minor update to the devices doc 2013-07-23 22:50:37 +02:00
Daniel Pavel
c97f4082dd translation credits updated 2013-07-23 22:49:47 +02:00
Daniel Pavel
5e6761c61b use relative paths in .pot/.po comments
otherwise the comments get changed when someone else run po-update
2013-07-23 22:48:59 +02:00
Daniel Pavel
b2c87b4f80 Merge pull request #95 from nexces/master
Added Polish translation
2013-07-23 13:36:30 -07:00
Adrian 'Nexces' Piotrowicz
58fcb074ff Updated po-update.sh script for use in (x)buntu.
Added another location to scan in function unfmt() due to fact that gtk30.mo and gtk30-properties.mo are found in /usr/share/locale-langpack/ instead of /usr/share/locale/.
2013-07-23 10:49:25 +02:00
Adrian 'Nexces' Piotrowicz
dbff65a4d1 Updated POT (translation template) 2013-07-23 10:49:05 +02:00
Adrian 'Nexces' Piotrowicz
a7ac589692 Added Polish translation 2013-07-23 10:46:56 +02:00
Daniel Pavel
3d4570cd1f check the Gtk bindings version at start-up 2013-07-20 06:22:15 +02:00
Daniel Pavel
b6bc35ed3e K800: added support for hand detection 2013-07-19 11:49:30 +02:00
Daniel Pavel
5d4d0c07ad use () instead of [] where possible 2013-07-19 11:48:40 +02:00
Daniel Pavel
15cb97c56e udev devices may not have all the attributes; fixes #93 2013-07-19 11:46:50 +02:00
Daniel Pavel
f902b32755 m515 device scan 2013-07-18 20:40:38 +02:00
Daniel Pavel
fcfc7cd6fc a few more asserts in descriptors
just testing stuff...
2013-07-18 20:38:05 +02:00
Daniel Pavel
c3718d22d6 minor clean-ups 2013-07-18 20:36:27 +02:00
Daniel Pavel
2829acd6f5 added side-scrolling toggle setting 2013-07-18 20:35:39 +02:00
Daniel Pavel
c35ae8ffc9 added wpid to T650 descriptor 2013-07-18 20:34:29 +02:00
Daniel Pavel
f7159e9338 properly mask flags when writing device settings; fixes #86 2013-07-18 20:33:52 +02:00
Daniel Pavel
4074fb7750 trim the codename to the declared length (fixes #90) 2013-07-18 16:23:34 +02:00
Daniel Pavel
444169d84b added descriptor for V550 Nano 2013-07-18 15:26:53 +02:00
Daniel Pavel
5d5f97a776 Gtk.Application.get_dbus_object_path my be missing 2013-07-18 14:06:51 +02:00
Daniel Pavel
a8c5d3bc24 Nano receivers were unsupported on kernel 3.2; fixes #88 2013-07-18 14:01:36 +02:00
Daniel Pavel
dd2a18d60e added documentation for translators 2013-07-17 20:36:39 +02:00
Daniel Pavel
a3f9860181 added descriptor for V450 Nano; fixes #89 2013-07-17 20:02:31 +02:00
Daniel Pavel
1fed000855 added wpid to M515 desccriptor 2013-07-17 19:54:28 +02:00
Daniel Pavel
61dfefde94 internationalized most strings; fixes #79
some might have slipped through the cracks
2013-07-17 19:53:21 +02:00
Daniel Pavel
454fbcbc6e Merge remote-tracking branch 'origin/master' 2013-07-16 16:41:53 +02:00
Daniel Pavel
8112e90ded website: replace the png logo with embedded svg 2013-07-16 16:36:00 +02:00
Daniel Pavel
a4c0ad3d73 added M345 descriptor info 2013-07-16 12:51:01 +02:00
Daniel Pavel
30f2afacb7 debian packaging: cleaned-up the debian/ files
according to feedback on debian bug #715172
(http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=715172)
2013-07-16 12:50:47 +02:00
Daniel Pavel
2a27c1d14e Merge pull request #87 from Lekensteyn/updates
docs/devices: add M345 (HID++ 2.0)
2013-07-16 03:39:28 -07:00
Peter Wu
cccf4ec428 docs/devices: add M345 (HID++ 2.0) 2013-07-16 12:31:56 +02:00
Daniel Pavel
38c76393b1 added copyright notices to all source files 2013-07-15 17:54:42 +02:00
Daniel Pavel
ce9b10dc2d started i18n support 2013-07-15 17:16:44 +02:00
Daniel Pavel
13e89dc219 post-build updates: debian/changelog and jekyll config 2013-07-13 13:23:52 +02:00
Daniel Pavel
16af3a9acc version 0.9.1 2013-07-13 11:24:41 +02:00
Daniel Pavel
c690b2c9e9 minor descriptors clean-up 2013-07-13 11:15:23 +02:00
Daniel Pavel
43ab629a26 moved logitech.unifying_receiver package to logitech_receiver 2013-07-12 22:48:09 +02:00
Daniel Pavel
b83a14e16f minor clean-ups and formatting 2013-07-12 22:39:17 +02:00
Daniel Pavel
a966bbff6f fixed handling of protocol version when the device is offline 2013-07-12 22:23:03 +02:00
Daniel Pavel
141a5c3dee don't ping devices known to be offline 2013-07-12 22:07:58 +02:00
Daniel Pavel
994bb07bc4 descriptors updated 2013-07-12 21:55:32 +02:00
Daniel Pavel
24f658d8fe support multiple Wireless PIDs for same device model 2013-07-12 21:53:23 +02:00
Daniel Pavel
49d77a2f90 handle unknown devices slightly better 2013-07-12 20:30:46 +02:00
Daniel Pavel
876cf35954 automatically detect the latest source.changes file generated 2013-07-12 17:14:15 +02:00
Daniel Pavel
46c0448854 got rid of /opt/extras sillyness in ubuntu packaging 2013-07-12 17:02:17 +02:00
Daniel Pavel
d78c7ed9be make sure items in window tree are sorted by number (fixed #73) 2013-07-12 15:24:49 +02:00
Daniel Pavel
51d0ccf654 only popup the window once per device on battery alerts 2013-07-12 14:35:16 +02:00
Daniel Pavel
9c8252b59f on alert popups, selected the device that triggered the popup 2013-07-12 14:10:26 +02:00
Daniel Pavel
488a78cc52 fixed #75 (pair button disappearing) 2013-07-12 10:35:28 +02:00
Daniel Pavel
0e6d088372 fixed some awkward path joining stuff 2013-07-11 22:46:29 +02:00
Daniel Pavel
d4d1a4f8e2 install the .desktop file in /etc/xdg/autostart (fixes #77) 2013-07-11 22:45:29 +02:00
Daniel Pavel
34801bfd1e install the application icon in hicolor/scalable/apps 2013-07-11 22:24:57 +02:00
Daniel Pavel
948b4c4d51 updated descriptors and devices doc for Anywhere MX 2013-07-11 15:34:36 +02:00
Daniel Pavel
85efe92d30 replaced appinstance with GtkApplication 2013-07-09 17:52:07 +02:00
Daniel Pavel
b01636e05d build-updated files for 0.9.0 2013-07-09 15:26:38 +02:00
Daniel Pavel
c0a7838429 version 0.9.0 2013-07-09 14:42:46 +02:00
Daniel Pavel
eda4112501 removed obsolete old window code 2013-07-08 21:21:53 +02:00
Daniel Pavel
dbb9025e26 replaced _ dummies with _ignore 2013-07-08 21:21:14 +02:00
Daniel Pavel
beee0bc8c2 typo in comment 2013-07-08 20:51:30 +02:00
Daniel Pavel
1bd6fd512b debian changelog updated 2013-07-07 22:15:00 +02:00
Daniel Pavel
ab8421b2f2 simplified (again) the deb build script
This time also check for consistency of .orig archives.
2013-07-07 22:07:31 +02:00
Daniel Pavel
1be56dd072 version 0.8.99.12 2013-07-07 21:58:33 +02:00
Daniel Pavel
c023f81f1a ChangeLog clean-up 2013-07-07 21:58:06 +02:00
Daniel Pavel
47f64d40de explicit encoding in main scripts 2013-07-07 21:54:35 +02:00
Daniel Pavel
d0b8233c9a minor clean-up 2013-07-07 21:40:55 +02:00
Daniel Pavel
39534d11dd make sure all debug and info loggings are if-guarded 2013-07-07 17:18:42 +02:00
Daniel Pavel
ca2f5f927c configuration: save on every change (fixes #80) 2013-07-07 16:06:27 +02:00
Daniel Pavel
2ab040591c major clean-up of debian building script 2013-07-07 14:06:03 +02:00
Daniel Pavel
8b26759731 release 0.8.99.11 2013-07-07 14:04:11 +02:00
Daniel Pavel
0e43287386 added a symlink to README.md to pacify sdist 2013-07-07 12:25:12 +02:00
Daniel Pavel
7221ceb7b4 forget battery status when the device has been offline for too long 2013-07-07 12:23:58 +02:00
Daniel Pavel
66416ff4cc fixed parsing of custom battery messages 2013-07-07 12:23:23 +02:00
Daniel Pavel
0d89d1e6c8 formatting fix in unpairing error dialog 2013-07-07 01:31:22 +02:00
Daniel Pavel
81765ee971 clean-ed up and documented gh_pages build script 2013-07-06 18:10:05 +02:00
Daniel Pavel
b72273b2a9 jekyll: made all image/css links relative 2013-07-06 18:08:52 +02:00
Daniel Pavel
e697a2d6cf updated debian build & upload scripts 2013-07-06 14:47:07 +02:00
Daniel Pavel
94d07eed53 version 0.8.99.10 2013-07-06 14:35:34 +02:00
Daniel Pavel
64ce3872b4 changelog updated 2013-07-06 14:24:17 +02:00
Daniel Pavel
508444526a commented-out the poll-ticking feature
not useful right now, and less code to worry about
2013-07-06 14:23:56 +02:00
Daniel Pavel
faa6de3b75 more explicit error dialogs, when possible 2013-07-06 14:20:50 +02:00
Daniel Pavel
77d2ae5249 omit the date in logging, is not important and the lines are shorter 2013-07-06 14:20:12 +02:00
Daniel Pavel
e2f94a9e0e be more lax as to when to allow pairing new devices 2013-07-06 13:55:22 +02:00
Daniel Pavel
ba55e4d9bd import * cleanups 2013-07-05 16:19:49 +02:00
Daniel Pavel
8e9ff939f3 hidconsole: enable hidpp automatically when talking to a Logitech Recevier 2013-07-05 16:19:24 +02:00
Daniel Pavel
bd3198f6f0 correctly handle out-of-process pairing and unpairing 2013-07-05 16:06:38 +02:00
Daniel Pavel
3319feeb73 replaced type() with isinstance() where possible 2013-07-05 16:02:38 +02:00
Daniel Pavel
47bcd4478c prettier error message if unpair fails 2013-07-05 14:35:06 +02:00
Daniel Pavel
065b8628d2 don't always show Notifications in details 2013-07-05 14:34:37 +02:00
Daniel Pavel
87e2f1cad7 solaar-cli: clearer handling of invalid device numbers 2013-07-05 14:34:18 +02:00
Daniel Pavel
373b07f271 fixed pairing in solaar-cli 2013-07-05 14:33:58 +02:00
Daniel Pavel
58f598fc88 version 0.8.99.9 2013-07-04 13:49:48 +02:00
Daniel Pavel
8f44c294d7 still getting strange messages from some devices 2013-07-04 13:37:39 +02:00
Daniel Pavel
f65079ad6d formatting fix for notifications 2013-07-04 13:35:23 +02:00
Daniel Pavel
edce56cd20 use a single separate thread for all possibly long-running stuff in GUI 2013-07-04 13:23:25 +02:00
Daniel Pavel
cd437c3809 only set NOTIFICATION_FLAGS for 1.0 devices 2013-07-04 13:22:35 +02:00
Daniel Pavel
007cbef086 better coverage of incoming events 2013-07-04 13:20:00 +02:00
Daniel Pavel
a03cc9ce64 more chair switching -- moved notifications handling into own .py 2013-07-03 08:21:40 +02:00
Daniel Pavel
3275aa4c12 allow most receivers to unpair (or at least try) 2013-07-03 08:18:47 +02:00
Daniel Pavel
a0f880fbba fix for NoneType crash 2013-07-02 19:43:18 +02:00
Daniel Pavel
833f087fdf also show polling rate in Hz 2013-07-02 12:23:47 +02:00
Daniel Pavel
9a2a28e0aa replaced hard-coded register numbers with constants
also re-worked the battery reading code a bit
2013-07-02 12:23:12 +02:00
Daniel Pavel
bf5fc42f07 fixed duplicate entries in keyboard tasks 2013-07-02 00:40:34 +02:00
Daniel Pavel
fb495fd2fc version 0.8.99.8 2013-07-01 19:35:46 +02:00
Daniel Pavel
90ab7af069 Anywhere MX and M600 descriptor updates 2013-07-01 19:22:46 +02:00
Daniel Pavel
0914e4c48d scan-registers: more lax interpretation of arguments 2013-07-01 19:01:37 +02:00
Daniel Pavel
3436055c7f re-worked (AGAIN) the way the devices are initially set-up
There is absolutely no consistency between the registers and
features receivers have, even if they're the same product_id!
2013-07-01 19:00:26 +02:00
Daniel Pavel
20aa797e96 configuration: use wpid in device key 2013-07-01 18:53:10 +02:00
Daniel Pavel
5ebc2634ae (hopefully) better serial read-out for devices 2013-07-01 18:40:03 +02:00
Daniel Pavel
94464a40b8 show the battery charge in the devices tree, if available (fixes #71) 2013-07-01 18:39:17 +02:00
Daniel Pavel
1194abf125 don't know yet how to tell if the receiver supports the unifying protocol 2013-07-01 15:28:05 +02:00
Daniel Pavel
ceba698678 moved settings templates into separate .py 2013-07-01 15:24:30 +02:00
Daniel Pavel
b1e9480f5a minor logging tweaks 2013-07-01 15:00:21 +02:00
Daniel Pavel
eaa38c858c properly format battery status string for 0x07 devices 2013-07-01 11:51:20 +02:00
Daniel Pavel
4504045bc6 extended descriptor for M305 2013-07-01 11:49:44 +02:00
Daniel Pavel
a9ea69b9a1 more explicit error message when trying to pair uncompatible devices 2013-07-01 11:41:47 +02:00
Daniel Pavel
9a8d089c73 handle some mystery data packets from older devices 2013-07-01 11:34:54 +02:00
Daniel Pavel
0d56cfbded clean-up in get/set notification flags computation 2013-06-30 17:12:44 +02:00
Daniel Pavel
9896875180 cleaner import 2013-06-30 15:03:39 +02:00
Daniel Pavel
a1c04ce39f renamed 'leds' register to '3leds', in case other may be found later 2013-06-30 15:02:58 +02:00
Daniel Pavel
da541e000a put usb ids into separate py file 2013-06-30 14:34:53 +02:00
Daniel Pavel
e490162e4f the K400 also has the FN swap feature 2013-06-30 14:04:14 +02:00
Daniel Pavel
a0b7d39f83 use the wpid to identify devices, when possible 2013-06-30 13:49:35 +02:00
Daniel Pavel
c464e049bf allow settings to be bound to certain device types
avoids stuff like smooth-scroll being attached to a keyboard
2013-06-29 21:26:25 +02:00
Daniel Pavel
daad9b5d5f cleaned-up NamedInts, added int2bytes and bytes2int generic functions 2013-06-29 20:37:04 +02:00
Daniel Pavel
2682722cb1 cleaned-up config_panel code 2013-06-29 20:35:35 +02:00
Daniel Pavel
8d5718178f load the configuration when the device is detected
and apply it every time the device comes online
2013-06-29 20:35:02 +02:00
Daniel Pavel
1d438f098f handle 0x07 battery notifications with indicating charging, but with no battery level 2013-06-29 20:26:29 +02:00
Daniel Pavel
1d305db29e minor UI layout tweaks 2013-06-29 19:02:19 +02:00
Daniel Pavel
c2a549c114 the K800 also has 3 leds, use them to indicate battery charge 2013-06-28 17:09:05 +02:00
Daniel Pavel
f43e298ac7 clean-up configuration on load and save 2013-06-26 16:05:14 +02:00
Daniel Pavel
c25b769578 repr() formatting cleanups 2013-06-26 13:40:46 +02:00
Daniel Pavel
0cf1f1983d handle backlight notifications from register 0x17 2013-06-26 13:38:36 +02:00
Daniel Pavel
39ec568ab1 descriptors table and devices documentation updated 2013-06-25 18:54:27 +02:00
Daniel Pavel
5b94ebae34 enable the backlight notifications on devices, if available 2013-06-25 18:53:18 +02:00
Daniel Pavel
a857b5fc43 fixed transparency in generated site icons 2013-06-25 17:11:28 +02:00
Daniel Pavel
eb8791ec47 fixed gh_pages script to use solaar.svg 2013-06-25 16:18:05 +02:00
Daniel Pavel
ff6da43007 version 0.8.99.7 2013-06-25 16:08:47 +02:00
Daniel Pavel
d42fdf8a4a updated debian copyright file (added svgs) 2013-06-25 16:06:13 +02:00
Daniel Pavel
adab25ad44 changelog updated 2013-06-25 16:02:21 +02:00
Daniel Pavel
90b057938b recommend python-dbus and upower in debian package control 2013-06-25 16:02:14 +02:00
Daniel Pavel
fc5c72e164 some clean-ups in descriptors 2013-06-25 16:01:29 +02:00
Daniel Pavel
bd5c03812f replaced solaar png icons with svgs 2013-06-25 15:59:49 +02:00
Daniel Pavel
6b0b7ea823 minor clean-ups and formatting 2013-06-24 17:04:19 +02:00
Daniel Pavel
dd24ed5fe0 brought solaar-cli in sync with the latest gui code 2013-06-24 17:02:45 +02:00
Daniel Pavel
f64942b51d if the battery level is approximative, show a string instead of percentage 2013-06-24 17:02:00 +02:00
Daniel Pavel
375db9996f fixed reading correct device kind on link notification 2013-06-24 16:58:41 +02:00
Daniel Pavel
20dfc063ff initial support for performance mx leds
The leds light up when we get updates about the battery level.
Right now they are not (programatically) turned off.
2013-06-23 20:59:16 +02:00
Daniel Pavel
70c341e268 don't use proxies for receiver/device objects
they should be unnecessary now that their status is properly tracked
2013-06-23 18:37:50 +02:00
Daniel Pavel
dc59c79bd3 properly handle tree re-selection when removing a receiver 2013-06-23 18:35:23 +02:00
Daniel Pavel
422cd26b92 some extra asserts on hid++ 1.0 register r/w 2013-06-23 18:16:13 +02:00
Daniel Pavel
cec892ce88 disable poll ticking
It was necessary to periodically check if the peripherals are still
online -- suspend/resume may cause Solaar to (wrongfully) remember the
status of devices after a resume.

Now that is handled by the optional upower module -- the hard way -- by
restarting all listeners on resume.
2013-06-23 18:15:19 +02:00
Daniel Pavel
d5374b9f51 optionally listen for upower suspend/resume events to stop/start all receiver listeners 2013-06-23 18:11:42 +02:00
Daniel Pavel
51e2d965cf version 0.8.99.6 2013-06-23 15:46:16 +02:00
Daniel Pavel
a6c8f2212a suggest appindicator library in solaar package 2013-06-23 15:45:07 +02:00
Daniel Pavel
b3aac40246 dropped activate_on_single_click, requires gtk 3.8 2013-06-23 13:44:34 +02:00
Daniel Pavel
fb138b77ff version 0.8.99.5 2013-06-23 13:09:44 +02:00
Daniel Pavel
273284da39 use number instead of serial to pick devices in ui (faster start-up) 2013-06-23 12:09:46 +02:00
Daniel Pavel
7102229937 properly handle ^C in console 2013-06-22 21:32:19 +02:00
Daniel Pavel
be80ba3b3b version 0.8.99.4 2013-06-21 22:27:18 +02:00
Daniel Pavel
4410cb6dc6 comment-out old main window 2013-06-21 22:25:04 +02:00
Daniel Pavel
df8df2bffa don't force a battery read on link active, will happen anyway 2013-06-21 22:24:28 +02:00
Daniel Pavel
ae4c921300 cleaner start-up of paired devices 2013-06-21 22:23:53 +02:00
Daniel Pavel
3d1aa6698d only check for non-unifying protocol only on nano receviers 2013-06-21 22:19:31 +02:00
Daniel Pavel
613b115eb4 fixed clean-up of config panel when unpairing devices 2013-06-21 16:51:39 +02:00
Daniel Pavel
e19b690bd5 fixed reading of polling rate 2013-06-21 16:47:19 +02:00
Daniel Pavel
888be8e8a8 be a bit more patient when pairing, the device notification may come after the pairing lock is closed 2013-06-21 16:40:00 +02:00
Daniel Pavel
5785896007 status: the device may be invalid when processing the unpair notification 2013-06-21 16:39:30 +02:00
Daniel Pavel
8d522de7e7 drop some unnecessary logging when ignoring request replies 2013-06-21 16:39:04 +02:00
Daniel Pavel
81ae4c8d4d forgot about pairing notification on receiver... 2013-06-21 16:32:29 +02:00
Daniel Pavel
8cd3b8fdef save configuration a little early, better timing on shutdown 2013-06-21 15:21:49 +02:00
Daniel Pavel
c1aa341a7a tweaked timing of enabling receiver notifications 2013-06-21 15:20:52 +02:00
Daniel Pavel
f9c192c47a only look for a different tray battery icon if the changed device is a peripheral 2013-06-21 15:19:07 +02:00
Daniel Pavel
cdc6da844e made the config_panel self-contained 2013-06-21 15:18:21 +02:00
Daniel Pavel
fd35f23af7 one a separate flag to check if the device is active 2013-06-21 15:17:14 +02:00
Daniel Pavel
c04851f64e better handling of timeouts in base.request 2013-06-21 15:05:48 +02:00
Daniel Pavel
3a63c3ad43 fixed reading encrypted link status in pairing window 2013-06-21 15:04:06 +02:00
Daniel Pavel
431f1c97cf added read/write_register to receiver and devices 2013-06-21 15:03:36 +02:00
Daniel Pavel
1b68a3d5a9 fixed request timeouts for devices 2013-06-20 19:51:54 +02:00
Daniel Pavel
c797808a40 fixed status keys in pairing 2013-06-20 19:35:54 +02:00
Daniel Pavel
d810ccba84 tray icon: pick the battery of the lowest _active_ device 2013-06-20 17:25:53 +02:00
Daniel Pavel
2fea5d9af2 disable the unpair button for peripherals of a Nano receiver 2013-06-20 17:21:58 +02:00
Daniel Pavel
1d9a3bf23a fixed checking for features of offline 2.0 devices 2013-06-20 17:21:23 +02:00
Daniel Pavel
3d8c764eb0 relax timeouts for device requests 2013-06-20 17:13:49 +02:00
Daniel Pavel
eb317f0d46 version 0.8.99.2 2013-06-20 14:49:02 +02:00
Daniel Pavel
27de1aea11 tray/window: append new devices rather than inserting them at the top 2013-06-20 14:43:49 +02:00
Daniel Pavel
92f7e761ee don't save the configuration if it hasn't been loaded first 2013-06-20 14:27:18 +02:00
Daniel Pavel
b2f1786eff use consistent naming of offline state for devices 2013-06-20 14:18:36 +02:00
Daniel Pavel
f8369e7c63 properly style the details panel 2013-06-20 14:18:03 +02:00
Daniel Pavel
f095a74f2a make the main window a regular window (visible in tasks list) 2013-06-20 13:51:42 +02:00
Daniel Pavel
4e3fccb009 fixed sizing of details panel 2013-06-20 13:41:05 +02:00
Daniel Pavel
a2995ed3c5 minor build_deb script update 2013-06-20 13:13:14 +02:00
Daniel Pavel
5edff9235b changelog update 2013-06-20 13:12:39 +02:00
Daniel Pavel
31e134c1e0 don't wait so long on the first idle poll 2013-06-20 13:12:29 +02:00
Daniel Pavel
47e22b788f version 0.8.99, will become 0.9 on release 2013-06-20 13:12:12 +02:00
Daniel Pavel
798628fdf8 add the USB id for the receiver in the details panel 2013-06-20 13:10:55 +02:00
Daniel Pavel
ca9825d262 support for the VX Nano mouse 2013-06-20 13:10:30 +02:00
Daniel Pavel
1a36ec65ee faster checking of feature-based settings 2013-06-20 12:55:48 +02:00
Daniel Pavel
d07a20e6f8 improved reading device properties 2013-06-20 12:54:27 +02:00
Daniel Pavel
783b317281 added a protocol field to the device descriptors 2013-06-20 11:04:17 +02:00
Daniel Pavel
4bc525f250 minor clean-ups 2013-06-20 11:02:45 +02:00
Daniel Pavel
11cfc7ea09 enable notification on recevier as soon as possible 2013-06-19 19:46:54 +02:00
Daniel Pavel
a806f2672d group all status keys into one object 2013-06-19 19:45:39 +02:00
Daniel Pavel
2fee88e54b fixed battery charge display in device info 2013-06-19 19:23:18 +02:00
Daniel Pavel
7e1a2a6e4f more fixes for device unpairing 2013-06-19 17:21:28 +02:00
Daniel Pavel
d5b311760e clean obsolete settings controls when devices are unpaired 2013-06-19 17:04:01 +02:00
Daniel Pavel
dffe6f8b91 fix display of firmware in details panel 2013-06-19 17:03:16 +02:00
Daniel Pavel
b4bca4670b cache notification flags when possible
avoids unnecessary reads from devices when the status hasn't changed
2013-06-19 17:03:01 +02:00
Daniel Pavel
150c43f41f some logging in udev 2013-06-19 16:49:20 +02:00
Daniel Pavel
9fc11df229 fixed window update when unpairing 2013-06-19 16:22:44 +02:00
Daniel Pavel
56a7a960c3 polling: it may happen that the receiver is removed mid-poll 2013-06-19 16:14:04 +02:00
Daniel Pavel
cd44cc6396 new single-window UI 2013-06-19 15:28:13 +02:00
Daniel Pavel
4af714f1dd K750: register the FN swap setting statically, no need to detect it at runtime 2013-06-18 16:48:02 +02:00
Daniel Pavel
836719587c renamed NANO receiver id 2013-06-18 16:45:44 +02:00
Daniel Pavel
2d6fab6e14 gh_pages build script updated 2013-06-17 16:48:04 +02:00
Daniel Pavel
0ae58a3346 fixed ubuntu dh_link 2013-06-17 16:47:44 +02:00
Daniel Pavel
f32e958984 version 0.8.9.4 2013-06-17 16:12:32 +02:00
Daniel Pavel
0703d927ca document Logitech receiver USB ids 2013-06-17 16:12:09 +02:00
Daniel Pavel
62b5deb77d debconf translation support (just english for now) 2013-06-17 16:11:46 +02:00
Daniel Pavel
82e718b3d1 create the plugdev group in postinst, not config 2013-06-17 16:11:17 +02:00
Daniel Pavel
41409c9b94 use debconf to check if the plugdev group is necessary 2013-06-17 14:45:45 +02:00
Daniel Pavel
57c759773a attach configuration to device settings objects 2013-06-17 11:00:53 +02:00
Daniel Pavel
9d6402a4f7 shorter thread name on receiver listener 2013-06-17 08:00:17 +02:00
Daniel Pavel
a29609df21 only save the configuration once when Solaar ends 2013-06-17 08:00:00 +02:00
Daniel Pavel
04ea8293a8 persist and restore device settings 2013-06-16 17:41:03 +02:00
Daniel Pavel
bde54aba3b proper shutdown of receiver listeners 2013-06-16 17:10:46 +02:00
Daniel Pavel
687e1be3e5 simplify debian/rules a bit 2013-06-16 17:10:46 +02:00
Daniel Pavel
a44d9b7ca8 fix battery display in main window 2013-06-16 17:10:46 +02:00
Daniel Pavel
febf571d84 account for devices going out-of-range while active 2013-06-16 17:10:46 +02:00
Daniel Pavel
818ece9f10 Merge pull request #67 from Lekensteyn/updates
udev: Use uaccess instead of plugdev (pwr/Solaar#66)
2013-06-16 08:10:04 -07:00
Peter Wu
ec10c9c70c udev: Use uaccess instead of plugdev (pwr/Solaar#66)
Rules are taken from https://git.lekensteyn.nl/ltunify/. The "VX Nano" receivers
(c51a and c526) have been removed as these are only used for Cordless mice and
are not even enabled in Solaar.

The installer is updated to check for the existence of a group and `mktemp` to
create temporary files. (relying on `$TMPDIR` is a bad idea.) This installer is
too fancy, most users will be fine with `install -m644
rules.d/42-logitech-unify-permissions.rules /etc/udev/rules.d/`. If you are lazy
and want to make `solaar-cli` work over SSH, then this installer will help you.
It won't add you to the `plugdev` group, instead it will edit the rule to use
your user's primary group.

Oh, and it does not change this group to "root" as that is pretty useless given
that root is the default.
2013-06-16 11:33:37 +02:00
Daniel Pavel
8852d50971 mark device status as inactive after idling out 2013-06-12 14:31:46 +02:00
Daniel Pavel
908f6763be updated deb/ppa build scripts 2013-06-12 14:31:16 +02:00
Daniel Pavel
03e20842fb cleaned-up gtk ui initialization 2013-06-12 14:29:34 +02:00
Daniel Pavel
084913ac91 updated devices documentation 2013-06-12 14:29:01 +02:00
Daniel Pavel
d9801e2d57 fixed firmware info for some HID++ 2.0 devices 2013-06-12 14:21:31 +02:00
Daniel Pavel
29fe913fd8 version 0.8.9.3 2013-06-08 21:11:39 +02:00
Daniel Pavel
5b68f9623e fix indicator description when there are receivers but no devices 2013-06-08 21:10:17 +02:00
Daniel Pavel
2a6662472d account for all GLib.id_add_watch variants 2013-06-08 21:07:24 +02:00
Daniel Pavel
5cf6777340 more tweaks to idle polling 2013-06-08 21:06:52 +02:00
Daniel Pavel
17863c85b6 fixed querying for known registers 2013-06-08 21:06:22 +02:00
Daniel Pavel
237d0f9d9a keep the battery level if polling the device marks it as offline 2013-06-08 21:05:30 +02:00
Daniel Pavel
b98e27e464 fix permissions error popup 2013-06-08 21:04:32 +02:00
Daniel Pavel
d01d9edb78 tweaked idle polling timings 2013-06-08 16:27:03 +02:00
Daniel Pavel
0a86683392 clean-up in solaar.listener 2013-06-08 16:18:25 +02:00
Daniel Pavel
b2b4febd31 receiver notifications: don't set all flags, might fail 2013-06-08 16:18:10 +02:00
Daniel Pavel
ad67e6eaee fix read timeouts in base.py, use seconds everywhere 2013-06-08 16:17:14 +02:00
Daniel Pavel
ed5ce48f65 fixes to polling receiver/device status 2013-06-08 16:16:12 +02:00
Daniel Pavel
2e351bfc78 read .devscripts if available 2013-06-08 16:08:00 +02:00
Daniel Pavel
f324b97e8b use GLib.io_add_watch_full when available 2013-06-08 15:02:44 +02:00
Daniel Pavel
46544e1cbe listen for udev events on the GLib main loop 2013-06-07 14:39:04 +02:00
Daniel Pavel
ffab6c0e12 move Gtk-specific idle_add() and main() into ui 2013-06-07 14:37:03 +02:00
Daniel Pavel
10e736386b user module __name__ when initializing logger 2013-06-07 14:28:13 +02:00
Daniel Pavel
a1ecebf5bf documentation and logging for 2013-06-07 14:24:05 +02:00
Daniel Pavel
996597dcb1 fixed upload_ppa script 2013-06-06 12:25:17 +02:00
Daniel Pavel
e09ad373b3 version 0.8.9.2 2013-06-06 12:19:44 +02:00
Daniel Pavel
ddf7d34982 debian packaging: always require -gnome3 for unity integration 2013-06-06 12:18:48 +02:00
Daniel Pavel
db9a4e4402 docs & changelog updates 2013-06-06 10:44:45 +02:00
Daniel Pavel
39a75a6792 AppIndicator: scrolling on the icon cycles through all devices 2013-06-06 10:25:35 +02:00
Daniel Pavel
d78484ff38 use githubredir.debian.net in watch 2013-06-05 19:49:23 +02:00
Daniel Pavel
8900ac9a1f tweak main window geometry 2013-06-05 13:21:22 +02:00
Daniel Pavel
7df2e8af97 jekyll config update, tweaked deb/gh scripts 2013-06-05 13:20:26 +02:00
Daniel Pavel
2ed723dfc2 minor doc update 2013-06-05 13:20:26 +02:00
Daniel Pavel
087177274d Merge pull request #63 from Lekensteyn/updates
Device documentation updates
2013-06-05 04:16:58 -07:00
Peter Wu
59459ebbd6 Fix crash in Python3 due to excess space
The error message was:

    TabError: inconsistent use of tabs and spaces in indentation
2013-06-05 12:39:00 +02:00
Peter Wu
2d981cd737 docs: add mk700 2013-06-05 12:39:00 +02:00
Peter Wu
4c4e6fd6f9 doc/k360: add another recv+kbd, fixup recv serial
Bug in ltunify made the serial number shift by one byte.
2013-06-05 12:38:03 +02:00
Daniel Pavel
c52f2fc069 fix descriptor for K700 keyboard 2013-06-05 01:24:19 +02:00
Daniel Pavel
eb3e2566e9 comment-out unnecessary logs 2013-06-05 00:32:01 +02:00
Daniel Pavel
c186573775 fix register blacklisting 2013-06-05 00:31:40 +02:00
Daniel Pavel
3d9d8d6efc replaced light_* icons with smaller ones 2013-06-04 10:03:13 +02:00
Daniel Pavel
1ed82fc7d5 version 0.8.9.1 2013-06-03 22:02:00 +02:00
Daniel Pavel
162228aff3 started configuration persistence implementation 2013-06-03 22:01:16 +02:00
Daniel Pavel
dd051f4c6e check latest github tag when generating gh-pages 2013-06-03 21:58:53 +02:00
Daniel Pavel
e59645b347 documentation updates 2013-06-03 21:40:54 +02:00
Daniel Pavel
cbdc0bd99b very low battery level should trigger an attention event 2013-06-03 21:40:15 +02:00
Daniel Pavel
b4fc36701a added attention() to tray icon 2013-06-03 21:39:29 +02:00
Daniel Pavel
f2f00e3017 re-arranged for easier extension 2013-06-03 11:17:58 +02:00
Daniel Pavel
c706fbc6e7 update icon theme paths directly, don't mess with XDG_DATA_DIRS 2013-06-03 11:17:19 +02:00
Daniel Pavel
88fb8458c1 logging tweaks 2013-06-02 16:16:58 +02:00
Daniel Pavel
982f298fc4 fixed page back-link 2013-06-02 12:20:44 +02:00
Daniel Pavel
4a9a05718e readme updated with Debian repo link 2013-06-02 12:16:24 +02:00
Daniel Pavel
b99a851af3 build deb-repo Packages index in $SITE/packages 2013-06-02 12:14:20 +02:00
Daniel Pavel
f452d6f5b7 jekyll pages: use absolute path for styles/images 2013-06-02 12:13:10 +02:00
Daniel Pavel
b98b94de91 documentation update -- gnome-shell indicators supported 2013-06-02 11:23:53 +02:00
Daniel Pavel
b18aee9dba maintain proper devices order in tray menu 2013-06-02 11:19:49 +02:00
Daniel Pavel
bfe7bcf1b4 avoid possible race condition on device initialization 2013-06-02 11:19:30 +02:00
Daniel Pavel
55bb732bb0 dropped unused battery icons 2013-06-02 01:11:47 +02:00
Daniel Pavel
465fea8a16 dropped solaar-mask unused icon 2013-06-02 01:11:32 +02:00
Daniel Pavel
149758ccab fixed battery icons in systray menu items 2013-06-02 01:11:04 +02:00
Daniel Pavel
16095544cb debian/control: put solaar-gnome3 in 'gnome' section 2013-06-01 23:10:10 +02:00
Daniel Pavel
37265f25d8 support custom icons in notification messages 2013-06-01 22:32:57 +02:00
Daniel Pavel
c61eb3f039 show charging status in device icon 2013-06-01 22:08:14 +02:00
Daniel Pavel
39862034e1 use just the battery icon in systray 2013-06-01 21:09:41 +02:00
Daniel Pavel
f938b29040 doc: icon names for various icon themes 2013-06-01 18:53:49 +02:00
Daniel Pavel
984b92815c use explicit debian/*.install files 2013-06-01 18:53:20 +02:00
Daniel Pavel
82c4b0007c updated solaar version to 0.8.9 2013-06-01 18:19:47 +02:00
Daniel Pavel
f4a3f699e8 debian/control: tweaks for gnome-shell/unity support 2013-06-01 18:19:31 +02:00
Daniel Pavel
9c4055a046 added Keywords entry to .desktop file 2013-06-01 18:01:23 +02:00
Daniel Pavel
088493dc4f guess battery icon set from the current theme 2013-06-01 17:34:54 +02:00
Daniel Pavel
479ab1fb7b generate a -gnome3 package for gnome-shell integration 2013-06-01 17:34:05 +02:00
Daniel Pavel
749cde6e72 require gir1.2-appindicator3 on ubuntu 2013-06-01 15:09:05 +02:00
Daniel Pavel
7317fad754 some debugging when setting icon theme paths 2013-06-01 15:08:23 +02:00
Daniel Pavel
83a29328c7 don't use notification flags with HID++ 2.0 devices 2013-06-01 15:07:39 +02:00
Daniel Pavel
788fb145af use an AppIndicator if available, instead of the status icon 2013-06-01 15:06:43 +02:00
Daniel Pavel
b1b1a9b5de Merge remote-tracking branch 'origin/master' 2013-05-27 16:24:34 +03:00
Daniel Pavel
941a36a385 Merge pull request #61 from Lekensteyn/sandbox
More special keys
2013-05-27 06:23:45 -07:00
Peter Wu
3ef3c23a29 devices/k360: update solaar output (keys, features) 2013-05-27 14:12:44 +02:00
Peter Wu
39e630cece cli: improve alignment for special keys
The following lines have an insane length and are therefore not included in the
longest line:

    WIN7_MONITOR_SWITCH_AS_WIN_SHIFT_LEFTARROW=0x0093,
    WIN7_MONITOR_SWITCH_AS_WIN_SHIFT_RIGHTARROW=0x0094,

While doing this, also fix an obvious typo in the "Lock PC" control.
2013-05-27 14:07:38 +02:00
Peter Wu
b2a62c2dd7 special_keys: update controls list
My previous observation was right, controls and tasks are really different
entities. The following "controls" appears to be invalid and have been removed:

    Home=0x001A,
    Music=0x001D,
    Search=0x0029,
    Sleep=0x002F,
2013-05-27 11:44:20 +02:00
Daniel Pavel
26dd3a2ca8 only need to set the default window icon once 2013-05-27 12:36:39 +03:00
Daniel Pavel
c328d6f6c6 fixed pairing in solaar-cli 2013-05-27 09:08:23 +03:00
Daniel Pavel
44c79d71d7 use new get_notifications_flags api in solaar-cli 2013-05-27 08:04:49 +03:00
Daniel Pavel
ecd90d605a Merge pull request #60 from Lekensteyn/updates
Update feature name list
2013-05-26 14:55:23 -07:00
Peter Wu
b6bd4b9da0 cli: fix alignment with new feature names 2013-05-26 23:51:46 +02:00
Peter Wu
6ae11f862c Add more feature names, rename existing ones
Extracted from SetPoint 6.52.74 software using:

    <FeaturesSupported.xml awk -F\" '/<Feature /{sub(/^LD_FID_/, "", $2); printf("\t%s=%s,\n", $2, $4)}' | sort -t= -k2

Existing names are renamed to the newer, verbose names.
2013-05-26 23:47:40 +02:00
Daniel Pavel
c224141355 Merge pull request #59 from Lekensteyn/special-keys
Special keys and tasks
2013-05-26 13:54:00 -07:00
Peter Wu
28c35633d3 Add more tasks for special keys
Based on tasks.xml from `%ProgramFiles%\\SetPointP\\tasks.xml`.
2013-05-26 22:47:03 +02:00
Peter Wu
6e36e33b22 Decouple controls from tasks (programmable keys)
They are treated differently in the HID++ 2.0 specification. Observations seem
to confirm this difference. For instance, a part of solaar-cli's output:

	0: unknown:0022         => Home                   FN sensitive, is FN, reprogrammable
	1: Mail                 => Mail                   FN sensitive, is FN, reprogrammable
	2: unknown:003E         => Search                 FN sensitive, is FN, reprogrammable
2013-05-26 22:47:03 +02:00
Daniel Pavel
093cca9d21 Merge pull request #57 from Lekensteyn/fixes
K360 docs, Improved solaar-cli argparse fix
2013-05-26 12:18:43 -07:00
Peter Wu
410c19dd78 devices/k360: ltunify+solaar-cli output of k360+receiver 2013-05-26 21:02:08 +02:00
Peter Wu
4a7be89be6 devices.md: add reprog keys to feature list, K360 2013-05-26 20:58:53 +02:00
Peter Wu
51305e0a21 solaar-cli: fix regression in argument parsing
When no hidraw device is given, `solaar-cli` crashes because `None` is being
indirected. Use the correct action (`store`) to avoid indirecting a list.
2013-05-26 20:51:58 +02:00
Daniel Pavel
fda3398440 commented-out stray print 2013-05-26 19:02:17 +03:00
Daniel Pavel
340ff0107c version 0.8.8.2 2013-05-26 18:43:23 +03:00
Daniel Pavel
8374a58dc1 fixed items in the systray menu 2013-05-26 18:40:53 +03:00
Daniel Pavel
3690863a27 fixed receiver icon in systray menu 2013-05-26 02:56:43 +03:00
Daniel Pavel
078d003cfe about window icon was not displayed 2013-05-26 02:56:25 +03:00
Daniel Pavel
b6ab795878 don't add receivers to the status icon tooltip 2013-05-26 02:03:58 +03:00
Daniel Pavel
7e81dede2f non-modal about dialog; fixes #46 2013-05-26 02:01:59 +03:00
Daniel Pavel
3482257b15 fix solaar-cli when no hidraw path given 2013-05-26 01:40:10 +03:00
Daniel Pavel
9f3ab8d3dd Merge remote-tracking branch 'origin/master' 2013-05-26 01:33:13 +03:00
Daniel Pavel
8f2ee555ec updated arch packaging scripts with official ones 2013-05-26 01:32:46 +03:00
Daniel Pavel
db53de2233 updated status_icon to support future appindicator implementation 2013-05-26 01:24:49 +03:00
Daniel Pavel
3596faed2f documentation updated with info about Nano receivers 2013-05-26 01:23:27 +03:00
Daniel Pavel
9e13d134d3 Merge pull request #56 from Lekensteyn/cli-updates
solaar-cli: Python3 fix, add option for custom receiver path
2013-05-25 08:43:53 -07:00
Peter Wu
7f229005a6 solaar-cli: support specifying different receiver 2013-05-25 15:46:13 +02:00
Peter Wu
e3a887f36c solaar-cli: fix argument parsing in Python 3 2013-05-25 15:17:43 +02:00
Daniel Pavel
bca8e64574 added README to packaging/ folder 2013-05-23 16:21:53 +03:00
Daniel Pavel
3873d7099c slightly reduce sleep timings when waiting for reply 2013-05-23 04:59:16 +03:00
Daniel Pavel
48b176f49a show result on reg00 unparsable output 2013-05-23 04:58:35 +03:00
Daniel Pavel
8b8b387f2a minor tweak to guessing device icon 2013-05-22 20:50:49 +03:00
Daniel Pavel
f459d9b953 updated installation docs and udev rule install scrip 2013-05-22 20:50:35 +03:00
Daniel Pavel
b276fbab90 updated scan-registers to support receiver scan 2013-05-22 20:47:04 +03:00
Daniel Pavel
e73f076324 don't support the VX Nano right now 2013-05-22 20:43:29 +03:00
Daniel Pavel
131f8f7f45 disable status polling on devices
the regular flow should be reading the battery on all devices now
2013-05-22 20:42:26 +03:00
Daniel Pavel
c3b73964d5 improved support for some Nano receivers 2013-05-22 20:41:11 +03:00
Daniel Pavel
790fc7c04b improved support for the Nano receiver 2013-05-22 07:31:16 +03:00
Daniel Pavel
cd33314d0b use passwd | addgroup in post-install 2013-05-22 06:55:59 +03:00
Daniel Pavel
4ba50267f1 add favicon when building site 2013-05-22 01:25:45 +03:00
Daniel Pavel
d46e603366 Merge remote-tracking branch 'origin/master' 2013-05-22 01:21:34 +03:00
Daniel Pavel
f8878d73c3 Merge pull request #54 from Lekensteyn/doc-updates
Doc updates
2013-05-21 15:19:46 -07:00
Peter Wu
9c0dac044c hid10: update 07 battery parsing based on spec
This fixes pwr/Solaar#49 partially, at least the charging state will be reported
correctly hereafter. The charge level may still be incorrect though.
2013-05-22 00:10:17 +02:00
Peter Wu
2f8e330b73 doc/logitech: add HID++1.0 battery level info
This should help in https://github.com/pwr/Solaar/issues/49. This information
was shared by Nestor Lopez Casado from Logitech.

What remains unclear are the 0x25 and 0x26 values for r1 (Charging state). It is
also not clear whether r0 (Battery/Charging level) always reports 0x00 while
charging the Performance MX. (Perhaps this is only reported the first few
seconds?)
2013-05-21 23:56:44 +02:00
Daniel Pavel
e6e55aa827 added performance mx LED documentation
supplied by Alexander Hofbauer
2013-05-22 00:31:08 +03:00
Peter Wu
07bff8cb37 docs/installation: typo fix, clarification
- Fix typo in rules path
 - Fix capitalisation.
 - `udevadm control --reload-rules` is unnecessary[1].
 - `adduser` is Debian-specific, use the more portable `gpasswd`.
 - No need to wait 10 seconds before re-inserting.
 - After adding to group, user must re-login.

 [1]: http://unix.stackexchange.com/a/39485/8250
2013-05-21 10:59:46 +02:00
Daniel Pavel
d857144653 added script to build gh-pages with jekyll 2013-05-21 01:12:04 +03:00
Daniel Pavel
17fdd840bb setup.py: use the version declared in the sources 2013-05-21 01:08:34 +03:00
Daniel Pavel
da6711c93c the 'Solar key' on K750 is named 'Light Check button' 2013-05-21 00:48:21 +03:00
Daniel Pavel
36b307eb49 updated debian/ppa build scripts 2013-05-21 00:47:47 +03:00
Daniel Pavel
2d8ec2fd78 added jekyll skeleton for the site 2013-05-21 00:46:49 +03:00
Daniel Pavel
11ba96103c minor updates to the documentation files 2013-05-21 00:46:07 +03:00
Daniel Pavel
843d2a224d add license section into the README 2013-05-20 16:49:44 +03:00
Daniel Pavel
0faf01c194 place the main application icon in share/pixmaps, not share/icons 2013-05-20 16:34:14 +03:00
Daniel Pavel
e868cf6270 use a separate icon for the about logo 2013-05-20 16:32:26 +03:00
Daniel Pavel
255b3d0da7 minor documentation updates 2013-05-20 13:53:39 +03:00
Daniel Pavel
5fad8d0680 minor documentation updates 2013-05-20 13:27:26 +03:00
Daniel Pavel
d3dcdcb92e Merge remote-tracking branch 'origin/master' 2013-05-19 11:54:38 +03:00
Daniel Pavel
44ae5edc56 Merge pull request #48 from Lekensteyn/doc-updates
Doc updates for HID++ 1.0 notifications
2013-05-19 01:52:07 -07:00
Peter Wu
f0542923d7 hid10: update flags description for notifications
The Logitech HID++ 1.0 documentation actually names the fields for devices and
receiver. Clarify that and explain why enabling all of the bits is a bad idea.
2013-05-19 10:30:41 +02:00
Peter Wu
29d0c07164 hid10: Formatting and re-order NOTIFICATION_FLAGs
Align values for easier reading the numeric values of NOTIFICATION_FLAGs.  To
maintain consistency in the ordering of the values, swap keyboard_backlight with
keyboard_present.
2013-05-19 10:20:21 +02:00
Peter Wu
152abb086a hid10: document notifications better
See [registers.txt][1] for 'keyboard_backlight'. The behavior of
keyboard_sleep_raw and keyboard_multimedia_raw is described at
[keyboard.txt][2].

 [1]: https://git.lekensteyn.nl/ltunify/tree/registers.txt
 [2]: https://git.lekensteyn.nl/ltunify/tree/keyboard.txt
2013-05-19 10:14:31 +02:00
Daniel Pavel
d5c36ddc89 about window tweak 2013-05-19 03:54:30 +03:00
Daniel Pavel
226a4ea2f3 version 0.8.8.1 2013-05-19 03:53:49 +03:00
Daniel Pavel
ac0eafe6ab don't crash when failing to load the icon mask 2013-05-19 03:52:01 +03:00
Daniel Pavel
87bc9a5431 depend on gnome-icon-theme or oxygen-icon-theme
It's necessary to make sure all the standard icons are available.
2013-05-19 03:35:42 +03:00
Daniel Pavel
ef62892f60 pop up a desktop notification if the battery is below 5% 2013-05-18 14:35:33 +03:00
Daniel Pavel
7ae24488d9 only notify on connected devices at start-up 2013-05-18 02:20:22 +03:00
Daniel Pavel
6482670fdf minor readme update 2013-05-18 01:31:15 +03:00
Daniel Pavel
317cf6d00f only enable certain notification flags on devices
Also added some documentation to the notification flags, where possible.
2013-05-18 00:15:42 +03:00
Daniel Pavel
a5eeac6e5a enable notifications for peripherals; fixes #27 2013-05-17 23:06:24 +03:00
Daniel Pavel
e2cf9255ac Merge pull request #41 from Lekensteyn/tool-updates
scan-registers: determine available notifications
2013-05-17 12:44:23 -07:00
Daniel Pavel
25941cdbdd debian version update 2013-05-17 20:04:33 +03:00
Daniel Pavel
1764633bc5 status icon menu items open the right device window 2013-05-17 19:55:07 +03:00
Daniel Pavel
f6eb90bd2d version and url fixes 2013-05-17 19:22:05 +03:00
Daniel Pavel
5f46c820e6 re-work the status icon updating 2013-05-17 16:03:37 +03:00
Daniel Pavel
c20b279362 minor tweaks 2013-05-08 12:06:01 +03:00
Daniel Pavel
24ceb8801e window popup fix for kwin
also, only try to position the window next to the status icon if it has never
been shown before
2013-05-07 05:59:29 +02:00
Daniel Pavel
8d5ca66db7 get rid of bad map() calls 2013-05-06 17:51:03 +02:00
Daniel Pavel
f0d250ff15 updated debian/control dependencies 2013-05-06 17:40:17 +02:00
Daniel Pavel
074cafbab1 simpler (and dumber) way to position receiver windows initially 2013-05-06 17:39:27 +02:00
Daniel Pavel
79cd52833c fix hidconsole for python 2/3 2013-05-06 17:38:09 +02:00
Daniel Pavel
6b75286885 Merge remote-tracking branch 'origin/master' 2013-05-06 17:23:38 +02:00
Daniel Pavel
b884ae039c Merge pull request #40 from Lekensteyn/fixes
Fix window close, fix positioning of new windows
2013-05-06 08:19:27 -07:00
Daniel Pavel
3ecfdd027e handle all 07/0D register notifications 2013-05-06 17:08:58 +02:00
Daniel Pavel
55ca9927b0 python 2/3: fix handling of first argument (unicode) of pack/unpack 2013-05-06 16:50:17 +02:00
Daniel Pavel
b67377c41e minor clean-up in hidconsole 2013-05-06 15:35:47 +02:00
Daniel Pavel
15f24eb26b use 'with' lock syntax instead of acquire/release 2013-05-06 15:35:20 +02:00
Daniel Pavel
0283bb0e91 fix str/unicode detection in Python 3.2 2013-05-06 15:33:42 +02:00
Daniel Pavel
d39c0995b6 Merge remote-tracking branch 'origin/master' 2013-05-06 14:55:21 +02:00
Daniel Pavel
db4c088ce9 Merge pull request #37 from Lekensteyn/py3-compat
Py3 compat: replace use of "unicode" (pwr/Solaar#32)

The `u''` syntax fails in Python 3.2; will fix is_string after the merge.
2013-05-06 05:54:53 -07:00
Daniel Pavel
a4898e24b7 extended documentation of descriptors and registers 2013-05-06 14:51:57 +02:00
Daniel Pavel
086db0d52f Merge pull request #42 from Lekensteyn/doc-updates
performance-mx: dump from scan-registers
2013-05-06 05:47:24 -07:00
Peter Wu
7b3523fb24 performance-mx: dump from scan-registers
Source: https://github.com/pwr/Solaar/issues/27#issuecomment-17472543 and
https://github.com/pwr/Solaar/issues/27#issuecomment-17478409 .
2013-05-06 14:37:28 +02:00
Daniel Pavel
74ca91d611 next version will be 0.8.8 2013-05-06 14:33:06 +02:00
Daniel Pavel
e94d4b28b0 build a proper ghost device when unpairing; fixes #36 2013-05-06 12:06:28 +02:00
Peter Wu
a85aa2da52 scan-registers: determine available notifications
00 is documented in HID++ 1.0 specification, it should be safe to set the 00
register. As another program may have written the notifications register
already and since enabling notifications has side-effects such as "disabling"
certaing functions, restore the flags after reading out available notifs.
2013-05-05 18:16:00 +02:00
Peter Wu
dded8504e6 Fix window positioning of main windows
Previously, the intent was likely to position the receiver window near the
status icon. It did so by calling move followed by present. According to the
Gtk documentation, move() may fail if the window is hidden before.

Therefore present the window *after* determining the position, but *before*
moving it. (presenting the window before getting the position gives a Gtk
warning and has unpredictable behavior wrt. the window position).

As window positioning is now enabled, add additional logic to prevent overlap
of windows: position the first window near the status icon and others on the
left. This is not idea, e.g. when the status icon is on the left side of the
screen, but the idea of positioning windows near to each other is broken anyway.
2013-05-05 11:18:29 +02:00
Peter Wu
a2bad425f6 Fix window close, icon toggle logic
"Toggle" should mean "show or hide all windows", not "flip the visibility state
of windows". Case: one receiver window is open. When a new receiver is
connected, I also expect it to be open. Instead it is hidden, so I click the
icon. Now the new receiver window is shown, but the previous one is hidden.
Huh?! Indeed, let's fix that.
2013-05-05 11:18:29 +02:00
Daniel Pavel
a4ec8ec05d better error dialog on receiver permission error; fixes #17
The problem is caused by starting Solaar right after installing it; while udev
does have the new rule loaded, the /dev/hidraw* device nodes already exist
with the old permissions.

Rather than doing a "udevadm --reload-rules" (which could have unknown side-
effects on other devices), instruct the user to remove and re-insert the usb
receiver. The new /dev/hidraw* device nods will be created with the right
permissions.
2013-05-05 10:35:03 +02:00
Daniel Pavel
1b4bf7918b minor fixes in shell scripts 2013-05-04 19:00:14 +02:00
Daniel Pavel
1f48e44cc6 Merge remote-tracking branch 'origin/master' 2013-05-04 20:20:43 +02:00
Daniel Pavel
83613f02a0 disable info label while we're still reading the info from the device 2013-05-04 20:19:33 +02:00
Daniel Pavel
9d8743e765 comment-out descriptor settings for Anywhere MX, not actually tested 2013-05-04 20:18:10 +02:00
Daniel Pavel
84b9b11ef5 Merge pull request #39 from Lekensteyn/doc-updates
descriptors.py: Clarify use of negative values
2013-05-04 11:14:09 -07:00
Peter Wu
2327a0012e descriptors.py: Clarify use of negative values
The negative behavior is not obvious, document it in the descriptors.py file
such that people who edit it to add new devices know how it works.
2013-05-04 20:02:37 +02:00
Daniel Pavel
4cdd796a3d comment-out some debugging prints 2013-05-04 19:50:50 +02:00
Daniel Pavel
e819265e7e fix automatic register blacklisting 2013-05-04 19:50:08 +02:00
Daniel Pavel
070a96c506 removed dox(x) documentation 2013-05-04 19:42:26 +02:00
Daniel Pavel
e1be54823c updated supported devices documentation 2013-05-04 18:26:09 +02:00
Daniel Pavel
d7dd9393ff minor clean-ups 2013-05-04 17:19:48 +02:00
Daniel Pavel
64c36a1562 updated descriptors table and the devices doc 2013-05-04 17:18:39 +02:00
Daniel Pavel
13a54565ba cleaned-up the descriptors table 2013-05-04 15:09:50 +02:00
Daniel Pavel
12eb17cc41 updated supported devices table 2013-05-04 15:06:55 +02:00
Daniel Pavel
9715dfa126 added a couple of more logitech docs 2013-05-04 15:06:38 +02:00
Daniel Pavel
a6e3689e97 split manual instalation procedure into it's own document 2013-05-04 14:13:31 +02:00
Daniel Pavel
2e5cf81231 split the supporte devices section into separate file
docs/devices.md contains now a few tables with supported devices
and their features (in progress)
2013-05-04 14:06:12 +02:00
Daniel Pavel
4eeca12d6a create and destroy windows on demand
based on receiver added/removed events generated by udev
2013-05-04 12:20:51 +02:00
Daniel Pavel
ad577d22d0 handle sleep in udev monitoring, fixes #35 2013-05-04 12:19:29 +02:00
Daniel Pavel
5e68094e87 split the about window into its own module 2013-05-04 12:01:28 +02:00
Peter Wu
10c26fe642 Py3 compat: replace use of "unicode" (pwr/Solaar#32)
Generating "an unknown notification" type bailed out because of an unknown
feature type None. Since `isinstance(other, str)` is False for None, the script
will raise an exception on `isinstance(other, unicode)`.

There is no differentiation between `str` and `bytes` in Python 2, therefore
add another condition to `NamedInt.__eq__` to catch unknown types (like
`bytes`).
2013-05-03 23:46:46 +02:00
Daniel Pavel
49ecd252ed always log exceptions, even without -v 2013-05-03 18:42:45 +02:00
Daniel Pavel
2ee2a5dc46 Merge remote-tracking branch 'origin/master' 2013-05-03 17:08:32 +02:00
Daniel Pavel
430fdf4fcf initial support for the MOUSE_POINTER hid++2.0 feature 2013-05-03 17:08:26 +02:00
Daniel Pavel
abca81ea38 fix device _match-ing in enumerate() 2013-05-03 16:35:54 +02:00
Daniel Pavel
a0a76f738b assert that data read/written on the receiver handle is of type bytes 2013-05-03 16:35:28 +02:00
Daniel Pavel
7d440c2430 replace thrown OSError with IOError 2013-05-03 16:25:32 +02:00
Daniel Pavel
94274fd092 Merge pull request #34 from Lekensteyn/battery-notif
Refactor battery setter, register 07 processing
2013-05-02 20:40:20 -07:00
Peter Wu
266edd80f3 Process reg07 battery notification 2013-05-03 00:10:58 +02:00
Peter Wu
d1b1be32ca Make read_battery use set_battery_info
This allows battery readouts to generate warnings and debug logs for a given
status and level.
2013-05-02 23:56:08 +02:00
Peter Wu
fbdd923d43 Refactor battery info update
- `self[BATTERY_STATUS] = BATTERY_STATUS[battery_status]` should be:
  `self[BATTERY_STATUS] = _hidpp20.BATTERY_STATUS[battery_status]`, otherwise
  the battery status would be a single char from the string `battery-status`.
- Make `_hidpp20.BATTERY_OK` check against strings instead of a number.
- Move setting battery information to a separate function, `set_battery_info`.
  This prepares for notifications when a battery error/warning occurs.
2013-05-02 23:51:40 +02:00
Daniel Pavel
2c30414f88 Merge pull request #33 from Lekensteyn/py3-hidconsole
Python3 compatibility for hidconsole
2013-05-02 14:23:16 -07:00
Peter Wu
d8e469a33a hidpp10: split reg07 (battery) parsing so it can be reused 2013-05-02 23:06:45 +02:00
Peter Wu
a6b89b3ea3 Python3 compatibility for hidconsole
`type(u'')` is 'str' in Python 3, it was `unicode` on Python 2 (with
`unicode_literals` from `__future__`).
2013-05-02 22:58:35 +02:00
Daniel Pavel
0f80901bce quicker detection of matching receivers in udev 2013-05-02 11:11:53 +02:00
Daniel Pavel
8fc45e5590 fix solaar-cli to handle the new Receiver.open() api 2013-05-01 15:51:12 +02:00
Daniel Pavel
c829304e31 use only udev events to detect receiver devices 2013-05-01 15:47:23 +02:00
Daniel Pavel
d3f94ff2fb detect some HID++1.0 custom battery notifications
they're not handled yet
2013-05-01 11:36:15 +02:00
Daniel Pavel
85d9a9dc27 fix for bug #28 2013-04-30 23:05:26 +02:00
Daniel Pavel
04db6d3838 python 3 fixes for #29 2013-04-30 22:31:06 +02:00
Daniel Pavel
e5a28ac64e simplified window/icon code, reworked how device updates are signalled 2013-04-30 19:44:03 +02:00
Daniel Pavel
2397c6c0ea about dialog updated 2013-04-30 17:25:09 +02:00
Daniel Pavel
c3e6c3d1da more flexible icon loading 2013-04-30 15:45:35 +02:00
Daniel Pavel
22da75cb72 replaced some deprecated GObject calls with GLib 2013-04-30 11:47:30 +02:00
Daniel Pavel
22a8ca37b6 updated FSF address in COPYING 2013-04-29 15:38:15 +02:00
Daniel Pavel
692afba3d9 updated FSF address in COPYING 2013-04-29 15:34:00 +02:00
Daniel Pavel
9c621d5816 always try to initialize systray icon and notifications 2013-04-28 15:44:20 +02:00
Daniel Pavel
feedbcf581 some code clean-ups 2013-04-28 15:16:45 +02:00
Daniel Pavel
a57f3be58d renamed event alert levels to be more clear 2013-04-28 15:12:20 +02:00
Daniel Pavel
897dffc426 only dispatch notification events from the specialized listener thread 2013-04-28 15:09:09 +02:00
Daniel Pavel
6f0b61e6d8 better handling of eq/ne/hash in receiver and device objects 2013-04-28 15:02:17 +02:00
Daniel Pavel
674ee9ac9e split read_battery in status into its own function 2013-04-28 15:01:27 +02:00
Daniel Pavel
5eab013cf6 more explicit logging 2013-04-28 14:58:40 +02:00
Daniel Pavel
079ef8d800 incipient support for the Nano receiver 2013-04-28 14:27:16 +02:00
Daniel Pavel
1a9be279c6 move the code for single-instance check into its own file 2013-04-28 14:06:41 +02:00
Daniel Pavel
f5d2eba0c4 hidapi: dropped native, slight update to the python implementation
added an optional filter for driver name when enumerating devices
2013-04-28 14:05:33 +02:00
Daniel Pavel
e7d19c9084 small fixes to hidconsole 2013-04-28 14:00:46 +02:00
Daniel Pavel
638bf38b25 version increased to 0.8.7.1 2013-04-28 13:59:07 +02:00
Daniel Pavel
c4dc49ac5e Merge pull request #24 from Lekensteyn/hid10-fnkey
Add FN key swap support for K800 (and presumably K710)
2013-04-28 02:03:33 -07:00
Daniel Pavel
926600e29d Merge pull request #26 from Lekensteyn/hid10-battery
Fix battery status reading, add "fully charged"
2013-04-27 23:51:18 -07:00
Peter Wu
5e58f1e273 Fix battery status reading, add "fully charged"
Commit 438c501fae introduced support for HID++ 1.0
battery information. That accidentally selected the third parameter instead of
the second one. This commit fixes that and additionally adds a "fully charged"
status too that was found on the K800.
2013-04-27 17:07:55 +02:00
Peter Wu
c79ad65d37 Add K710 with FN key swap support (pwr/Solaar#18)
The K710 keyboard is (according to the issue reporter) part of a MK710 combo
(which also contains a M705 mouse). Observing a succesful 07 register read,
I think that it is a HID++ 1.0 device too that uses the same register for FN
key swapping as K800.
2013-04-27 15:17:05 +02:00
Peter Wu
95a97ad776 Support FN keys swap for K800 2013-04-27 15:13:42 +02:00
Peter Wu
6c28cedf23 Make BooleanValidator accept bytes too besides int
Previously, only the first parameter byte can be read or written. After this
patch, it is possible to select/write more bytes by specifying a mask of type
bytes with the appropriate length.
2013-04-27 15:12:55 +02:00
Daniel Pavel
a3599b53bb Merge pull request #23 from Lekensteyn/hid10-battery
Parse battery status of HID++ 1.0 devices
2013-04-27 05:20:29 -07:00
Peter Wu
438c501fae Parse battery status of HID++ 1.0 devices
This applies to K800 but it seems also to apply to M510. The numbers are based
on the HID++ 2.0 spec that state the following for GetBatteryCapability:

    If number of levels < 10 or if mileage is disabled then report are
    mapped to 4 levels this way.

    0%->10%     critical
    11%->30%    low
    31%->80%    good
    81%->100%   full

    i.e. to report battery low, FW send 25%, to report battery good, FW send 50%.
2013-04-27 11:58:09 +02:00
Daniel Pavel
25cbd55841 Merge pull request #22 from Lekensteyn/doc-regs
Document registers for K800 and M525
2013-04-27 01:53:16 -07:00
Peter Wu
5ef53f251d Document registers for K800 and M525
See also https://lekensteyn.nl/logitech-unifying.html for tools being used to
draw conclusions. Extended dumps and description can be found on
https://git.lekensteyn.nl/ltunify/tree/registers.txt .
2013-04-27 10:17:36 +02:00
Daniel Pavel
92819b6c9e readme updated 2013-02-24 22:43:16 +01:00
Daniel Pavel
d22674f362 Merge pull request #16 from pivoq/master
Arch Linux package
2013-02-20 10:08:28 -08:00
pivoq
0fc83e9255 add Arch Linux package 2013-02-19 17:38:52 +01:00
pivoq
f171c5d59e add Arch Linux package 2013-02-19 17:15:37 +01:00
Daniel Pavel
78b8299130 readme update 2013-01-25 14:54:48 +02:00
Daniel Pavel
2c7fe0c92d updated gentoo ebuild file 2013-01-18 18:41:15 +02:00
Daniel Pavel
6ff30f2a0e release 0.8.7 2013-01-18 18:37:06 +02:00
Daniel Pavel
7707c5e558 don't notify on device disconnection 2013-01-18 17:41:45 +02:00
Daniel Pavel
9b7a920e0d fix for systray visibility (gihub #14) 2013-01-18 17:18:35 +02:00
Daniel Pavel
2e51380be5 log value of register 0x07 when register 0x0D not available 2013-01-18 12:41:01 +02:00
Daniel Pavel
445f508ea5 readme updates 2013-01-14 20:00:52 +02:00
Daniel Pavel
b82c89c582 release 0.8.6.2 2013-01-09 21:47:59 +02:00
Daniel Pavel
85a47a8049 fixed icon name in desktop file 2013-01-09 21:41:50 +02:00
Daniel Pavel
f8e9798038 gentoo ebuild updated 2013-01-09 21:31:47 +02:00
Daniel Pavel
581d6747ad Merge branch 'nano' into 0.9
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2013-01-09 21:10:39 +02:00
Daniel Pavel
00a1aa7628 release 0.8.6.1 2013-01-09 15:36:15 +02:00
Daniel Pavel
79a9048db5 fixed names for NamedInts numerical values 2013-01-09 15:31:19 +02:00
Daniel Pavel
2bfba2e399 fixed application quit icon 2013-01-09 13:47:30 +02:00
Daniel Pavel
484419e526 release 0.8.6 2013-01-08 00:59:30 +02:00
Daniel Pavel
8c18830c97 added source changelog file 2013-01-08 00:55:47 +02:00
Daniel Pavel
653d370a85 fixed locating application icons when running in a custom prefix 2013-01-08 00:40:54 +02:00
Daniel Pavel
316e91cfcf fixed some icon names 2013-01-08 00:39:13 +02:00
Daniel Pavel
f31632c8c8 debian: make sure the plugdev group exists after installation 2013-01-07 22:09:43 +02:00
Daniel Pavel
bb52c13f9a only allow a single instance of solaar to run at a time 2013-01-07 21:34:47 +02:00
Daniel Pavel
738d43fd83 fix for gihub issue #10
http://github.com/pwr/Solaar/issues/10
2013-01-07 20:14:31 +02:00
Daniel Pavel
1c6c8588d9 release 0.8.5.3, only packaging changes 2013-01-07 13:01:59 +02:00
Daniel Pavel
7a97cb2e02 gentoo ebuild update 2013-01-07 12:43:11 +02:00
Daniel Pavel
5e0d2992c9 small fixes for ubuntu packaging 2013-01-07 12:40:44 +02:00
Daniel Pavel
210859a5ef ignore some development-side directories 2013-01-07 12:05:40 +02:00
Daniel Pavel
25f6d229dd advanced version to account for latest changes in packaging 2013-01-07 12:04:22 +02:00
Daniel Pavel
60405abf58 dropped unnecessary #! in lib/ python files 2013-01-07 11:54:52 +02:00
Daniel Pavel
8070b11c27 customized debian/ and debian packaging script to support ubuntu ppas 2013-01-07 11:46:34 +02:00
Daniel Pavel
7d76ce77c9 packaging updates for debian/ubunutu 2013-01-05 17:40:06 +02:00
Daniel Pavel
3d48cbc111 updated debian packaging script, added ppa build script 2013-01-05 15:50:37 +02:00
Daniel Pavel
36f34da227 proper debian packaging, dropper stdeb 2013-01-05 11:48:35 +02:00
Daniel Pavel
d06e07542e dependency fix for debian package 2013-01-04 12:43:16 +02:00
Daniel Pavel
a0c8646923 Merge branch 'master' into packaging 2013-01-04 11:55:31 +02:00
Daniel Pavel
6c924de209 small readme update 2013-01-04 11:52:17 +02:00
Daniel Pavel
500503c069 release 0.8.5 2013-01-04 11:38:15 +02:00
Daniel Pavel
5dd8cd66dd added smooth scroll setting for the anywhere mx mouse 2013-01-04 11:23:41 +02:00
Daniel Pavel
41e84e55f1 fix hidconsole input 2013-01-04 10:59:00 +02:00
Daniel Pavel
7f8888d7dd added an ebuild script 2013-01-04 10:51:22 +02:00
Daniel Pavel
216928f904 small logging fixes for repr() 2013-01-04 08:25:47 +02:00
Daniel Pavel
345bab3a99 fix code looking for icons 2013-01-04 08:18:22 +02:00
Daniel Pavel
064a7a113c added setup.py for python and debian packaging 2012-12-18 05:03:43 +02:00
205 changed files with 23939 additions and 4411 deletions

34
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,34 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Information**
<!-- Do not bother opening an issue for version 0.9.2 or older, it is extremely outdated. Please update to the latest one and see if your issue persists. -->
- Solaar version (`git describe --tags` if cloned from Solaar repository):
- Distribution:
- Kernel version (ex. `uname -srmo`): `KERNEL VERSION HERE`
- Output of `solaar show`:
```
OUTPUT HERE
```
**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.

View File

@@ -0,0 +1,26 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Information**
- Output of `solaar show` for the target device (if applicable):
```
OUTPUT HERE
```
**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.

15
.gitignore vendored
View File

@@ -1,4 +1,17 @@
*.so
*.pyc
*.pyo
__pycache__/
*.log
*.mo
/lib/Solaar.egg-info/
/lib/solaar.egg-info/
/build/
/sdist/
/dist/
/deb_dist/
/MANIFEST
/docs/captures/
/share/logitech_icons/
/share/locale/

41
COPYING
View File

@@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -15,7 +15,7 @@ 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 Library General Public License instead.) You can apply it to
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
@@ -55,8 +55,8 @@ 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
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
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
@@ -168,7 +168,7 @@ 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
@@ -225,7 +225,7 @@ 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
@@ -255,7 +255,7 @@ 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
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
@@ -277,9 +277,9 @@ 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
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
@@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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 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.
@@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names:
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 Library General
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

14
COPYRIGHT Normal file
View File

@@ -0,0 +1,14 @@
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/>.

144
ChangeLog Normal file
View File

@@ -0,0 +1,144 @@
1.0.2:
* Add usage document
1.0.2rc3:
* 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
1.0.2rc2:
* 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
1.0.2-rc1:
* 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 Croation 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.

3
MANIFEST.in Normal file
View File

@@ -0,0 +1,3 @@
include COPYRIGHT COPYING README.md ChangeLog
recursive-include rules.d *
recursive-include share/locale *

1
README Symbolic link
View File

@@ -0,0 +1 @@
README.md

106
README.md
View File

@@ -1,106 +0,0 @@
**Solaar** is a Linux device manager for Logitech's
[Unifying Receiver](http://www.logitech.com/en-us/66/6079) peripherals. It is
able to pair/unpair devices to the receiver, and for some devices read battery
status.
It comes in two flavors, command-line and GUI. Both are able to list the
devices paired to a Unifying Receiver, show detailed info for each device, and
also pair/unpair supported devices with the receiver.
## Supported Devices
**Solaar** will detect all devices paired with your Unifying Receiver, and at
the very least display some basic information about them. Depending on the
device, it may be able to read its battery status.
A few devices also have extended support, mostly because I was able to directly
test on them:
* The [K750 Solar Keyboard](http://www.logitech.com/keyboards/keyboard/devices/7454)
is also queried for its solar charge status. Pressing the Solar key on the
keyboard will pop-up the application window and display the current lighting
value (Lux) as reported by the keyboard, similar to Logitech's *Solar.app* for
Windows.
Also, you can change the way the function keys (`F1`..`F12`) work, i.e.
whether holding `FN` while pressing the function keys will generate the
standard keycodes or the special function (yellow icons) keycodes.
* The [M705 Marathon Mouse](http://www.logitech.com/product/marathon-mouse-m705)
supports turning on/off Smooth Scrolling (higher sensitivity on vertical
scrolling with the wheel).
Extended support for other devices may be added in the future, depending on the
documentation available, but the K750 keyboard and M705 mouse are the only
devices I have and can test on right now.
## Requirements
You should have a reasonably new kernel (3.2+), with the `logitech-djreceiver`
driver enabled and loaded; also, the `udev` package must be installed and the
daemon running. If you have a modern Linux distribution (2011+), you're most
likely good to go.
The command-line application (`bin/solaar-cli`) requires Python 2.7.3 or 3.2+
(either version should work), and the `python-pyudev`/`python3-pyudev` package.
The GUI application (`bin/solaar`) also requires Gtk3, and its GObject
Introspection bindings. The Debian/Ubuntu package names are
`python-gi`/`python3-gi` and `gir1.2-gtk-3.0`; if you're using another
distribution the required packages are most likely named something similar.
If the desktop notifications bindings are also installed (`gir1.2-notify-0.7`),
you will also get desktop notifications when devices come online/go offline.
## Installation
Normally USB devices are not accessible for r/w by regular users, so you will
need to do a one-time udev rule installation to allow access to the Logitech
Unifying Receiver.
You can run the `rules.d/install.sh` script from Solaar to do this installation
automatically (it will switch to root when necessary), or you can do all the
required steps by hand, as the root user:
1. copy `rules.d/99-logitech-unfiying-receiver.rules` from Solaar to
`/etc/udev/rules.d/`
By default, the rule makes the Unifying Receiver device available for r/w by
all users belonging to the `plugdev` system group (standard Debian/Ubuntu
group for pluggable devices). It may need changes, specific to your
particular system's configuration. If in doubt, replacing `GROUP="plugdev"`
with `GROUP="<your username>"` should just work.
2. run `udevadm control --reload-rules` to let the udev daemon know about the new
rule
3. physically remove the Unifying Receiver, wait 10 seconds and re-insert it
## Known Issues
- When running under Ubuntu's Unity, the tray icon will probably not appear, nor
will the application window. Either run the application with the '-S' option,
or whitelist "Solaar" into the systray. For details, see
[How do I access and enable more icons to be in the system tray?](http://askubuntu.com/questions/30742/how-do-i-access-and-enable-more-icons-to-be-in-the-system-tray).
Support for Unity's indicators is a planned feature.
- Running the command-line application (`bin/solaar-cli`) while the GUI
application is also running *may* occasionally cause either of them to become
confused about the state of the devices. I haven't encountered this often
enough to be able to be able to diagnose it properly yet.
## Thanks
This project began as a third-hand clone of [Noah K. Tilton](https://github.com/noah)'s
logitech-solar-k750 project on GitHub (no longer available). It was developed
further thanks to the diggings in Logitech's HID++ protocol done by many other
people:
- [Julien Danjou](http://julien.danjou.info/blog/2012/logitech-k750-linux-support),
who also provided some internal
[Logitech documentation](http://julien.danjou.info/blog/2012/logitech-unifying-upower)
- [Lars-Dominik Braun](http://6xq.net/git/lars/lshidpp.git)
- [Alexander Hofbauer](http://derhofbauer.at/blog/blog/2012/08/28/logitech-performance-mx)
- [Clach04](http://bitbucket.org/clach04/logitech-unifying-receiver-tools)
Also thanks to Douglas Wagner and Julien Gascard for helping with application
testing and supporting new devices.

1
README.md Symbolic link
View File

@@ -0,0 +1 @@
docs/index.md

15
RELEASE.md Normal file
View File

@@ -0,0 +1,15 @@
# 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 ChangeLog, setup.py, lib/solaar/__init__.py, and docs/_config.yml to the new version
- 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 have a github token with `public_repo` access
in `~/.github-token`

View File

@@ -1,157 +0,0 @@
#
#
#
from __future__ import absolute_import, division, print_function, unicode_literals
from logging import getLogger, DEBUG as _DEBUG
_log = getLogger('listener')
del getLogger
from logitech.unifying_receiver import (Receiver,
listener as _listener,
status as _status)
#
#
#
from collections import namedtuple
_GHOST_DEVICE = namedtuple('_GHOST_DEVICE', ['number', 'name', 'kind', 'status', 'max_devices'])
_GHOST_DEVICE.__bool__ = lambda self: False
_GHOST_DEVICE.__nonzero__ = _GHOST_DEVICE.__bool__
del namedtuple
def _ghost(device):
return _GHOST_DEVICE(number=device.number, name=device.name, kind=device.kind, status=None, max_devices=None)
DUMMY = _GHOST_DEVICE(Receiver.number, Receiver.name, None, 'Receiver not found.', Receiver.max_devices)
#
#
#
# how often to poll devices that haven't updated their statuses on their own
# (through notifications)
_POLL_TICK = 60 # seconds
class ReceiverListener(_listener.EventsListener):
"""Keeps the status of a Unifying Receiver.
"""
def __init__(self, receiver, status_changed_callback=None):
super(ReceiverListener, self).__init__(receiver, self._notifications_handler)
self.tick_period = _POLL_TICK
self._last_tick = 0
self.status_changed_callback = status_changed_callback
# make it a bit similar with the regular devices
receiver.kind = None
# replace the
receiver.handle = _listener.ThreadedHandle(receiver.handle, receiver.path)
receiver.status = _status.ReceiverStatus(receiver, self._status_changed)
def has_started(self):
_log.info("notifications listener has started")
self.receiver.enable_notifications()
self.receiver.notify_devices()
self._status_changed(self.receiver, _status.ALERT.LOW)
def has_stopped(self):
_log.info("notifications listener has stopped")
if self.receiver:
self.receiver.enable_notifications(False)
self.receiver.close()
self.receiver = None
self._status_changed(None, _status.ALERT.LOW)
def tick(self, timestamp):
if _log.isEnabledFor(_DEBUG):
_log.debug("polling status: %s %s", self.receiver, list(iter(self.receiver)))
if self._last_tick > 0 and timestamp - self._last_tick > _POLL_TICK * 3:
# if we missed a couple of polls, most likely the computer went into
# sleep, and we have to reinitialize the receiver again
_log.warn("possible sleep detected, closing this listener")
self.stop()
return
self._last_tick = timestamp
# read these in case they haven't been read already
self.receiver.serial, self.receiver.firmware
if self.receiver.status.lock_open:
# don't mess with stuff while pairing
return
for dev in self.receiver:
if dev.status is not None:
dev.status.poll(timestamp)
def _status_changed(self, device, alert=_status.ALERT.NONE, reason=None):
if _log.isEnabledFor(_DEBUG):
_log.debug("status_changed %s: %s %s (%X) %s", device,
None if device is None else 'active' if device.status else 'inactive',
None if device is None else device.status,
alert, reason or '')
if self.status_changed_callback:
r = self.receiver or DUMMY
if device is None or device.kind is None:
# the status of the receiver changed
self.status_changed_callback(r, None, alert, reason)
else:
if device.status is None:
# device was unpaired, and since the object is weakref'ed
# it won't be valid for much longer
device = _ghost(device)
self.status_changed_callback(r, device, alert, reason)
if device.status is None:
# the receiver changed status as well
self.status_changed_callback(r)
def _notifications_handler(self, n):
assert self.receiver
if n.devnumber == 0xFF:
# a receiver notification
if self.receiver.status is not None:
self.receiver.status.process_notification(n)
else:
# a device notification
assert n.devnumber > 0 and n.devnumber <= self.receiver.max_devices
already_known = n.devnumber in self.receiver
dev = self.receiver[n.devnumber]
if not dev:
_log.warn("received %s for invalid device %d: %s", n, n.devnumber, repr(dev))
return
if not already_known:
# read these as soon as possible, they will be used everywhere
dev.protocol, dev.codename
dev.status = _status.DeviceStatus(dev, self._status_changed)
# the receiver changed status as well
self._status_changed(self.receiver)
# status may be None if the device has just been unpaired
if dev.status is not None:
dev.status.process_notification(n)
if self.receiver.status.lock_open and not already_known:
# this should be the first notification after a device was paired
assert n.sub_id == 0x41 and n.address == 0x04
_log.info("pairing detected new device")
self.receiver.status.new_device = dev
def __str__(self):
return '<ReceiverListener(%s,%s)>' % (self.receiver.path, self.receiver.handle)
__unicode__ = __str__
@classmethod
def open(self, status_changed_callback=None):
receiver = Receiver.open()
if receiver:
rl = ReceiverListener(receiver, status_changed_callback)
rl.start()
return rl

View File

@@ -1,128 +0,0 @@
#!/usr/bin/env python -u
from __future__ import absolute_import, division, print_function, unicode_literals
NAME = 'Solaar'
VERSION = '0.8.4'
__author__ = "Daniel Pavel <daniel.pavel@gmail.com>"
__version__ = VERSION
__license__ = "GPL"
#
#
#
def _require(module, os_package):
try:
__import__(module)
except ImportError:
import sys
sys.exit("%s: missing required package '%s'" % (NAME, os_package))
def _parse_arguments():
import argparse
arg_parser = argparse.ArgumentParser(prog=NAME.lower())
arg_parser.add_argument('-S', '--no-systray', action='store_false', dest='systray',
help='do not place an icon in the desktop\'s systray')
arg_parser.add_argument('-N', '--no-notifications', action='store_false', dest='notifications',
help='disable desktop notifications (shown only when in systray)')
arg_parser.add_argument('-d', '--debug', action='count', default=0,
help='print logging messages, for debugging purposes (may be repeated for extra verbosity)')
arg_parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__)
args = arg_parser.parse_args()
import logging
if args.debug > 0:
log_level = logging.WARNING - 10 * args.debug
log_format='%(asctime)s %(levelname)8s [%(threadName)s] %(name)s: %(message)s'
logging.basicConfig(level=max(log_level, logging.DEBUG), format=log_format)
else:
logging.root.addHandler(logging.NullHandler())
logging.root.setLevel(logging.CRITICAL)
return args
def _run(args):
import ui
# even if --no-notifications is given on the command line, still have to
# check they are available, and decide whether to put the option in the
# systray icon
args.notifications &= args.systray
if args.systray and ui.notify.init(NAME):
ui.action.toggle_notifications.set_active(args.notifications)
if not args.notifications:
ui.notify.uninit()
else:
ui.action.toggle_notifications = None
from listener import DUMMY
window = ui.main_window.create(NAME, DUMMY.name, DUMMY.max_devices, args.systray)
if args.systray:
menu_actions = (ui.action.toggle_notifications,
ui.action.about)
icon = ui.status_icon.create(window, menu_actions)
else:
icon = None
from gi.repository import Gtk, GObject
# initializes the receiver listener
def check_for_listener(notify=False):
# print ("check_for_listener", notify)
global listener
listener = None
from listener import ReceiverListener
try:
listener = ReceiverListener.open(status_changed)
except OSError:
ui.error(window, 'Permissions error',
'Found a possible Unifying Receiver device,\n'
'but did not have permission to open it.')
if listener is None:
if notify:
status_changed(DUMMY)
else:
return True
from logitech.unifying_receiver import status
# callback delivering status notifications from the receiver/devices to the UI
def status_changed(receiver, device=None, alert=status.ALERT.NONE, reason=None):
if alert & status.ALERT.MED:
GObject.idle_add(window.present)
if window:
GObject.idle_add(ui.main_window.update, window, receiver, device)
if icon:
GObject.idle_add(ui.status_icon.update, icon, receiver, device)
if ui.notify.available:
# always notify on receiver updates
if device is None or alert & status.ALERT.LOW:
GObject.idle_add(ui.notify.show, device or receiver, reason)
if receiver is DUMMY:
GObject.timeout_add(3000, check_for_listener)
GObject.timeout_add(10, check_for_listener, True)
Gtk.main()
if listener:
listener.stop()
listener.join()
ui.notify.uninit()
if __name__ == '__main__':
_require('pyudev', 'python-pyudev')
_require('gi.repository', 'python-gi')
_require('gi.repository.Gtk', 'gir1.2-gtk-3.0')
args = _parse_arguments()
listener = None
_run(args)

View File

@@ -1,384 +0,0 @@
#!/usr/bin/env python -u
from __future__ import absolute_import, division, print_function, unicode_literals
import sys
import solaar
NAME = 'solaar-cli'
__author__ = solaar.__author__
__version__ = solaar.__version__
__license__ = solaar.__license__
del solaar
#
#
#
def _fail(text):
sys.exit("%s: error: %s" % (NAME, text))
def _require(module, os_package):
try:
__import__(module)
except ImportError:
_fail("missing required package '%s'" % os_package)
#
#
#
def _receiver():
from logitech.unifying_receiver import Receiver
try:
r = Receiver.open()
except Exception as e:
_fail(str(e))
if r is None:
_fail("Logitech Unifying Receiver not found")
return r
def _find_device(receiver, name, may_be_receiver=False):
if len(name) == 1:
try:
number = int(name)
except:
pass
else:
if number in range(1, 1 + receiver.max_devices):
dev = receiver[number]
if dev is None:
_fail("no paired device with number", number)
return dev
if len(name) < 3:
_fail("need at least 3 characters to match a device")
name = name.lower()
if may_be_receiver and ('receiver'.startswith(name) or name == receiver.serial.lower()):
return receiver
for dev in receiver:
if (name == dev.serial.lower() or
name == dev.codename.lower() or
name == str(dev.kind).lower() or
name in dev.name.lower()):
return dev
_fail("no device found matching '%s'" % name)
def _print_receiver(receiver, verbose=False):
paired_count = receiver.count()
if not verbose:
print ("-: Unifying Receiver [%s:%s] with %d devices" % (receiver.path, receiver.serial, paired_count))
return
print ("-: Unifying Receiver")
print (" Device path :", receiver.path)
print (" Serial :", receiver.serial)
for f in receiver.firmware:
print (" %-11s: %s" % (f.kind, f.version))
print (" Has", paired_count, "paired device(s).")
notification_flags = receiver.request(0x8100)
if notification_flags:
notification_flags = ord(notification_flags[0:1]) << 16 | ord(notification_flags[1:2]) << 8
if notification_flags:
from logitech.unifying_receiver import hidpp10
notification_names = hidpp10.NOTIFICATION_FLAG.flag_names(notification_flags)
print (" Enabled notifications: 0x%06X = %s." % (notification_flags, ', '.join(notification_names)))
else:
print (" All notifications disabled.")
if paired_count > 0:
activity = receiver.request(0x83B3)
if activity:
activity = [(d, ord(activity[d - 1:d])) for d in range(1, receiver.max_devices)]
print (" Device activity counters:", ', '.join(('%d=%d' % (d, a)) for d, a in activity if a > 0))
def _print_device(dev, verbose=False):
p = dev.protocol
state = '' if p > 0 else 'inactive'
if not verbose:
print ("%d: %s [%s:%s]" % (dev.number, dev.name, dev.codename, dev.serial), state)
return
print ("%d: %s" % (dev.number, dev.name))
print (" Codename :", dev.codename)
print (" Kind :", dev.kind)
if p == 0:
print (" Protocol : unknown (device is inactive)")
else:
print (" Protocol : HID++ %1.1f" % p)
print (" Polling rate :", dev.polling_rate, "ms")
print (" Wireless PID :", dev.wpid)
print (" Serial number:", dev.serial)
for fw in dev.firmware:
print (" %-11s:" % fw.kind, (fw.name + ' ' + fw.version).strip())
if dev.power_switch_location:
print (" The power switch is located on the", dev.power_switch_location)
from logitech.unifying_receiver import hidpp10, hidpp20
if p > 0:
if dev.features:
print (" Supports %d HID++ 2.0 features:" % len(dev.features))
for index, feature in enumerate(dev.features):
feature = dev.features[index]
flags = dev.request(0x0000, feature.bytes(2))
flags = 0 if flags is None else ord(flags[1:2])
flags = hidpp20.FEATURE_FLAG.flag_names(flags)
print (" %2d: %-20s {%04X} %s" % (index, feature, feature, ', '.join(flags)))
if dev.keys:
print (" Has %d reprogrammable keys:" % len(dev.keys))
for k in dev.keys:
flags = hidpp20.KEY_FLAG.flag_names(k.flags)
print (" %2d: %-20s => %-20s %s" % (k.index, k.key, k.task, ', '.join(flags)))
if p > 0:
battery = hidpp20.get_battery(dev)
if battery is None:
battery = hidpp10.get_battery(dev)
if battery:
charge, status = battery
print (" Battery is %d%% charged," % charge, status)
else:
print (" Battery status unavailable.")
else:
print (" Battery status is unknown (device is inactive).")
#
#
#
def show_devices(receiver, args):
if args.device == 'all':
_print_receiver(receiver, args.verbose)
for dev in receiver:
if args.verbose:
print ("")
_print_device(dev, args.verbose)
else:
dev = _find_device(receiver, args.device, True)
if dev is receiver:
_print_receiver(receiver, args.verbose)
else:
_print_device(dev, args.verbose)
def pair_device(receiver, args):
# get all current devices
known_devices = [dev.number for dev in receiver]
from logitech.unifying_receiver import status
r_status = status.ReceiverStatus(receiver, lambda *args, **kwargs: None)
done = [False]
def _notification_handler(n):
if n.devnumber == 0xFF:
r_status.process_notification(n)
if not r_status.lock_open:
done[0] = True
elif n.sub_id == 0x41 and n.address == 0x04:
if n.devnumber not in known_devices:
r_status.new_device = receiver[n.devnumber]
from logitech.unifying_receiver import base
base.notifications_hook = _notification_handler
# check if it's necessary to set the notification flags
notification_flags = receiver.request(0x8100)
if notification_flags:
# just to see if any bits are set
notification_flags = ord(notification_flags[:1]) + ord(notification_flags[1:2]) + ord(notification_flags[2:3])
if not notification_flags:
# if there are any notifications set, just assume the one we need is already set
receiver.enable_notifications()
receiver.set_lock(False, timeout=20)
print ("Pairing: turn your new device on (timing out in 20 seconds).")
while not done[0]:
n = base.read(receiver.handle, 2000)
if n:
n = base.make_notification(*n)
if n:
_notification_handler(n)
if not notification_flags:
# only clear the flags if they weren't set before, otherwise a
# concurrently running Solaar app will stop working properly
receiver.enable_notifications(False)
base.notifications_hook = None
if r_status.new_device:
dev = r_status.new_device
print ("Paired device %d: %s [%s:%s]" % (dev.number, dev.name, dev.codename, dev.serial))
else:
_fail(r_status[status.ERROR])
def unpair_device(receiver, args):
dev = _find_device(receiver, args.device)
# query these now, it's last chance to get them
number, name, codename, serial = dev.number, dev.name, dev.codename, dev.serial
try:
del receiver[number]
print ("Unpaired %d: %s [%s:%s]" % (number, name, codename, serial))
except Exception as e:
_fail("failed to unpair device %s: %s" % (dev.name, e))
def config_device(receiver, args):
dev = _find_device(receiver, args.device)
# if dev is receiver:
# _fail("no settings for the receiver")
if not dev.settings:
_fail("no settings for %s" % dev.name)
if not args.setting:
print ("[%s:%s]" % (dev.serial, dev.kind))
print ("#", dev.name)
for s in dev.settings:
print ("")
print ("# %s" % s.label)
if s.choices:
print ("# possible values: one of [", ', '.join(str(v) for v in s.choices), "], or higher/lower/highest/max/lowest/min")
else:
print ("# possible values: true/t/yes/y/1 or false/f/no/n/0")
value = s.read()
if value is None:
print ("# %s = ? (failed to read from device)" % s.name)
else:
print (s.name, "=", value)
return
setting = None
for s in dev.settings:
if args.setting.lower() == s.name.lower():
setting = s
break
if setting is None:
_fail("no setting '%s' for %s" % (args.setting, dev.name))
if args.value is None:
result = setting.read()
if result is None:
_fail("failed to read '%s'" % setting.name)
print ("%s = %s" % (setting.name, setting.read()))
return
from logitech.unifying_receiver import settings as _settings
if setting.kind == _settings.KIND.toggle:
value = args.value
try:
value = bool(int(value))
except:
if value.lower() in ['1', 'true', 'yes', 't', 'y']:
value = True
elif value.lower() in ['0', 'false', 'no', 'f', 'n']:
value = False
else:
_fail("don't know how to interpret '%s' as boolean" % value)
elif setting.choices:
value = args.value.lower()
if value in ['higher', 'lower']:
old_value = setting.read()
if old_value is None:
_fail("could not read current value of '%s'" % setting.name)
if value == 'lower':
lower_values = setting.choices[:old_value]
value = lower_values[-1] if lower_values else setting.choices[:][0]
elif value == 'higher':
higher_values = setting.choices[old_value + 1:]
value = higher_values[0] if higher_values else setting.choices[:][-1]
elif value in ('highest', 'max'):
value = setting.choices[:][-1]
elif value in ('lowest', 'min'):
value = setting.choices[:][0]
elif value not in setting.choices:
_fail("possible values for '%s' are: [%s]" % (setting.name, ', '.join(str(v) for v in setting.choices)))
value = setting.choices[value]
else:
raise NotImplemented
result = setting.write(value)
if result is None:
_fail("failed to set '%s' = '%s' [%s]" % (setting.name, value, repr(value)))
print ("%s = %s" % (setting.name, result))
#
#
#
def _parse_arguments():
import argparse
arg_parser = argparse.ArgumentParser(prog=NAME.lower())
arg_parser.add_argument('-d', '--debug', action='count', default=0,
help='print logging messages, for debugging purposes (may be repeated for extra verbosity)')
arg_parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__)
subparsers = arg_parser.add_subparsers(title='commands')
sp = subparsers.add_parser('show', help='show information about paired devices')
sp.add_argument('device', nargs='?', default='all',
help='device to show information about; may be a device number (1..6), a device serial, '
'at least 3 characters of a device\'s name, "receiver", or "all" (the default)')
sp.add_argument('-v', '--verbose', action='store_true',
help='print all available information about the inspected device(s)')
sp.set_defaults(cmd=show_devices)
sp = subparsers.add_parser('config', help='read/write device-specific settings',
epilog='Please note that configuration only works on active devices.')
sp.add_argument('device',
help='device to configure; may be a device number (1..6), a device serial, '
'or at least 3 characters of a device\'s name')
sp.add_argument('setting', nargs='?',
help='device-specific setting; leave empty to list available settings')
sp.add_argument('value', nargs='?',
help='new value for the setting')
sp.set_defaults(cmd=config_device)
sp = subparsers.add_parser('pair', help='pair a new device',
epilog='The Logitech Unifying Receiver supports up to 6 paired devices at the same time.')
sp.set_defaults(cmd=pair_device)
sp = subparsers.add_parser('unpair', help='unpair a device')
sp.add_argument('device',
help='device to unpair; may be a device number (1..6), a device serial, '
'or at least 3 characters of a device\'s name.')
sp.set_defaults(cmd=unpair_device)
args = arg_parser.parse_args()
import logging
if args.debug > 0:
log_level = logging.WARNING - 10 * args.debug
log_format='%(asctime)s %(levelname)8s %(name)s: %(message)s'
logging.basicConfig(level=max(log_level, logging.DEBUG), format=log_format)
else:
logging.root.addHandler(logging.NullHandler())
logging.root.setLevel(logging.CRITICAL)
return args
if __name__ == '__main__':
_require('pyudev', 'python-pyudev')
args = _parse_arguments()
receiver = _receiver()
args.cmd(receiver, args)

View File

@@ -1,111 +0,0 @@
#
#
#
from __future__ import absolute_import, division, print_function, unicode_literals
from gi.repository import GObject, Gtk
GObject.threads_init()
_LARGE_SIZE = 64
Gtk.IconSize.LARGE = Gtk.icon_size_register('large', _LARGE_SIZE, _LARGE_SIZE)
# Gtk.IconSize.XLARGE = Gtk.icon_size_register('x-large', _LARGE_SIZE * 2, _LARGE_SIZE * 2)
from . import notify, status_icon, main_window, pair_window, action
from solaar import NAME
APP_ICON = { 1: NAME, 2: NAME + '-mask', 0: NAME + '-init', -1: NAME + '-fail' }
def get_battery_icon(level):
if level < 0:
return 'battery_unknown'
return 'battery_%03d' % (10 * ((level + 5) // 10))
_ICON_SETS = {}
def device_icon_set(name, kind=None):
icon_set = _ICON_SETS.get(name)
if icon_set is None:
icon_set = Gtk.IconSet.new()
_ICON_SETS[name] = icon_set
names = ['preferences-desktop-peripherals']
if kind:
if str(kind) == 'numpad':
names += ('input-dialpad',)
elif str(kind) == 'touchpad':
names += ('input-tablet',)
elif str(kind) == 'trackball':
names += ('input-mouse',)
names += ('input-' + str(kind),)
theme = Gtk.IconTheme.get_default()
if theme.has_icon(name):
names += (name,)
source = Gtk.IconSource.new()
for n in names:
source.set_icon_name(n)
icon_set.add_source(source)
icon_set.names = names
return icon_set
def device_icon_file(name, kind=None):
icon_set = device_icon_set(name, kind)
assert icon_set
theme = Gtk.IconTheme.get_default()
for n in reversed(icon_set.names):
if theme.has_icon(n):
return theme.lookup_icon(n, _LARGE_SIZE, 0).get_filename()
def icon_file(name, size=_LARGE_SIZE):
theme = Gtk.IconTheme.get_default()
if theme.has_icon(name):
return theme.lookup_icon(name, size, 0).get_filename()
def error(window, title, text):
m = Gtk.MessageDialog(window, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, text)
m.set_title(title)
m.run()
m.destroy()
def remove_children(container):
container.foreach(lambda x, _: container.remove(x), None)
# def find_children(container, *child_names):
# assert container is not None
# assert isinstance(container, Gtk.Container)
#
# def _iterate_children(widget, names, result, count):
# assert isinstance(widget, Gtk.Widget)
# wname = widget.get_name()
# if wname in names:
# index = names.index(wname)
# names[index] = None
# result[index] = widget
# count -= 1
#
# if count > 0 and isinstance(widget, Gtk.Container):
# for w in widget:
# # assert isinstance(w, Gtk.Widget):
# count = _iterate_children(w, names, result, count)
# if count == 0:
# break
#
# return count
#
# names = list(child_names)
# count = len(names)
# result = [None] * count
# if _iterate_children(container, names, result, count) > 0:
# # some children could not be found
# pass
# return tuple(result) if count > 1 else result[0]

View File

@@ -1,113 +0,0 @@
#
#
#
from __future__ import absolute_import, division, print_function, unicode_literals
# from sys import version as PYTHON_VERSION
from gi.repository import Gtk, Gdk
import ui
from solaar import NAME as _NAME
from solaar import VERSION as _VERSION
def _action(name, label, function, *args):
action = Gtk.Action(name, label, label, None)
action.set_icon_name(name)
if function:
action.connect('activate', function, *args)
return action
def _toggle_action(name, label, function, *args):
action = Gtk.ToggleAction(name, label, label, None)
action.set_icon_name(name)
action.connect('activate', function, *args)
return action
#
#
#
def _toggle_notifications(action):
if action.get_active():
ui.notify.init(_NAME)
else:
ui.notify.uninit()
action.set_sensitive(ui.notify.available)
toggle_notifications = _toggle_action('notifications', 'Notifications', _toggle_notifications)
def _show_about_window(action):
about = Gtk.AboutDialog()
about.set_icon_name(_NAME)
about.set_program_name(_NAME)
about.set_logo_icon_name(_NAME)
about.set_version(_VERSION)
about.set_comments('Shows status of devices connected\nto a Logitech Unifying Receiver.')
about.set_copyright(b'\xC2\xA9'.decode('utf-8') + ' 2012 Daniel Pavel')
about.set_license_type(Gtk.License.GPL_2_0)
about.set_authors(('Daniel Pavel http://github.com/pwr',))
try:
about.add_credit_section('Testing', ('Douglas Wagner', 'Julien Gascard'))
about.add_credit_section('Technical specifications\nprovided by',
('Julien Danjou http://julien.danjou.info/blog/2012/logitech-unifying-upower',))
except TypeError:
# gtk3 < 3.6 has incorrect gi bindings
pass
except:
# is the Gtk3 version too old?
pass
about.set_website('http://pwr.github.com/Solaar/')
about.set_website_label('Solaar')
about.run()
about.destroy()
about = _action('help-about', 'About ' + _NAME, _show_about_window)
quit = _action('exit', 'Quit', Gtk.main_quit)
#
#
#
def _pair_device(action, frame):
window = frame.get_toplevel()
pair_dialog = ui.pair_window.create(action, frame._device)
pair_dialog.set_transient_for(window)
pair_dialog.set_destroy_with_parent(True)
pair_dialog.set_modal(True)
pair_dialog.set_type_hint(Gdk.WindowTypeHint.DIALOG)
pair_dialog.set_position(Gtk.WindowPosition.CENTER)
pair_dialog.present()
def pair(frame):
return _action('add', 'Pair new device', _pair_device, frame)
def _unpair_device(action, frame):
window = frame.get_toplevel()
# window.present()
device = frame._device
qdialog = Gtk.MessageDialog(window, 0,
Gtk.MessageType.QUESTION, Gtk.ButtonsType.NONE,
"Unpair device\n%s ?" % device.name)
qdialog.set_icon_name('remove')
qdialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
qdialog.add_button('Unpair', Gtk.ResponseType.ACCEPT)
choice = qdialog.run()
qdialog.destroy()
if choice == Gtk.ResponseType.ACCEPT:
try:
del device.receiver[device.number]
except:
ui.error(window, 'Unpairing failed', 'Failed to unpair device\n%s .' % device.name)
def unpair(frame):
return _action('edit-delete', 'Unpair', _unpair_device, frame)

View File

@@ -1,198 +0,0 @@
#
#
#
from __future__ import absolute_import, division, print_function, unicode_literals
from gi.repository import Gtk, GObject
import ui
from logitech.unifying_receiver import settings as _settings
#
#
#
try:
from Queue import Queue as _Queue
except ImportError:
from queue import Queue as _Queue
_apply_queue = _Queue(4)
def _process_apply_queue():
def _write_start(sbox):
_, failed, spinner, control = sbox.get_children()
control.set_sensitive(False)
failed.set_visible(False)
spinner.set_visible(True)
spinner.start()
while True:
task = _apply_queue.get()
assert isinstance(task, tuple)
# print ("task", *task)
if task[0] == 'write':
_, setting, value, sbox = task
GObject.idle_add(_write_start, sbox, priority=0)
value = setting.write(value)
elif task[0] == 'read':
_, setting, force_read, sbox = task
value = setting.read(not force_read)
GObject.idle_add(_update_setting_item, sbox, value, priority=99)
from threading import Thread as _Thread
_queue_processor = _Thread(name='SettingsProcessor', target=_process_apply_queue)
_queue_processor.daemon = True
_queue_processor.start()
#
#
#
def _switch_notify(switch, _, setting, spinner):
# print ("switch notify", switch, switch.get_active(), setting)
if switch.get_sensitive():
# value = setting.write(switch.get_active() == True)
# _update_setting_item(switch.get_parent(), value)
_apply_queue.put(('write', setting, switch.get_active() == True, switch.get_parent()))
def _combo_notify(cbbox, setting, spinner):
# print ("combo notify", cbbox, cbbox.get_active_id(), setting)
if cbbox.get_sensitive():
_apply_queue.put(('write', setting, cbbox.get_active_id(), cbbox.get_parent()))
# def _scale_notify(scale, setting, spinner):
# _apply_queue.put(('write', setting, scale.get_value(), scale.get_parent()))
# def _snap_to_markers(scale, scroll, value, setting):
# value = int(value)
# candidate = None
# delta = 0xFFFFFFFF
# for c in setting.choices:
# d = abs(value - int(c))
# if d < delta:
# candidate = c
# delta = d
# assert candidate is not None
# scale.set_value(int(candidate))
# return True
def _add_settings(box, device):
for s in device.settings:
sbox = Gtk.HBox(homogeneous=False, spacing=8)
sbox.pack_start(Gtk.Label(s.label), False, False, 0)
spinner = Gtk.Spinner()
spinner.set_tooltip_text('Working...')
failed = Gtk.Image.new_from_icon_name('dialog-warning', Gtk.IconSize.SMALL_TOOLBAR)
failed.set_tooltip_text('Failed to read value from the device.')
if s.kind == _settings.KIND.toggle:
control = Gtk.Switch()
control.connect('notify::active', _switch_notify, s, spinner)
elif s.kind == _settings.KIND.choice:
control = Gtk.ComboBoxText()
for entry in s.choices:
control.append(str(entry), str(entry))
control.connect('changed', _combo_notify, s, spinner)
# elif s.kind == _settings.KIND.range:
# first, second = s.choices[:2]
# last = s.choices[-1:][0]
# control = Gtk.HScale.new_with_range(first, last, second - first)
# control.set_draw_value(False)
# control.set_has_origin(False)
# for entry in s.choices:
# control.add_mark(int(entry), Gtk.PositionType.TOP, str(entry))
# control.connect('change-value', _snap_to_markers, s)
# control.connect('value-changed', _scale_notify, s, spinner)
else:
raise NotImplemented
control.set_sensitive(False) # the first read will enable it
sbox.pack_end(control, False, False, 0)
sbox.pack_end(spinner, False, False, 0)
sbox.pack_end(failed, False, False, 0)
if s.description:
sbox.set_tooltip_text(s.description)
sbox.show_all()
spinner.start() # the first read will stop it
failed.set_visible(False)
box.pack_start(sbox, False, False, 0)
yield sbox
def _update_setting_item(sbox, value):
_, failed, spinner, control = sbox.get_children()
spinner.set_visible(False)
spinner.stop()
# print ("update", control, "with new value", value)
if value is None:
control.set_sensitive(False)
failed.set_visible(True)
return
failed.set_visible(False)
if isinstance(control, Gtk.Switch):
control.set_active(value)
elif isinstance(control, Gtk.ComboBoxText):
control.set_active_id(str(value))
# elif isinstance(control, Gtk.Scale):
# control.set_value(int(value))
else:
raise NotImplemented
control.set_sensitive(True)
#
#
#
def create():
b = Gtk.VBox(homogeneous=False, spacing=4)
b.set_property('margin', 8)
return b
def update(frame):
box = frame._config_box
assert box
device = frame._device
if device is None:
# remove all settings widgets
# if another device gets paired here, it will add its own widgets
ui.remove_children(box)
return
if not box.get_visible():
# no point in doing this right now, is there?
return
if not device.settings:
# nothing to do here
return
force_read = False
items = box.get_children()
if len(device.settings) != len(items):
ui.remove_children(box)
if device.status:
items = list(_add_settings(box, device))
assert len(device.settings) == len(items)
force_read = True
device_active = bool(device.status)
# if the device just became active, re-read the settings
force_read |= device_active and not box.get_sensitive()
box.set_sensitive(device_active)
if device_active:
for sbox, s in zip(items, device.settings):
_apply_queue.put(('read', s, force_read, sbox))

View File

@@ -1,434 +0,0 @@
#
#
#
from __future__ import absolute_import, division, print_function, unicode_literals
from gi.repository import Gtk, Gdk, GObject
import ui
from logitech.unifying_receiver import status as _status
from . import config_panel as _config_panel
_RECEIVER_ICON_SIZE = Gtk.IconSize.LARGE_TOOLBAR
_DEVICE_ICON_SIZE = Gtk.IconSize.DIALOG
_STATUS_ICON_SIZE = Gtk.IconSize.LARGE_TOOLBAR
_TOOLBAR_ICON_SIZE = Gtk.IconSize.MENU
_PLACEHOLDER = '~'
_FALLBACK_ICON = 'preferences-desktop-peripherals'
#
#
#
def _make_receiver_box(name):
frame = Gtk.Frame()
frame._device = None
frame.set_name(name)
icon_set = ui.device_icon_set(name)
icon = Gtk.Image.new_from_icon_set(icon_set, _RECEIVER_ICON_SIZE)
icon.set_padding(2, 2)
frame._icon = icon
label = Gtk.Label('Scanning...')
label.set_alignment(0, 0.5)
frame._label = label
pairing_icon = Gtk.Image.new_from_icon_name('network-wireless', _RECEIVER_ICON_SIZE)
pairing_icon.set_tooltip_text('The pairing lock is open.')
pairing_icon._tick = 0
frame._pairing_icon = pairing_icon
toolbar = Gtk.Toolbar()
toolbar.set_style(Gtk.ToolbarStyle.ICONS)
toolbar.set_icon_size(_TOOLBAR_ICON_SIZE)
toolbar.set_show_arrow(False)
frame._toolbar = toolbar
hbox = Gtk.HBox(homogeneous=False, spacing=8)
hbox.pack_start(icon, False, False, 0)
hbox.pack_start(label, True, True, 0)
hbox.pack_start(pairing_icon, False, False, 0)
hbox.pack_start(toolbar, False, False, 0)
info_label = Gtk.Label()
info_label.set_markup('<small>reading ...</small>')
info_label.set_property('margin-left', 36)
info_label.set_alignment(0, 0)
info_label.set_selectable(True)
frame._info_label = info_label
def _update_info_label(f):
device = f._device
if f._info_label.get_visible() and '\n' not in f._info_label.get_text():
items = [('Path', device.path), ('Serial', device.serial)] + \
[(fw.kind, fw.version) for fw in device.firmware]
f._info_label.set_markup('<small><tt>%s</tt></small>' % '\n'.join('%-13s: %s' % item for item in items))
def _toggle_info_label(action, f):
active = action.get_active()
vb = f.get_child()
for c in vb.get_children()[1:]:
c.set_visible(active)
if active:
GObject.timeout_add(50, _update_info_label, f)
toggle_info_action = ui.action._toggle_action('info', 'Details', _toggle_info_label, frame)
toolbar.insert(toggle_info_action.create_tool_item(), 0)
toolbar.insert(ui.action.pair(frame).create_tool_item(), -1)
# toolbar.insert(ui.action.about.create_tool_item(), -1)
vbox = Gtk.VBox(homogeneous=False, spacing=2)
vbox.set_border_width(2)
vbox.pack_start(hbox, True, True, 0)
vbox.pack_start(Gtk.HSeparator(), False, False, 0)
vbox.pack_start(info_label, True, True, 0)
frame.add(vbox)
frame.show_all()
pairing_icon.set_visible(False)
_toggle_info_label(toggle_info_action, frame)
return frame
def _make_device_box(index):
frame = Gtk.Frame()
frame._device = None
frame.set_name(_PLACEHOLDER)
icon = Gtk.Image.new_from_icon_name(_FALLBACK_ICON, _DEVICE_ICON_SIZE)
icon.set_alignment(0.5, 0)
frame._icon = icon
label = Gtk.Label('Initializing...')
label.set_alignment(0, 0.5)
label.set_padding(4, 0)
frame._label = label
battery_icon = Gtk.Image.new_from_icon_name(ui.get_battery_icon(-1), _STATUS_ICON_SIZE)
battery_label = Gtk.Label()
battery_label.set_width_chars(6)
battery_label.set_alignment(0, 0.5)
light_icon = Gtk.Image.new_from_icon_name('light_unknown', _STATUS_ICON_SIZE)
light_label = Gtk.Label()
light_label.set_alignment(0, 0.5)
light_label.set_width_chars(8)
not_encrypted_icon = Gtk.Image.new_from_icon_name('security-low', _STATUS_ICON_SIZE)
not_encrypted_icon.set_name('not-encrypted')
not_encrypted_icon.set_tooltip_text('The wireless link between this device and the Unifying Receiver is not encrypted.\n'
'\n'
'For pointing devices (mice, trackballs, trackpads), this is a minor security issue.\n'
'\n'
'It is, however, a major security issue for text-input devices (keyboards, numpads),\n'
'because typed text can be sniffed inconspicuously by 3rd parties within range.')
toolbar = Gtk.Toolbar()
toolbar.set_style(Gtk.ToolbarStyle.ICONS)
toolbar.set_icon_size(_TOOLBAR_ICON_SIZE)
toolbar.set_show_arrow(False)
frame._toolbar = toolbar
status_box = Gtk.HBox(homogeneous=False, spacing=2)
status_box.pack_start(battery_icon, False, True, 0)
status_box.pack_start(battery_label, False, True, 0)
status_box.pack_start(light_icon, False, True, 0)
status_box.pack_start(light_label, False, True, 0)
status_box.pack_end(toolbar, False, False, 0)
status_box.pack_end(not_encrypted_icon, False, False, 0)
frame._status_icons = status_box
status_vbox = Gtk.VBox(homogeneous=False, spacing=4)
status_vbox.pack_start(label, True, True, 0)
status_vbox.pack_start(status_box, True, True, 0)
device_box = Gtk.HBox(homogeneous=False, spacing=4)
# device_box.set_border_width(4)
device_box.pack_start(icon, False, False, 0)
device_box.pack_start(status_vbox, True, True, 0)
device_box.show_all()
info_label = Gtk.Label()
info_label.set_markup('<small>reading ...</small>')
info_label.set_property('margin-left', 54)
info_label.set_selectable(True)
info_label.set_alignment(0, 0)
frame._info_label = info_label
def _update_info_label(f):
if frame._info_label.get_text().count('\n') < 4:
device = f._device
assert device
items = [None, None, None, None, None, None, None, None]
hid = device.protocol
items[0] = ('Protocol', 'HID++ %1.1f' % hid if hid else 'unknown')
items[1] = ('Polling rate', '%d ms' % device.polling_rate)
items[2] = ('Wireless PID', device.wpid)
items[3] = ('Serial', device.serial)
firmware = device.firmware
if firmware:
items[4:] = [(fw.kind, (fw.name + ' ' + fw.version).strip()) for fw in firmware]
frame._info_label.set_markup('<small><tt>%s</tt></small>' % '\n'.join('%-13s: %s' % i for i in items if i))
def _toggle_info_label(action, f):
active = action.get_active()
if active:
# set config toggle button as inactive
f._toolbar.get_children()[-1].set_active(False)
vb = f.get_child()
children = vb.get_children()
children[1].set_visible(active) # separator
children[2].set_visible(active) # info label
if active:
GObject.timeout_add(30, _update_info_label, f)
def _toggle_config(action, f):
active = action.get_active()
if active:
# set info toggle button as inactive
f._toolbar.get_children()[0].set_active(False)
vb = f.get_child()
children = vb.get_children()
children[1].set_visible(active) # separator
children[3].set_visible(active) # config box
children[4].set_visible(active) # unpair button
if active:
GObject.timeout_add(30, _config_panel.update, f)
toggle_info_action = ui.action._toggle_action('info', 'Details', _toggle_info_label, frame)
toolbar.insert(toggle_info_action.create_tool_item(), 0)
toggle_config_action = ui.action._toggle_action('preferences-system', 'Configuration', _toggle_config, frame)
toolbar.insert(toggle_config_action.create_tool_item(), -1)
vbox = Gtk.VBox(homogeneous=False, spacing=2)
vbox.set_border_width(2)
vbox.pack_start(device_box, True, True, 0)
vbox.pack_start(Gtk.HSeparator(), False, False, 0)
vbox.pack_start(info_label, False, False, 0)
frame._config_box = _config_panel.create()
vbox.pack_start(frame._config_box, False, False, 0)
unpair = Gtk.Button('Unpair')
unpair.set_image(Gtk.Image.new_from_icon_name('edit-delete', Gtk.IconSize.BUTTON))
unpair.connect('clicked', ui.action._unpair_device, frame)
unpair.set_relief(Gtk.ReliefStyle.NONE)
unpair.set_property('margin-left', 106)
unpair.set_property('margin-right', 106)
unpair.set_property('can-focus', False) # exclude from tab-navigation
vbox.pack_end(unpair, False, False, 0)
vbox.show_all()
frame.add(vbox)
_toggle_info_label(toggle_info_action, frame)
_toggle_config(toggle_config_action, frame)
return frame
def create(title, name, max_devices, systray=False):
window = Gtk.Window()
window.set_title(title)
window.set_icon_name(ui.APP_ICON[0])
window.set_role('status-window')
vbox = Gtk.VBox(homogeneous=False, spacing=12)
vbox.set_border_width(4)
rbox = _make_receiver_box(name)
vbox.add(rbox)
for i in range(1, 1 + max_devices):
dbox = _make_device_box(i)
vbox.add(dbox)
vbox.set_visible(True)
window.add(vbox)
geometry = Gdk.Geometry()
geometry.min_width = 320
geometry.min_height = 32
window.set_geometry_hints(vbox, geometry, Gdk.WindowHints.MIN_SIZE)
window.set_resizable(False)
def _toggle_visible(w, trigger):
if w.get_visible():
# hiding moves the window to 0,0
position = w.get_position()
w.hide()
w.move(*position)
else:
if isinstance(trigger, Gtk.StatusIcon):
x, y = w.get_position()
if x == 0 and y == 0:
# if the window hasn't been shown yet, position it next to the status icon
x, y, _ = Gtk.StatusIcon.position_menu(Gtk.Menu(), trigger)
w.move(x, y)
w.present()
return True
def _set_has_systray(w, systray):
if systray != w._has_systray:
w._has_systray = systray
if systray:
if w._delete_event_connection is None or not w.get_skip_taskbar_hint():
w.set_skip_taskbar_hint(True)
w.set_skip_pager_hint(True)
if w._delete_event_connection:
w.disconnect(w._delete_event_connection)
w._delete_event_connection = w.connect('delete-event', _toggle_visible)
else:
if w._delete_event_connection is None or w.get_skip_taskbar_hint():
w.set_skip_taskbar_hint(False)
w.set_skip_pager_hint(False)
if w._delete_event_connection:
w.disconnect(w._delete_event_connection)
w._delete_event_connection = w.connect('delete-event', Gtk.main_quit)
w.present()
from types import MethodType
window.toggle_visible = MethodType(_toggle_visible, window)
window.set_has_systray = MethodType(_set_has_systray, window)
del MethodType
window.set_keep_above(True)
window._delete_event_connection = None
window._has_systray = None
window.set_has_systray(systray)
return window
#
#
#
def _update_receiver_box(frame, receiver):
frame._label.set_text(str(receiver.status))
if receiver:
frame._device = receiver
frame._icon.set_sensitive(True)
if receiver.status.lock_open:
if frame._pairing_icon._tick == 0:
def _pairing_tick(i, s):
if s and s.lock_open:
i.set_sensitive(bool(i._tick % 2))
i._tick += 1
return True
i.set_visible(False)
i.set_sensitive(True)
i._tick = 0
frame._pairing_icon.set_visible(True)
GObject.timeout_add(1000, _pairing_tick, frame._pairing_icon, receiver.status)
else:
frame._pairing_icon.set_visible(False)
frame._pairing_icon.set_sensitive(True)
frame._pairing_icon._tick = 0
frame._toolbar.set_sensitive(True)
else:
frame._device = None
frame._icon.set_sensitive(False)
frame._pairing_icon.set_visible(False)
frame._toolbar.set_sensitive(False)
frame._toolbar.get_children()[0].set_active(False)
frame._info_label.set_text('')
def _update_device_box(frame, dev):
if dev is None:
frame.set_visible(False)
frame.set_name(_PLACEHOLDER)
frame._device = None
_config_panel.update(frame)
return
first_run = frame.get_name() != dev.name
if first_run:
frame._device = dev
frame.set_name(dev.name)
icon_set = ui.device_icon_set(dev.name, dev.kind)
frame._icon.set_from_icon_set(icon_set, _DEVICE_ICON_SIZE)
frame._label.set_markup('<b>%s</b>' % dev.name)
for i in frame._toolbar.get_children():
i.set_active(False)
battery_icon, battery_label, light_icon, light_label, not_encrypted_icon, _ = frame._status_icons
battery_level = dev.status.get(_status.BATTERY_LEVEL)
if dev.status:
frame._label.set_sensitive(True)
if battery_level is None:
battery_icon.set_sensitive(False)
battery_icon.set_from_icon_name(ui.get_battery_icon(-1), _STATUS_ICON_SIZE)
battery_label.set_markup('<small>no status</small>')
battery_label.set_sensitive(True)
else:
battery_icon.set_from_icon_name(ui.get_battery_icon(battery_level), _STATUS_ICON_SIZE)
battery_icon.set_sensitive(True)
battery_label.set_text('%d%%' % battery_level)
battery_label.set_sensitive(True)
battery_status = dev.status.get(_status.BATTERY_STATUS)
battery_icon.set_tooltip_text(battery_status or '')
light_level = dev.status.get(_status.LIGHT_LEVEL)
if light_level is None:
light_icon.set_visible(False)
light_label.set_visible(False)
else:
icon_name = 'light_%03d' % (20 * ((light_level + 50) // 100))
light_icon.set_from_icon_name(icon_name, _STATUS_ICON_SIZE)
light_icon.set_visible(True)
light_label.set_text('%d lux' % light_level)
light_label.set_visible(True)
not_encrypted_icon.set_visible(dev.status.get(_status.ENCRYPTED) == False)
else:
frame._label.set_sensitive(False)
battery_icon.set_sensitive(False)
battery_label.set_sensitive(False)
if battery_level is None:
battery_label.set_markup('<small>inactive</small>')
else:
battery_label.set_markup('%d%%' % battery_level)
light_icon.set_visible(False)
light_label.set_visible(False)
not_encrypted_icon.set_visible(False)
frame._toolbar.get_children()[-1].set_active(False)
frame.set_visible(True)
_config_panel.update(frame)
def update(window, receiver, device=None):
assert receiver is not None
# print ("update", receiver, receiver.status, len(receiver), device)
window.set_icon_name(ui.APP_ICON[1 if receiver else -1])
vbox = window.get_child()
frames = list(vbox.get_children())
assert len(frames) == 1 + receiver.max_devices, frames
if device is None:
_update_receiver_box(frames[0], receiver)
if not receiver:
for frame in frames[1:]:
_update_device_box(frame, None)
else:
_update_device_box(frames[device.number], None if device.status is None else device)

View File

@@ -1,70 +0,0 @@
#
# Optional desktop notifications.
#
from __future__ import absolute_import, division, print_function, unicode_literals
try:
# this import is allowed to fail, in which case the entire feature is unavailable
from gi.repository import Notify
import logging
import ui
# assumed to be working since the import succeeded
available = True
_notifications = {}
def init(app_title):
"""Init the notifications system."""
global available
if available:
if not Notify.is_initted():
logging.info("starting desktop notifications")
try:
return Notify.init(app_title)
except:
logging.exception("initializing desktop notifications")
available = False
return available and Notify.is_initted()
def uninit():
if available and Notify.is_initted():
logging.info("stopping desktop notifications")
_notifications.clear()
Notify.uninit()
def show(dev, reason=None):
"""Show a notification with title and text."""
if available and Notify.is_initted():
summary = dev.name
# if a notification with same name is already visible, reuse it to avoid spamming
n = _notifications.get(summary)
if n is None:
n = _notifications[summary] = Notify.Notification()
message = reason or ('unpaired' if dev.status is None else
(str(dev.status) or ('connected' if dev.status else 'inactive')))
# we need to use the filename here because the notifications daemon
# is an external application that does not know about our icon sets
n.update(summary, message, ui.device_icon_file(dev.name, dev.kind))
urgency = Notify.Urgency.LOW if dev.status else Notify.Urgency.NORMAL
n.set_urgency(urgency)
try:
# logging.debug("showing %s", n)
n.show()
except Exception:
logging.exception("showing %s", n)
except ImportError:
available = False
init = lambda app_title: False
uninit = lambda: None
show = lambda dev, reason: None

View File

@@ -1,126 +0,0 @@
#
#
#
from __future__ import absolute_import, division, print_function, unicode_literals
from gi.repository import Gtk, GObject, GdkPixbuf
import ui
from logitech.unifying_receiver import status as _status
#
#
#
_NO_DEVICES = [None] * 6
def create(window, menu_actions=None):
name = window.get_title()
icon = Gtk.StatusIcon()
icon.set_title(name)
icon.set_name(name)
icon.set_from_icon_name(ui.APP_ICON[0])
icon._devices = list(_NO_DEVICES)
icon.set_tooltip_text(name)
icon.connect('activate', window.toggle_visible)
menu = Gtk.Menu()
for action in menu_actions or ():
if action:
menu.append(action.create_menu_item())
menu.append(ui.action.quit.create_menu_item())
menu.show_all()
icon.connect('popup_menu',
lambda icon, button, time, menu:
menu.popup(None, None, icon.position_menu, icon, button, time),
menu)
# use size-changed to detect if the systray is available or not
def _size_changed(i, size, w):
def _check_systray(i2, w2):
w2.set_has_systray(i2.is_embedded() and i2.get_visible())
# first guess
GObject.timeout_add(250, _check_systray, i, w)
# just to make sure...
GObject.timeout_add(1000, _check_systray, i, w)
icon.connect('size-changed', _size_changed, window)
return icon
_PIXMAPS = {}
def _icon_with_battery(level, active):
battery_icon = ui.get_battery_icon(level)
name = '%s-%s' % (battery_icon, active)
if name not in _PIXMAPS:
mask = ui.icon_file(ui.APP_ICON[2], 128)
assert mask
mask = GdkPixbuf.Pixbuf.new_from_file(mask)
assert mask.get_width() == 128 and mask.get_height() == 128
mask.saturate_and_pixelate(mask, 0.7, False)
battery = ui.icon_file(battery_icon, 128)
assert battery
battery = GdkPixbuf.Pixbuf.new_from_file(battery)
assert battery.get_width() == 128 and battery.get_height() == 128
if not active:
battery.saturate_and_pixelate(battery, 0, True)
# TODO can the masking be done at runtime?
battery.composite(mask, 0, 7, 80, 121, -32, 7, 1, 1, GdkPixbuf.InterpType.NEAREST, 255)
_PIXMAPS[name] = mask
return _PIXMAPS[name]
def update(icon, receiver, device=None):
# print ("icon update", receiver, receiver.status, len(receiver), device)
if device is not None:
icon._devices[device.number] = None if device.status is None else device
if not receiver:
icon._devices[:] = _NO_DEVICES
if not icon.is_embedded():
return
def _lines(r, devices):
yield '<b>%s</b>: %s' % (ui.NAME, r.status)
yield ''
for dev in devices:
if dev is None:
continue
yield '<b>%s</b>' % dev.name
assert hasattr(dev, 'status') and dev.status is not None
p = str(dev.status)
if p: # does it have any properties to print?
if dev.status:
yield '\t%s' % p
else:
yield '\t%s <small>(inactive)</small>' % p
else:
if dev.status:
yield '\t<small>no status</small>'
else:
yield '\t<small>(inactive)</small>'
yield ''
icon.set_tooltip_markup('\n'.join(_lines(receiver, icon._devices)).rstrip('\n'))
battery_status = None
battery_level = 1000
for dev in icon._devices:
if dev is not None:
level = dev.status.get(_status.BATTERY_LEVEL)
if level is not None and level < battery_level:
battery_status = dev.status
battery_level = level
if battery_status is None:
icon.set_from_icon_name(ui.APP_ICON[1 if receiver else -1])
else:
icon.set_from_pixbuf(_icon_with_battery(battery_level, bool(battery_status)))

View File

@@ -1,11 +0,0 @@
#!/bin/sh
Z=`dirname "$0"`
Z=`readlink -f "$Z/.."`
export PYTHONPATH="$Z/lib"
export PYTHONUNBUFFERED=yes
NICE=`which nice 2>/dev/null`
PYTHON=${PYTHON:-`which python python2 python3 | head -n 1`}
exec $NICE $PYTHON -m hidapi.hidconsole "$@"

View File

@@ -1,23 +0,0 @@
#!/bin/sh
if test -z "$1"; then
echo "Use: $0 <device number 1..6>"
exit 2
fi
Z=`readlink -f "$0"`
HC=`dirname "$Z"`/hidconsole
z='0 1 2 3 4 5 6 7 8 9 a b c d e f'
for x in $z; do
for y in $z; do
echo "10 0${1} 81${x}${y} 000000"
done
done | "$HC" --hidpp | grep -v ' 8F.. ..0[12]' | grep -B 1 '^>> '
for x in $z; do
for y in $z; do
echo "10 0${1} 83${x}${y} 000000"
done
done | "$HC" --hidpp | grep -v ' 8F.. ..0[12]' | grep -B 1 '^>> '

View File

@@ -1,11 +1,57 @@
#!/bin/sh
#!/usr/bin/env python3
# -*- python-mode -*-
# -*- coding: UTF-8 -*-
Z=`dirname "$0"`
Z=`readlink -f "$Z/.."`
## 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.
export PYTHONPATH="$Z/app:$Z/lib"
export XDG_DATA_DIRS="$Z/share_override:$Z/share:$XDG_DATA_DIRS"
from __future__ import absolute_import, unicode_literals
NICE=`which nice 2>/dev/null`
PYTHON=${PYTHON:-`which python python2 python3 | head -n 1`}
exec $NICE $PYTHON -m solaar "$@"
def init_paths():
"""Make the app work in the source tree."""
import sys
import os.path as _path
# Python 2 need conversion from utf-8 filenames
# Python 3 might have problems converting back to UTF-8 in case of Unicode surrogates
try:
if sys.version_info < (3,):
decoded_path = sys.path[0].decode(sys.getfilesystemencoding())
else:
decoded_path = sys.path[0]
sys.path[0].encode(sys.getfilesystemencoding())
except UnicodeError:
sys.stderr.write('ERROR: Solaar cannot recognize encoding of filesystem path, this may happen because non UTF-8 characters in the pathname.\n')
sys.exit(1)
prefix = _path.normpath(_path.join(_path.realpath(decoded_path), '..'))
src_lib = _path.join(prefix, 'lib')
share_lib = _path.join(prefix, 'share', 'solaar', 'lib')
for location in src_lib, share_lib:
init_py = _path.join(location, 'solaar', '__init__.py')
# print ("sys.path[0]: checking", init_py)
if _path.exists(init_py):
# print ("sys.path[0]: found", location, "replacing", sys.path[0])
sys.path[0] = location
break
if __name__ == '__main__':
init_paths()
import solaar.gtk
solaar.gtk.main()

View File

@@ -1,10 +1,43 @@
#!/bin/sh
#!/usr/bin/env python3
# -*- python-mode -*-
# -*- coding: UTF-8 -*-
Z=`dirname "$0"`
Z=`readlink -f "$Z/.."`
## 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.
export PYTHONPATH="$Z/app:$Z/lib"
from __future__ import absolute_import, unicode_literals
NICE=`which nice 2>/dev/null`
PYTHON=${PYTHON:-`which python python2 python3 | head -n 1`}
exec $NICE $PYTHON -m solaar_cli "$@"
def init_paths():
"""Make the app work in the source tree."""
import sys
import os.path as _path
prefix = _path.normpath(_path.join(_path.realpath(sys.path[0]), '..'))
src_lib = _path.join(prefix, 'lib')
share_lib = _path.join(prefix, 'share', 'solaar', 'lib')
for location in src_lib, share_lib:
init_py = _path.join(location, 'solaar', '__init__.py')
if _path.exists(init_py):
sys.path[0] = location
break
if __name__ == '__main__':
print ('WARNING: solaar-cli is deprecated; use solaar with the usual arguments')
init_paths()
import solaar.cli
solaar.cli.run()

6
docs/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
# ignore documentation-specific files
.jekyll-metadata
Gemfile
Gemfile.lock
_site/

4
docs/README.md Normal file
View File

@@ -0,0 +1,4 @@
# Documentation Readme
This project's documentation is hosted using GitHub pages, which serves static pages using Jeykll.
[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/)

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
docs/Solaar-menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

10
docs/_config.yml Normal file
View File

@@ -0,0 +1,10 @@
title: Solaar
description: Linux Device Manager for Logitech Unifying Receivers and Paired Devices.
tagline: Linux Device Manager for Logitech Unifying Receivers and Paired Devices.
owner: pwr-Solaar
owner_url: https://github.com/pwr-Solaar
repository: pwr-Solaar/Solaar
version: 1.0.2
show_downloads: false
encoding: utf-8
theme: jekyll-theme-slate

View File

@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="{{ site.lang | default: "en-US" }}">
<head>
<meta charset='utf-8'>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,maximum-scale=2">
<link rel="stylesheet" type="text/css" media="screen" href="{{ '/assets/css/style.css?v=' | append: site.github.build_revision | relative_url }}">
<link rel="icon" type="image/png" href="{{ site.baseurl }}/assets/favicon.png" />
{% seo %}
</head>
<body>
<!-- HEADER -->
<div id="header_wrap" class="outer">
<header class="inner">
{% if site.github.is_project_page %}
<a id="forkme_banner" href="{{ site.github.repository_url }}">View on GitHub</a>
{% endif %}
<h1 id="project_title">
<img src="{{ site.baseurl }}/assets/solaar.svg" style="margin-bottom: -10px; width: 48px; height: 48px; border: 0; box-shadow: none;" />
{{ site.title | default: site.github.repository_name }}</h1>
<h2 id="project_tagline">{{ site.description | default: site.github.project_tagline }}</h2>
{% if site.show_downloads %}
<section id="downloads">
<a class="zip_download_link" href="{{ site.github.zip_url }}">Download this project as a .zip file</a>
<a class="tar_download_link" href="{{ site.github.tar_url }}">Download this project as a tar.gz file</a>
</section>
{% endif %}
</header>
</div>
<!-- MAIN CONTENT -->
<div id="main_content_wrap" class="outer">
<section id="main_content" class="inner">
{{ content }}
</section>
</div>
<!-- FOOTER -->
<div id="footer_wrap" class="outer">
<footer class="inner">
{% if site.github.is_project_page %}
<p class="copyright">{{ site.title | default: site.github.repository_name }} maintained by <a href="{{ site.github.owner_url }}">{{ site.github.owner_name }}</a></p>
{% endif %}
<p>Published with <a href="https://pages.github.com">GitHub Pages</a></p>
</footer>
</div>
</body>
</html>

47
docs/_layouts/page.html Normal file
View File

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="{{ site.lang | default: "en-US" }}">
<head>
<meta charset='utf-8'>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,maximum-scale=2">
<link rel="stylesheet" type="text/css" media="screen" href="{{ '/assets/css/style.css?v=' | append: site.github.build_revision | relative_url }}">
<link rel="icon" type="image/png" href="{{ site.baseurl }}/assets/favicon.png" />
{% seo %}
</head>
<body>
<!-- HEADER -->
<div id="header_wrap" class="outer">
<header class="inner">
{% if site.github.is_project_page %}
<a id="forkme_banner" href="{{ site.github.repository_url }}">View on GitHub</a>
{% endif %}
<h1 id="project_title">
<a href="{{ site.baseurl }}" style="color: #fff;">
<img src="{{ site.baseurl }}/assets/solaar.svg" style="margin-bottom: -10px; width: 48px; height: 48px; border: 0; box-shadow: none;" />
{{ site.title | default: site.github.repository_name }}</h1>
</a>
</header>
</div>
<!-- MAIN CONTENT -->
<div id="main_content_wrap" class="outer">
<section id="main_content" class="inner">
{{ content }}
</section>
</div>
<!-- FOOTER -->
<div id="footer_wrap" class="outer">
<footer class="inner">
{% if site.github.is_project_page %}
<p class="copyright">{{ site.title | default: site.github.repository_name }} maintained by <a href="{{ site.github.owner_url }}">{{ site.github.owner_name }}</a></p>
{% endif %}
<p>Published with <a href="https://pages.github.com">GitHub Pages</a></p>
</footer>
</div>
</body>
</html>

BIN
docs/assets/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

100
docs/assets/solaar.svg Normal file
View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="solaar.svg"
inkscape:export-filename="/home/chris/Git/Solaar/_includes/favicon.png"
inkscape:export-xdpi="66.666672"
inkscape:export-ydpi="66.666672"
width="43.200001"
height="43.200001">
<metadata
id="metadata21">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1807"
inkscape:window-height="797"
id="namedview19"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="2.36"
inkscape:cx="1.4135593"
inkscape:cy="-4.4"
inkscape:window-x="3000"
inkscape:window-y="840"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" />
<defs
id="defs4">
<linearGradient
id="gradient_blue">
<stop
style="stop-color:#009099;stop-opacity:1"
offset="0"
id="stop7" />
<stop
style="stop-color:#00a899;stop-opacity:0.9"
offset="1"
id="stop9" />
</linearGradient>
<linearGradient
x1="5"
y1="50"
x2="95"
y2="50"
id="gradient_rect"
xlink:href="#gradient_blue"
gradientUnits="userSpaceOnUse" />
<linearGradient
x1="37"
y1="50"
x2="63"
y2="50"
id="gradient_dot"
xlink:href="#gradient_blue"
gradientUnits="userSpaceOnUse" />
</defs>
<g
transform="matrix(0.48,0,0,0.48,-2.4,-2.4)"
id="g13">
<path
d="m 21.5,5.5 c -8.864,0 -16,7.136 -16,16 l 0,57 c 0,8.864 7.136,16 16,16 l 57,0 c 8.864,0 16,-7.136 16,-16 l 0,-57 c 0,-8.864 -7.136,-16 -16,-16 l -57,0 z m 16.1875,11.1875 9.03125,15.625 C 47.784179,32.115965 48.877705,32 50,32 c 1.122295,0 2.215821,0.115965 3.28125,0.3125 l 9.03125,-15.625 10.375,6 -9.03125,15.625 C 65.078123,39.972287 66.191785,41.898777 66.9375,44 L 85,44 85,56 66.9375,56 c -0.745715,2.101223 -1.859377,4.027713 -3.28125,5.6875 l 9.03125,15.625 -10.375,6 -9.03125,-15.625 C 52.215821,67.884035 51.122295,68 50,68 48.877705,68 47.784179,67.884035 46.71875,67.6875 l -9.03125,15.625 -10.375,-6 9.03125,-15.625 C 34.921877,60.027713 33.808215,58.101223 33.0625,56 L 15,56 15,44 33.0625,44 c 0.745715,-2.101223 1.859377,-4.027713 3.28125,-5.6875 l -9.03125,-15.625 10.375,-6 z"
style="fill:url(#gradient_rect);fill-opacity:1;fill-rule:nonzero;stroke:#16161d;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
id="path15"
inkscape:connector-curvature="0" />
<path
d="m 62,50 a 12,12 0 1 1 -24,0 12,12 0 1 1 24,0 z"
style="fill:url(#gradient_dot);fill-opacity:1;fill-rule:nonzero;stroke:#16161d;stroke-opacity:1"
id="path17"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

115
docs/capabilities.md Normal file
View File

@@ -0,0 +1,115 @@
---
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) and communicate with the receiver using Logitech's HID++
protocol. Solaar is designed to detect all devices paired with your
receivers, and at the very least display some basic information about them.
At this moment, all [Unifying][unifying] receivers are supported (devices
with USB ID `046d:c52b` or `046d:c532`) as are several Lightspeed Receivers
and a dozen Nano receivers.
## HID++
HID++ is a Logitech-proprietary protocol that extends the standard HID
protocol for interfacing with keyboards, mice, and so on. HID++ allows
Logitech receivers to communicate with multiple devices and modify some
features of the device on the device itself. 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 the HID++ and many different 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 working
completely 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 id
(reported by Solaar and also viewable in Linux using `lsusb`). The software
identity of a device can be determined by its Wireless PID as reported by
Solaar.
Even something as fundamental as pairing works differently for different
receivers. For Unifying 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 other receivers, like the
Nano receiver with USB ID `046d:c534`, can only pair with particular kinds of
devices 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.
Only some connections between receivers and devices are possible. In should
be possible to connect any device with a Unifying logo on it to any receiver
with a Unifying logo on it. Receivers without the Unifying logo probably
can connect only to the kind of devices they were bought with and devices
without the Unifying logo can probably only connect to the kind of receiver
that they were bought with.
## Supported features
Solaar uses the HID++ protocol to pair devices to receivers and unpair
devices from receivers. Solaar also uses the HID++ protocol to display
features of receivers and devices. Solaar can modify some of the features
of devices. Solaar currently only displays some features and can modify
even fewer.
Solaar does not do anything beyond using the HID++ protocol to change the
behavior of receivers and devices. 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).
Logitech receivers and devices have firmware in them. Some of the 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 to become
permanently non-functional if something goes wrong with the update or the
update installs the wrong firmware.
Solaar does keep track of some of the changeable state of a device between
invocations. When Solaar starts it restores on-line devices to their
previously-known state. Also, while running Solaar restores devices to
their previously-known state when the device comes on line.
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. 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 terminating
Solaar and starting it again.
## Battery Icons
For many devices, Solaar shows the approximate battery level via icons that
show up in both main Solaar window and the system tray. Solaar used to use
several heuristics to determine 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 bugs external to Solaar
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

8
docs/debian.md Normal file
View File

@@ -0,0 +1,8 @@
---
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`

217
docs/devices.md Normal file
View File

@@ -0,0 +1,217 @@
---
title: Supported Devices
layout: page
---
# Supported devices and receivers
These tables list Logitech receivers and devices and to what degree their
features are supported by Solaar. The information in these tables is
incomplete, based on what devices users have been able to test Solaar with.
The HID++ column specifies the device's HID++ version. Some devices report
version 4.5, but that is the same as version 2.0 as listed here.
For devices what support HID++ 2.0 or greater, Solaar is able to discover
the features the device supports.
The Battery column specifies if Solaar is able to read the device's battery
level.
For mice, the DPI column specifies if the mouse's sensitivity is fixed (`-`),
can only be read (`R`), or can be read and changed by Solaar (`R/W`).
The reprog(rammable) keys feature is currently not fully supported by Solaar.
You are able to read this feature using command-line interface of Solaar,
but it is not possible to assign different keys.
If your device works with Solaar, but its supported features are not
correctly specified here, please open an issue on the [Solaar github
repository][solaar] with the pleasant news.
### Receivers:
| USB ID | Kind | Max Paired Devices |
------------|------------|--------------------|
| 046d:c517 | Nano | 1 |
| 046d:c518 | Nano | 1 |
| 046d:c51a | Nano | 1 |
| 046d:c51b | Nano | 1 |
| 046d:c521 | Nano | 1 |
| 046d:c525 | Nano | 1 |
| 046d:c526 | Nano | 1 |
| 046d:c52b | Unifying | 6 |
| 046d:c52e | Nano | 1 |
| 046d:c52f | Nano | 1 |
| 046d:c531 | Nano | 1 |
| 046d:c532 | Unifying | 6 |
| 064d:c534 | Nano | 2 |
| 064d:c539 | Lightspeed | 1 |
| 064d:c53a | Lightspeed | 1 |
| 064d:c53f | Lightspeed | 1 |
| 17ef:6042 | Nano | 1 |
### Keyboards (Unifying):
| Device | WPID | HID++ | Battery | Other supported features |
|------------------|------|-------|---------|-----------------------------------------|
| K230 | 400D | 2.0 | yes | |
| K270 | 4003 | 2.0 | yes | |
| K340 | 2007 | 1.0 | yes | |
| K350 | 200A | 1.0 | yes | |
| K360 | 4004 | 2.0 | yes | FN swap, reprog keys |
| K375s | 4071 | | | FN swap |
| K400 Touch | 400E | 2.0 | yes | FN swap |
| K400 Touch | 4024 | 2.0 | yes | FN swap |
| K400 Plus | 404D | 2.0 | | FN swap |
| K520 | 2011 | 1.0 | yes | FN swap |
| K600 TV | 4078 | 2.0 | yes | FN swap |
| K750 Solar | 4002 | 2.0 | yes | FN swap, Lux reading, light button |
| K780 | 405B | 2.0 | yes | FN swap |
| K800 Illuminated | 2010 | 1.0 | yes | FN swap, reprog keys, LEDs |
| K800 (new ver) | 406E | 2.0 | yes | FN swap |
| K830 Illuminated | 4032 | 2.0 | yes | FN swap |
| MX Keys | 408A | 2.0 | yes | |
| N545 | 2006 | | yes | |
| TK820 | | 2.0 | yes | FN swap |
| Craft | 4066 | 2.0 | | |
* The [K750 Solar Keyboard][K750] can be queried for its solar charge status.
Pressing the `Light-Check` button on the keyboard will pop-up the application
window and display the current lighting value (Lux) as reported by the
keyboard, similar to Logitech's *Solar.app* for Windows.
* FN swap changes the way the function keys (`F1`..`F12`) work, i.e., whether holding `FN` while pressing the function keys will generate the standard `Fx` keycodes or the special function (yellow icons) keycodes.
### Mice (Unifying):
| Device | WPID | HID++ | Battery | DPI | Other supported features |
|------------------|------|-------|---------|-------|---------------------------------|
| M150 | 4022 | 2.0 | | | |
| M185 | 4055 | 2.0 | | R/W | smooth scrolling |
| M310 | 4031 | 2.0 | yes | | |
| M310 | 4055 | 2.0 | | R/W | smooth scrolling |
| M317 | | | | | |
| M325 | 400A | 2.0 | yes | 1000 | smooth scrolling |
| M330 | | 2.0 | yes | 1000 | smooth scrolling |
| M345 | 4017 | 2.0 | yes | - | smooth scrolling |
| M350 | 101C | 1.0 | yes | | |
| M350 | 4080 | 2.0 | | | |
| M505 | 101D | 1.0 | yes | | smooth scrolling, side scrolling|
| M510 | 1025 | 1.0 | yes | | smooth scrolling, side scrolling|
| M510 | 4051 | 2.0 | yes | | smooth scrolling |
| M515 Couch | 4007 | 2.0 | yes | - | smooth scrolling |
| M525 | 4013 | 2.0 | yes | - | smooth scrolling |
| M560 | | 2.0 | yes | - | smooth scrolling |
| M585 | 406B | 2.0 | yes | R/W | smooth scrolling |
| M590 | 406B | 2.0 | yes | R/W | smooth scrolling |
| M600 Touch | 401A | 2.0 | yes | | |
| M705 Marathon | 101B | 1.0 | yes | - | smooth scrolling, side scrolling|
| M705 Marathon | 406D | 2.0 | yes | R/W | smooth scrolling |
| T400 Zone Touch | | 2.0 | yes | | smooth scrolling |
| T620 Touch | | 2.0 | yes | | |
| Performance MX | 101A | 1.0 | yes | R/W | smooth scrolling, side scrolling|
| Anywhere MX | 1017 | 1.0 | yes | R/W | smooth scrolling, side scrolling|
| Anywhere MX 2 | 404A | 2.0 | yes | R/W | smooth scrolling |
| MX Master | 4041 | 2.0 | yes | R/W | smooth scrolling, smart shift |
| MX Master 2S | 4069 | 2.0 | yes | R/W | smooth scrolling, smart shift |
| Cube | | 2.0 | yes | | |
### Mice (Nano):
| Device | WPID | HID++ | Battery | DPI | Other supported features |
|------------------|------|-------|---------|-------|---------------------------------|
| G7 | 1002 | 1.0 | yes | - | |
| G700 | 1023 | 1.0 | yes | - | smooth scrolling, side scrolling|
| G700s | 102A | 1.0 | yes | - | smooth scrolling, side scrolling|
| V450 Nano | 1011 | 1.0 | yes | - | smooth scrolling |
| V550 Nano | 1013 | 1.0 | yes | - | smooth scrolling, side scrolling|
| VX Nano | 100B | 1.0 | yes | - | smooth scrolling, side scrolling|
| VX Nano | 100F | 1.0 | yes | - | smooth scrolling, side scrolling|
| M175 | 4008 | | yes | | |
| M185 (old) | 4038 | 2.0 | yes | R/W | smooth scrolling (note) |
| M185 (new) | 4054 | 2.0 | no | R/W | smooth scrolling (note) |
| M187 | 4019 | 2.0 | yes | | |
| M215 | 1020 | 1.0 | yes | | |
| M235 | 4055 | 2.0 | yes | R/W | smooth scrolling |
| M305 | 101F | 1.0 | yes | | side scrolling |
| M310 | 1024 | 1.0 | yes | | |
| M315 | | | yes | | |
| M330 | | ?.? | yes | ? | smooth scrolling |
| MX 1100 | 1014 | 1.0 | yes | - | smooth scrolling, side scrolling|
(old): M185 with P/N: 810-003496
(new): M185 with P/N: 810-005238 or 810-005232
(note): Currently, smooth scrolling events are not processed in xfce and this
setting is useful only to disable smooth scrolling.
### Mice (Mini):
| Device | WPID | HID++ | Battery | DPI | Other supported features |
|------------------|------|-------|---------|-------|---------------------------------|
| MX610 | 1001 | 1.0 | yes | | |
| MX610 lefthanded | 1004 | 1.0 | yes | | |
| MX620 | 100A | 1.0 | yes | | |
| MX620 | 1016 | 1.0 | yes | | |
| V400 | 1003 | 1.0 | yes | | |
| V450 | 1005 | 1.0 | yes | | |
| VX Revolution | 1006 | 1.0 | yes | | |
| VX Revolution | 100D | 1.0 | yes | | |
| MX Air | 1007 | 1.0 | yes | | |
| MX Air | 100E | 1.0 | yes | | |
| MX Revolution | 1008 | 1.0 | yes | | |
| MX Revolution | 100C | 1.0 | yes | | |
### Trackballs (Unifying):
| Device | WPID | HID++ | Battery | DPI | Other supported features |
|-------------------|------|-------|---------|-------|---------------------------------|
| M570 Trackball | | 1.0 | yes | - | |
| MX Ergo Trackball | | 2.0 | yes | - | |
### Touchpads (Unifying):
| Device | WPID | HID++ | Battery | DPI | Other supported features |
|------------------|------|-------|---------|-------|---------------------------------|
| Wireless Touch | 4011 | 2.0 | yes | | |
| T650 Touchpad | 4101 | 2.0 | yes | | smooth scrolling |
### Mice and Keyboards sold as combos:
| Device | WPID | HID++ | Battery | Other supported features |
|------------------|------|-------|---------|-----------------------------------------|
| MK220 | | 2.0 | yes | |
| MK270 | 4023 | 2.0 | yes | reprog keys |
| MK320 | 200F | | | |
| MK330 | | | | |
| MK520 | | M2/K1 | yes | FN swap, reprog keys |
| MK550 | | | | |
| MK700 | 2008 | 1.0 | yes | FN swap, reprog keys |
| MK710 | | 1.0 | yes | FN swap, reprog keys |
[solaar]: https://github.com/pwr-Solaar/Solaar
[logitech]: https://www.logitech.com
[unifying]: https://en.wikipedia.org/wiki/Logitech_Unifying_receiver
[G700s]: https://gaming.logitech.com/en-us/product/g700s-rechargeable-wireless-gaming-mouse
[K360]: http://logitech.com/product/keyboard-k360
[K700]: http://logitech.com/product/wireless-desktop-mk710
[K750]: http://logitech.com/product/k750-keyboard
[K800]: http://logitech.com/product/wireless-illuminated-keyboard-k800
[K830]: http://logitech.com/product/living-room-keyboard-k830
[M510]: http://logitech.com/product/wireless-mouse-m510
[M705]: http://logitech.com/product/marathon-mouse-m705
[P_MX]: http://logitech.com/product/performance-mouse-mx
[A_MX]: http://logitech.com/product/anywhere-mouse-mx
[M325]: http://logitech.com/product/wireless-mouse-m325
[M330]: https://www.logitech.com/en-us/product/m330-silent-plus

View File

@@ -0,0 +1,48 @@
1: Wireless Mouse M510
Codename : M510v2
Kind : mouse
Wireless PID : 4051
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
Serial number: 8989B04C
Firmware: RQM 62.00.B0013
The power switch is located on the base.
Supports 22 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: RESET {0020}
5: BATTERY STATUS {1000}
6: unknown:1802 {1802} internal, hidden
7: unknown:1810 {1810} internal, hidden
8: unknown:1830 {1830} internal, hidden
9: unknown:1862 {1862} internal, hidden
10: unknown:1890 {1890} internal, hidden
11: unknown:18A0 {18A0} internal, hidden
12: unknown:18B1 {18B1} internal, hidden
13: REPROG CONTROLS V4 {1B04}
14: WIRELESS DEVICE STATUS {1D4B}
15: unknown:1DF0 {1DF0} hidden
16: unknown:1DF3 {1DF3} internal, hidden
17: unknown:1E00 {1E00} hidden
18: unknown:1EB0 {1EB0} internal, hidden
19: unknown:1F03 {1F03} internal, hidden
20: LOWRES WHEEL {2130}
21: POINTER SPEED {2205}
Has 7 reprogrammable keys:
0: LEFT CLICK , default: LeftClick => LEFT CLICK
divertable, mse, pos:0, group:1, gmask:1
1: RIGHT CLICK , default: RightClick => RIGHT CLICK
divertable, mse, pos:0, group:1, gmask:1
2: MIDDLE BUTTON , default: MiddleMouseButton => MIDDLE BUTTON
divertable, mse, reprogrammable, pos:0, group:2, gmask:3
3: LEFT SCROLL AS AC PAN , default: HorzScrollLeftSet => LEFT SCROLL AS AC PAN
divertable, mse, reprogrammable, pos:0, group:2, gmask:3
4: RIGHT SCROLL AS AC PAN , default: HorzScrollRightSet => RIGHT SCROLL AS AC PAN
divertable, mse, reprogrammable, pos:0, group:2, gmask:3
5: BACK AS BUTTON 4 , default: BackEx => BACK AS BUTTON 4
divertable, mse, reprogrammable, pos:0, group:2, gmask:3
6: FORWARD AS BUTTON 5 , default: BrowserForwardEx => FORWARD AS BUTTON 5
divertable, mse, reprogrammable, pos:0, group:2, gmask:3
Battery: 70%, discharging.

View File

@@ -0,0 +1,51 @@
Unifying Receiver
Device path : /dev/hidraw0
USB id : 046d:c52b
Serial : A7F5923B
Firmware : 24.01.B0023
Bootloader : 01.08
Other : AA.AD
Has 1 paired device(s) out of a maximum of 6.
Notifications: wireless, software present (0x000900)
Device activity counters: 1=11
1: Wireless Mouse MX Anywhere 2
Codename : MX Anywhere 2
Kind : mouse
Wireless PID : 404A
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
Serial number: F3B81C5B
Bootloader: BOT 23.00.B0007
Firmware: MPM 02.00.B0007
Firmware: MPM 02.00.B0007
Other:
The power switch is located on the base.
Supports 26 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: WIRELESS DEVICE STATUS {1D4B}
5: RESET {0020}
6: BATTERY STATUS {1000}
7: CHANGE HOST {1814}
8: REPROG CONTROLS V4 {1B04}
9: ADJUSTABLE DPI {2201}
10: VERTICAL SCROLLING {2100}
11: HIRES WHEEL {2121}
12: DFUCONTROL 2 {00C1}
13: unknown:1813 {1813} internal, hidden
14: unknown:1830 {1830} internal, hidden
15: unknown:1890 {1890} internal, hidden
16: unknown:1891 {1891} internal, hidden
17: unknown:18A1 {18A1} internal, hidden
18: unknown:18C0 {18C0} internal, hidden
19: unknown:1DF3 {1DF3} internal, hidden
20: unknown:1E00 {1E00} hidden
21: unknown:1EB0 {1EB0} internal, hidden
22: unknown:1803 {1803} internal, hidden
23: unknown:1861 {1861} internal, hidden
24: unknown:9000 {9000} internal, hidden
25: unknown:1805 {1805} internal, hidden
Battery: 0%, recharging.

View File

@@ -0,0 +1,88 @@
Receiver
LZ301AR-DJ
M/N:C-U0007
(ltunify)
Serial number: D1759614
Firmware version: 012.001.00019
Bootloader version: BL.002.014
Supported notification flags: 00 09 00
- 01: Wireless Notifications
- 08: Software Present
Mouse
(ltunify)
HID++ version: 1.0
Device index 1
Mouse
Name: Anywhere MX
Wireless Product ID: 1017
Serial number: 13865F99
Firmware version: 016.001.00040
Bootloader version: BL.002.010
(solaar)
Unifying Receiver
Device path : /dev/hidraw2
USB id : 046d:c52b
Serial : D1759614
Firmware : 12.01.B0019
Bootloader : 02.14
Has 1 paired device(s) out of a maximum of 6.
Notifications: (none)
Device activity counters: 1=19
1: Anywhere Mouse MX
Codename : Anywhere MX
Kind : mouse
Wireless PID : 1017
Protocol : HID++ 1.0
Polling rate : 8 ms (125Hz)
Serial number: 13865F99
Firmware: 16.01.B0040
Bootloader: 02.10
Other: 00.06
The power switch is located on the base.
Notifications: (none).
Battery: 100%, discharging.
(scan-registers)
# Old notification flags: 000000
# 00 - Enabled Notifications, supported flags: Battery Status (10)
>> ( 0.792) [10 01 8100 100000] b'\x10\x01\x81\x00\x10\x00\x00'
# 01 - scrolling settings?
# Flags:
# 0x40 - Enable Smooth Scrolling
# 0x02 - "confuse KDE", see https://github.com/pwr/Solaar/issues/115
<< ( 0.011) [10 01 8101 000000] b'\x10\x01\x81\x01\x00\x00\x00'
>> ( 1.710) [10 01 8101 020000] b'\x10\x01\x81\x01\x02\x00\x00'
# 0D - battery level. first byte is remaining charge in percent; second is
# (guessed) maximum?; third is charge status (30=discharging)
# "10 ix 0D 64 64 30 00" is a battery notification (when enabled)
<< ( 9.789) [10 01 810D 000000] b'\x10\x01\x81\r\x00\x00\x00'
>> ( 9.816) [10 01 810D 646430] b'\x10\x01\x81\rdd0'
# 63 - DPI (range 0x80-0x8e (inclusive))
<< ( 75.521) [10 01 8163 000000] b'\x10\x01\x81c\x00\x00\x00'
>> ( 75.550) [10 01 8163 890000] b'\x10\x01\x81c\x89\x00\x00'
# D0 - ?
<< ( 163.118) [10 01 81D0 000000] b'\x10\x01\x81\xd0\x00\x00\x00'
>> ( 163.148) [10 01 81D0 000000] b'\x10\x01\x81\xd0\x00\x00\x00'
# D4 - ?
<< ( 166.034) [10 01 81D4 000000] b'\x10\x01\x81\xd4\x00\x00\x00'
>> ( 166.063) [10 01 81D4 000008] b'\x10\x01\x81\xd4\x00\x00\x08'
# F1 - firmware/bootloader version
<< ( 187.172) [10 01 81F1 000000] b'\x10\x01\x81\xf1\x00\x00\x00'
>> ( 187.199) [10 01 8F81 F10300] b'\x10\x01\x8f\x81\xf1\x03\x00'
# F3 - ?
<< ( 188.629) [10 01 81F3 000000] b'\x10\x01\x81\xf3\x00\x00\x00'
>> ( 188.661) [10 01 81F3 000000] b'\x10\x01\x81\xf3\x00\x00\x00'
# FD - ?
<< ( 195.715) [10 01 83FD 000000] b'\x10\x01\x83\xfd\x00\x00\x00'
>> ( 195.746) [11 01 83FD 00000000000000000000000000000000] b'\x11\x01\x83\xfd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

114
docs/devices/craft.txt Normal file
View File

@@ -0,0 +1,114 @@
Unifying Receiver
Device path : /dev/hidraw0
USB id : 046d:c52b
Serial : E21FAD57
Firmware : 24.06.B0030
Bootloader : 01.08
Other : AA.AC
Has 2 paired device(s) out of a maximum of 6.
Notifications: wireless, software present (0x000900)
Device activity counters: 1=243, 2=173
1: Craft Advanced Keyboard
Codename : Craft
Kind : keyboard
Wireless PID : 4066
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
Serial number: 428C2F81
Bootloader: BOT 41.00.B0014
Firmware: MPK 07.01.B0015
Other:
Other:
The power switch is located on the edge of top right corner.
Supports 39 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: WIRELESS DEVICE STATUS {1D4B}
5: RESET {0020}
6: unknown:0007 {0007}
7: BATTERY STATUS {1000}
8: CHANGE HOST {1814}
9: unknown:1815 {1815}
10: unknown:1982 {1982}
11: REPROG CONTROLS V4 {1B04}
12: unknown:1C00 {1C00}
13: K375S FN INVERSION {40A3}
14: ENCRYPTION {4100}
15: LOCK KEY STATE {4220}
16: KEYBOARD DISABLE {4521}
17: unknown:4531 {4531}
18: unknown:4600 {4600}
19: unknown:00C2 {00C2}
20: unknown:1803 {1803} internal, hidden
21: unknown:1806 {1806} internal, hidden
22: unknown:1813 {1813} internal, hidden
23: unknown:1805 {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
38: unknown:3615 {3615} internal, hidden
Has 24 reprogrammable keys:
0: unknown:00D1 , default: unknown:00AE => unknown:00D1
divertable, nonstandard, persistently divertable, pos:0, group:0, gmask:0
1: unknown:00D2 , default: unknown:00AF => unknown:00D2
divertable, nonstandard, persistently divertable, pos:0, group:0, gmask:0
2: unknown:00D3 , default: unknown:00B0 => unknown:00D3
divertable, nonstandard, persistently divertable, pos:0, group:0, gmask:0
3: unknown:00C7 , default: unknown:00A3 => unknown:00C7
divertable, is FN, FN sensitive, persistently divertable, reprogrammable, pos:1, group:0, gmask:0
4: unknown:00C8 , default: unknown:00A4 => unknown:00C8
divertable, is FN, FN sensitive, persistently divertable, reprogrammable, pos:2, group:0, gmask:0
5: unknown:00E0 , default: unknown:00BF => unknown:00E0
divertable, is FN, FN sensitive, persistently divertable, reprogrammable, pos:3, group:0, gmask:0
6: unknown:00E1 , default: unknown:00C0 => unknown:00E1
divertable, is FN, FN sensitive, persistently divertable, reprogrammable, pos:4, group:0, gmask:0
7: SHOW DESKTOP , default: ShowDesktop => SHOW DESKTOP
divertable, is FN, FN sensitive, persistently divertable, reprogrammable, pos:5, group:0, gmask:0
8: unknown:00E2 , default: unknown:00C1 => unknown:00E2
divertable, is FN, FN sensitive, persistently divertable, reprogrammable, pos:6, group:0, gmask:0
9: unknown:00E3 , default: unknown:00C2 => unknown:00E3
divertable, is FN, FN sensitive, persistently divertable, reprogrammable, pos:7, group:0, gmask:0
10: unknown:00E4 , default: Previous => unknown:00E4
divertable, is FN, FN sensitive, persistently divertable, reprogrammable, pos:8, group:0, gmask:0
11: unknown:00E5 , default: Play/Pause => unknown:00E5
divertable, is FN, FN sensitive, persistently divertable, reprogrammable, pos:9, group:0, gmask:0
12: unknown:00E6 , default: Next => unknown:00E6
divertable, is FN, FN sensitive, persistently divertable, reprogrammable, pos:10, group:0, gmask:0
13: unknown:00E7 , default: Mute => unknown:00E7
divertable, is FN, FN sensitive, persistently divertable, reprogrammable, pos:11, group:0, gmask:0
14: unknown:00E8 , default: Volume Down => unknown:00E8
divertable, is FN, FN sensitive, persistently divertable, reprogrammable, pos:12, group:0, gmask:0
15: unknown:00E9 , default: Volume Up => unknown:00E9
divertable, nonstandard, persistently divertable, reprogrammable, pos:0, group:0, gmask:0
16: Calculator , default: Calculator => Calculator
divertable, nonstandard, persistently divertable, reprogrammable, pos:0, group:0, gmask:0
17: unknown:00BF , default: unknown:009B => unknown:00BF
divertable, nonstandard, persistently divertable, reprogrammable, pos:0, group:0, gmask:0
18: unknown:00EA , default: unknown:00C3 => unknown:00EA
divertable, nonstandard, persistently divertable, reprogrammable, pos:0, group:0, gmask:0
19: Lock PC , default: WindowsLock => Lock PC
divertable, nonstandard, persistently divertable, reprogrammable, pos:0, group:0, gmask:0
20: unknown:00EC , default: unknown:00B8 => unknown:00EC
divertable, nonstandard, persistently divertable, pos:0, group:0, gmask:0
21: unknown:00EB , default: unknown:00B6 => unknown:00EB
divertable, nonstandard, persistently divertable, pos:0, group:0, gmask:0
22: unknown:00DE , default: Do Nothing One => unknown:00DE
is FN, pos:0, group:0, gmask:0
23: unknown:0034 , default: Do Nothing One => unknown:0034
nonstandard, pos:0, group:0, gmask:0
Battery: 0%, full.

View File

@@ -0,0 +1,43 @@
Unifying Receiver
Device path : /dev/hidraw2
USB id : 046d:c52b
Serial : C03E9E2E
Firmware : 12.01.B0019
Bootloader : 02.14
Has 2 paired device(s) out of a maximum of 6.
Notifications: wireless, software present (0x000900)
Device activity counters: 2=118
2: Wireless Keyboard K270(unifying)
Codename : K270(unifying)
Kind : keyboard
Wireless PID : 4003
Protocol : HID++ 2.0
Polling rate : 20 ms (50Hz)
Serial number: FE8C8542
Firmware: RQK 35.00.B0017
The power switch is located on the top case.
Supports 12 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: unknown:1820 {1820} hidden
6: REPROG CONTROLS {1B00}
7: WIRELESS DEVICE STATUS {1D4B}
8: unknown:1DF0 {1DF0} hidden
9: unknown:1DF3 {1DF3} hidden
10: ENCRYPTION {4100}
11: KEYBOARD LAYOUT {4520}
Has 8 reprogrammable keys:
0: Play/Pause => Play/Pause nonstandard
1: Mute => Mute nonstandard
2: Volume Down => Volume Down nonstandard
3: Volume Up => Volume Up nonstandard
4: MY HOME => HomePage nonstandard, reprogrammable
5: Mail => Email nonstandard, reprogrammable
6: SLEEP => Sleep nonstandard, reprogrammable
7: Calculator => Calculator nonstandard, reprogrammable
Battery: 90%, discharging.

93
docs/devices/k360.txt Normal file
View File

@@ -0,0 +1,93 @@
Receiver
LZ22175-DJ
LZ30965-DJ (another receiver)
M/N:C-U0007
(ltunify)
Serial number: 53B19204
Serial number: 82C3964B (another receiver)
Firmware version: 012.001.00019
Bootloader version: BL.002.014
(solaar-cli)
-: Unifying Receiver
Device path : /dev/hidraw2
Serial : 53B19204
Serial : 82C3964B (another receiver)
Firmware : 12.01.B0019
Bootloader : 02.14
Has 1 paired device(s) out of a maximum of 6
Enabled notifications: 0x000900 = wireless, software present.
Keyboard
K360
P/N: 820-003472
S/N: 1223CE0521E8
S/N: 1311CE0097D8 (another keyboard)
M/N: Y-R0017
(ltunify)
HID++ version: 2.0
Device index 1
Keyboard
Name: K360
Wireless Product ID: 4004
Serial number: 60BA944E
Device was unavailable, version information not available.
Total number of HID++ 2.0 features: 12
0: [0000] IRoot
1: [0001] IFeatureSet
2: [0003] IFirmwareInfo
3: [0005] GetDeviceNameType
4: [1000] batteryLevelStatus
5: [1820] H unknown
6: [1B00] SpecialKeysMSEButtons
7: [1D4B] WirelessDeviceStatus
8: [1DF0] H unknown
9: [1DF3] H unknown
10: [40A0] FnInversion
11: [4100] Encryption
12: [4520] KeyboardLayout
(O = obsolete feature; H = SW hidden feature)
(solaar-cli)
1: Wireless Keyboard K360
Codename : K360
Kind : keyboard
Protocol : HID++ 2.0
Polling rate : 20 ms
Wireless PID : 4004
Serial number: 60BA944E
Serial number: 0D2694C9 (another keyboard)
Firmware : RQK 36.00.B0007
The power switch is located on the top case
Supports 13 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: unknown:1820 {1820} hidden
6: REPROG CONTROLS {1B00}
7: WIRELESS DEVICE STATUS {1D4B}
8: unknown:1DF0 {1DF0} hidden
9: unknown:1DF3 {1DF3} hidden
10: FN INVERSION {40A0}
11: ENCRYPTION {4100}
12: KEYBOARD LAYOUT {4520}
Has 18 reprogrammable keys:
0: MY HOME => HomePage FN sensitive, is FN, reprogrammable
1: Mail => Mail FN sensitive, is FN, reprogrammable
2: SEARCH => Search FN sensitive, is FN, reprogrammable
3: MEDIA PLAYER => Music FN sensitive, is FN, reprogrammable
4: Application Switcher => Application Switcher FN sensitive, is FN, reprogrammable
5: SHOW DESKTOP => ShowDesktop FN sensitive, is FN, reprogrammable
6: MINIMIZE AS WIN M => WindowsMinimize FN sensitive, is FN, reprogrammable
7: MAXIMIZE AS WIN SHIFT M => WindowsRestore FN sensitive, is FN, reprogrammable
8: MY COMPUTER AS WIN E => My Computer FN sensitive, is FN, reprogrammable
9: Lock PC => WindowsLock FN sensitive, is FN, reprogrammable
10: SLEEP => Sleep FN sensitive, is FN, reprogrammable
11: Calculator => Calculator FN sensitive, is FN, reprogrammable
12: Previous => Previous nonstandard
13: Play/Pause => Play/Pause nonstandard
14: Next => Next nonstandard
15: Mute => Mute nonstandard
16: Volume Down => Volume Down nonstandard
17: Volume Up => Volume Up nonstandard
Battery is 90% charged, discharging

39
docs/devices/k750.txt Normal file
View File

@@ -0,0 +1,39 @@
(from Julien Danjou)
(solaar)
2: Wireless Solar Keyboard K750
Codename : K750
Kind : keyboard
Wireless PID : 4002
Protocol : HID++ 2.0
Polling rate : 20 ms (50Hz)
Serial number: 5692B2EC
Firmware: RQK 33.00.B0015
Bootloader: DFU 00.02.B0003
The power switch is located on the edge of top right corner.
Supports 11 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: REPROG CONTROLS {1B00}
5: WIRELESS DEVICE STATUS {1D4B}
6: unknown:1DF3 {1DF3} hidden
7: FN INVERSION {40A0}
8: ENCRYPTION {4100}
9: SOLAR DASHBOARD {4301}
10: KEYBOARD LAYOUT {4520}
Has 12 reprogrammable keys:
0: MY HOME => HomePage FN sensitive, is FN, reprogrammable
1: Mail => Email FN sensitive, is FN, reprogrammable
2: SEARCH => Search FN sensitive, is FN, reprogrammable
3: Calculator => Calculator FN sensitive, is FN, reprogrammable
4: MEDIA PLAYER => Music FN sensitive, is FN, reprogrammable
5: Previous => Previous FN sensitive, is FN
6: Play/Pause => Play/Pause FN sensitive, is FN
7: Next => Next FN sensitive, is FN
8: Mute => Mute FN sensitive, is FN
9: Volume Down => Volume Down FN sensitive, is FN
10: Volume Up => Volume Up FN sensitive, is FN
11: SLEEP => Sleep FN sensitive, is FN, reprogrammable
Battery status unavailable.

44
docs/devices/k780.txt Normal file
View File

@@ -0,0 +1,44 @@
2: K780 Multi-Device Keyboard
Codename : K780
Kind : keyboard
Wireless PID : 405B
Protocol : HID++ 4.5
Polling rate : 20 ms (50Hz)
Serial number: 4D71FEE1
Bootloader: BOT 25.00.B0005
Firmware: MPK 01.00.B0018
Other:
The power switch is located on the edge of top right corner.
Supports 31 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: WIRELESS DEVICE STATUS {1D4B}
5: RESET {0020}
6: unknown:0007 {0007}
7: BATTERY STATUS {1000}
8: CHANGE HOST {1814}
9: unknown:1815 {1815}
10: REPROG CONTROLS V4 {1B04}
11: unknown:1C00 {1C00}
12: NEW FN INVERSION {40A2}
13: ENCRYPTION {4100}
14: KEYBOARD DISABLE {4521}
15: unknown:4531 {4531}
16: LOCK KEY STATE {4220}
17: unknown:00C2 {00C2}
18: unknown:1803 {1803} internal, hidden
19: unknown:1806 {1806} internal, hidden
20: unknown:1805 {1805} internal, hidden
21: unknown:1813 {1813} internal, hidden
22: unknown:1830 {1830} internal, hidden
23: unknown:1861 {1861} internal, hidden
24: unknown:1890 {1890} internal, hidden
25: unknown:1891 {1891} internal, hidden
26: unknown:18A1 {18A1} internal, hidden
27: unknown:1DF3 {1DF3} internal, hidden
28: unknown:1E00 {1E00} hidden
29: unknown:1EB0 {1EB0} internal, hidden
30: unknown:18B0 {18B0} internal, hidden
Battery: 90%, discharging.

557
docs/devices/k800-new.txt Normal file
View File

@@ -0,0 +1,557 @@
[kamil@kamil-pc Solaar]$ bin/solaar -dd show
16:01:46,533 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 83B5 030000]
16:01:46,539 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 FF 83B5 03DC279AB20A06090000000000000000]
16:01:46,539 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 80B2 000000]
16:01:46,550 DEBUG [MainThread] logitech_receiver.base: (3) => r[20 01 4101 71401E0000000400000000]
16:01:46,551 DEBUG [MainThread] logitech_receiver.base: (3) => r[20 02 4101 6E401A4000000400000000]
16:01:46,551 DEBUG [MainThread] logitech_receiver.base: (3) => r[20 00 4102 0000000000000000000000]
16:01:46,551 DEBUG [MainThread] logitech_receiver.base: (3) => r[10 FF 8F80 B20300]
16:01:46,551 DEBUG [MainThread] logitech_receiver.base: (3) device 0xFF error on request {80B2}: 3 = invalid value
16:01:46,551 DEBUG [MainThread] solaar.cli: [/dev/hidraw0] => <UnifyingReceiver(/dev/hidraw0,3)>
16:01:46,646 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 8102 000000]
16:01:46,651 DEBUG [MainThread] logitech_receiver.base: (3) => r[10 FF 8102 000200]
Unifying Receiver
Device path : /dev/hidraw0
USB id : 046d:c52b
Serial : DC279AB2
16:01:46,652 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 81F1 010000]
16:01:46,657 DEBUG [MainThread] logitech_receiver.base: (3) => r[10 FF 81F1 012411]
16:01:46,658 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 81F1 020000]
16:01:46,664 DEBUG [MainThread] logitech_receiver.base: (3) => r[10 FF 81F1 020036]
16:01:46,664 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 81F1 040000]
16:01:46,669 DEBUG [MainThread] logitech_receiver.base: (3) => r[10 FF 81F1 040209]
16:01:46,670 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 81F1 030000]
16:01:46,675 DEBUG [MainThread] logitech_receiver.base: (3) => r[10 FF 81F1 03AAAC]
Firmware : 24.11.B0036
Bootloader : 02.09
Other : AA.AC
Has 2 paired device(s) out of a maximum of 6.
16:01:46,676 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 8100 000000]
16:01:46,681 DEBUG [MainThread] logitech_receiver.base: (3) => r[10 FF 8100 000900]
Notifications: wireless, software present (0x000900)
16:01:46,682 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 83B3 000000]
16:01:46,687 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 FF 83B3 51060000000000000000000000000000]
Device activity counters: 1=81, 2=6
16:01:46,688 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 8102 000000]
16:01:46,693 DEBUG [MainThread] logitech_receiver.base: (3) => r[10 FF 8102 000200]
16:01:46,694 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 83B5 200000]
16:01:46,699 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 FF 83B5 20090840710402020700000000000000]
16:01:46,700 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 83B5 400000]
16:01:46,705 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 FF 83B5 40094D58204D61737465720000000000]
16:01:46,706 INFO [MainThread] logitech_receiver.receiver: <UnifyingReceiver(/dev/hidraw0,3)>: found new device 1 (4071)
16:01:46,706 DEBUG [MainThread] logitech_receiver.base: (3) pinging device 1
16:01:46,706 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 001E 000016]
16:01:47,033 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000F 00000000000000000000000000000000]
16:01:47,049 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 001E 04051600000000000000000000000000]
1: Wireless Mouse MX Master
Codename : MX Master
Kind : mouse
Wireless PID : 4071
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
16:01:47,049 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 83B5 300000]
16:01:47,055 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 FF 83B5 30A6A400641E00000001000000000000]
Serial number: A6A40064
16:01:47,055 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0009 000100]
16:01:47,061 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000B 00000000000000000000000000000000]
16:01:47,077 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0009 01000100000000000000000000000000]
16:01:47,077 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0108 000000]
16:01:47,093 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000D 00000000000000000000000000000000]
16:01:47,101 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0108 1F000000000000000000000000000000]
16:01:47,101 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000C 000300]
16:01:47,109 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000B 00000000000000000000000000000000]
16:01:47,117 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000C 02000200000000000000000000000000]
16:01:47,117 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 020D 000000]
16:01:47,125 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000B 00000000000000000000000000000000]
16:01:47,133 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 020D 040382B4290006B01E40710000030000]
16:01:47,134 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 021E 000000]
16:01:47,141 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000B 00000000000000000000000000000000]
16:01:47,149 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 021E 01424F54561000050040717622661101]
16:01:47,150 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 021C 010000]
16:01:47,171 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 021C 004D504D1210000500B01E7622661101]
16:01:47,171 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 021E 020000]
16:01:47,191 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 021E 004D504D121000050140717622661101]
16:01:47,191 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 021F 030000]
16:01:47,213 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 021F 050000000000005A0000000000000000]
Bootloader: BOT 56.10.B0005
Firmware: MPM 12.10.B0005
Firmware: MPM 12.10.B0005
Other:
The power switch is located on the base.
Supports 32 HID++ 2.0 features:
16:01:47,214 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000B 000000]
16:01:47,311 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000B 00000100000000000000000000000000]
0: ROOT {0000}
16:01:47,312 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000C 000100]
16:01:47,333 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000C 01000100000000000000000000000000]
1: FEATURE SET {0001}
16:01:47,334 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000F 000300]
16:01:47,431 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000F 02000200000000000000000000000000]
2: DEVICE FW VERSION {0003}
16:01:47,431 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011C 030000]
16:01:47,453 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011C 00050000000000000000000000000000]
16:01:47,454 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000F 000500]
16:01:47,475 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000F 03000000000000000000000000000000]
3: DEVICE NAME {0005}
16:01:47,475 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0119 040000]
16:01:47,575 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0119 1D4B0000000000000000000000000000]
16:01:47,575 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000A 1D4B00]
16:01:47,593 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000A 04000000000000000000000000000000]
4: WIRELESS DEVICE STATUS {1D4B}
16:01:47,593 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011A 050000]
16:01:47,617 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011A 00200000000000000000000000000000]
16:01:47,617 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0009 002000]
16:01:47,715 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0009 05000000000000000000000000000000]
5: RESET {0020}
16:01:47,715 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011E 060000]
16:01:47,735 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011E 00210000000000000000000000000000]
16:01:47,735 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000B 002100]
16:01:47,755 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000B 06000000000000000000000000000000]
6: unknown:0021 {0021}
16:01:47,755 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011C 070000]
16:01:47,775 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011C 10000000000000000000000000000000]
16:01:47,775 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000C 100000]
16:01:47,795 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000C 07000000000000000000000000000000]
7: BATTERY STATUS {1000}
16:01:47,795 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011F 080000]
16:01:47,815 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011F 18066000000000000000000000000000]
16:01:47,815 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000C 180600]
16:01:47,835 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000C 08600000000000000000000000000000]
8: unknown:1806 {1806} internal, hidden
16:01:47,835 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0119 090000]
16:01:47,855 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0119 18140001000000000000000000000000]
16:01:47,855 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000A 181400]
16:01:47,875 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000A 09000100000000000000000000000000]
9: CHANGE HOST {1814}
16:01:47,875 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011A 0A0000]
16:01:47,895 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011A 1B040003000000000000000000000000]
16:01:47,895 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000A 1B0400]
16:01:47,915 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000A 0A000300000000000000000000000000]
10: REPROG CONTROLS V4 {1B04}
16:01:47,915 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011E 0B0000]
16:01:47,935 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011E 22010001000000000000000000000000]
16:01:47,935 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000E 220100]
16:01:47,957 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000E 0B000100000000000000000000000000]
11: ADJUSTABLE DPI {2201}
16:01:47,957 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011A 0C0000]
16:01:47,977 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011A 21000000000000000000000000000000]
16:01:47,977 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0009 210000]
16:01:47,997 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0009 0C000000000000000000000000000000]
12: VERTICAL SCROLLING {2100}
16:01:47,998 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0C0C 000000]
16:01:48,017 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0C0C 03180000000000000000000000000000]
Roller type: 3G
Ratchet per turn: 24
Scroll lines: 0
16:01:48,017 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011A 0D0000]
16:01:48,037 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011A 21100000000000000000000000000000]
16:01:48,037 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0008 211000]
16:01:48,057 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0008 0D000000000000000000000000000000]
13: SMART SHIFT {2110}
16:01:48,057 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011C 0E0000]
16:01:48,077 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011C 21210000000000000000000000000000]
16:01:48,077 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000C 212100]
16:01:48,097 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000C 0E000000000000000000000000000000]
14: HIRES WHEEL {2121}
16:01:48,097 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0E09 000000]
16:01:48,117 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0E09 080C0000000000000000000000000000]
16:01:48,117 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0E1D 000000]
16:01:48,137 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0E1D 02000000000000000000000000000000]
16:01:48,137 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0E38 000000]
16:01:48,159 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0E38 01000000000000000000000000000000]
Multiplier: 8
Has invert
Normal wheel motion
Has ratchet switch
Normal wheel mode
High resolution mode
HID notification
16:01:48,159 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011F 0F0000]
16:01:48,179 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011F 65010000000000000000000000000000]
16:01:48,179 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000A 650100]
16:01:48,199 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000A 0F000000000000000000000000000000]
15: GESTURE 2 {6501}
16:01:48,199 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0119 100000]
16:01:48,219 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0119 00C20000000000000000000000000000]
16:01:48,219 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0009 00C200]
16:01:48,239 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0009 10000000000000000000000000000000]
16: unknown:00C2 {00C2}
16:01:48,240 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011B 110000]
16:01:48,259 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011B 18136000000000000000000000000000]
16:01:48,259 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0009 181300]
16:01:48,279 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0009 11600000000000000000000000000000]
17: unknown:1813 {1813} internal, hidden
16:01:48,279 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011C 120000]
16:01:48,299 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011C 18306000000000000000000000000000]
16:01:48,299 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000C 183000]
16:01:48,319 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000C 12600000000000000000000000000000]
18: unknown:1830 {1830} internal, hidden
16:01:48,319 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011B 130000]
16:01:48,339 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011B 18906000000000000000000000000000]
16:01:48,339 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0008 189000]
16:01:48,359 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0008 13600000000000000000000000000000]
19: unknown:1890 {1890} internal, hidden
16:01:48,359 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011B 140000]
16:01:48,381 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011B 18916000000000000000000000000000]
16:01:48,381 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0008 189100]
16:01:48,401 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0008 14600000000000000000000000000000]
20: unknown:1891 {1891} internal, hidden
16:01:48,401 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011C 150000]
16:01:48,421 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011C 18A16000000000000000000000000000]
16:01:48,421 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000F 18A100]
16:01:48,441 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000F 15600000000000000000000000000000]
21: unknown:18A1 {18A1} internal, hidden
16:01:48,441 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011A 160000]
16:01:48,461 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011A 18C06000000000000000000000000000]
16:01:48,461 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0008 18C000]
16:01:48,481 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0008 16600000000000000000000000000000]
22: unknown:18C0 {18C0} internal, hidden
16:01:48,481 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011E 170000]
16:01:48,501 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011E 1DF36000000000000000000000000000]
16:01:48,501 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0009 1DF300]
16:01:48,521 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0009 17600000000000000000000000000000]
23: unknown:1DF3 {1DF3} internal, hidden
16:01:48,521 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011E 180000]
16:01:48,541 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011E 1E004000000000000000000000000000]
16:01:48,541 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0009 1E0000]
16:01:48,561 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0009 18400000000000000000000000000000]
24: unknown:1E00 {1E00} hidden
16:01:48,561 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0119 190000]
16:01:48,581 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0119 1EB06000000000000000000000000000]
16:01:48,581 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0009 1EB000]
16:01:48,603 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0009 19600000000000000000000000000000]
25: unknown:1EB0 {1EB0} internal, hidden
16:01:48,603 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011F 1A0000]
16:01:48,623 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011F 18036000000000000000000000000000]
16:01:48,623 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000F 180300]
16:01:48,643 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000F 1A600000000000000000000000000000]
26: unknown:1803 {1803} internal, hidden
16:01:48,643 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0118 1B0000]
16:01:48,663 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0118 18616000000000000000000000000000]
16:01:48,663 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0009 186100]
16:01:48,683 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0009 1B600000000000000000000000000000]
27: unknown:1861 {1861} internal, hidden
16:01:48,683 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0118 1C0000]
16:01:48,703 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0118 90016000000000000000000000000000]
16:01:48,703 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000F 900100]
16:01:48,723 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000F 1C600000000000000000000000000000]
28: unknown:9001 {9001} internal, hidden
16:01:48,723 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0119 1D0000]
16:01:48,743 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0119 92006000000000000000000000000000]
16:01:48,743 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000D 920000]
16:01:48,763 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000D 1D600000000000000000000000000000]
29: unknown:9200 {9200} internal, hidden
16:01:48,763 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 011F 1E0000]
16:01:48,783 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 011F 92026000000000000000000000000000]
16:01:48,783 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000C 920200]
16:01:48,805 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000C 1E600000000000000000000000000000]
30: unknown:9202 {9202} internal, hidden
16:01:48,805 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0119 1F0000]
16:01:48,825 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0119 18056000000000000000000000000000]
16:01:48,825 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 000B 180500]
16:01:48,845 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 000B 1F600000000000000000000000000000]
31: unknown:1805 {1805} internal, hidden
16:01:48,845 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A0A 000000]
16:01:48,865 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A0A 08000000000000000000000000000000]
Has 8 reprogrammable keys:
16:01:48,865 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A1C 000000]
16:01:48,885 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A1C 00500038010001010000000000000000]
16:01:48,885 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A2B 005000]
16:01:48,905 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A2B 00500000000000000000000000000000]
0: LEFT CLICK , default: LeftClick => LEFT CLICK
mse, pos:0, group:1, gmask:1
16:01:48,905 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A1D 010000]
16:01:48,925 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A1D 00510039010001010000000000000000]
16:01:48,925 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A28 005100]
16:01:48,945 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A28 00510000000000000000000000000000]
1: RIGHT CLICK , default: RightClick => RIGHT CLICK
mse, pos:0, group:1, gmask:1
16:01:48,945 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A1B 020000]
16:01:48,965 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A1B 0052003A310003070100000000000000]
16:01:48,965 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A2B 005200]
16:01:48,985 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A2B 00520000000000000000000000000000]
2: MIDDLE BUTTON , default: MiddleMouseButton => MIDDLE BUTTON
mse, reprogrammable, divertable, pos:0, group:3, gmask:7
16:01:48,985 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A1E 030000]
16:01:49,005 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A1E 0053003C310002030100000000000000]
16:01:49,006 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A28 005300]
16:01:49,027 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A28 00530000000000000000000000000000]
3: BACK AS BUTTON 4 , default: BackEx => BACK AS BUTTON 4
mse, reprogrammable, divertable, pos:0, group:2, gmask:3
16:01:49,027 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A1B 040000]
16:01:49,047 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A1B 0056003E310002030100000000000000]
16:01:49,047 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A2F 005600]
16:01:49,067 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A2F 00560000000000000000000000000000]
4: FORWARD AS BUTTON 5 , default: BrowserForwardEx => FORWARD AS BUTTON 5
mse, reprogrammable, divertable, pos:0, group:2, gmask:3
16:01:49,067 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A1C 050000]
16:01:49,087 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A1C 00C300A9310003070100000000000000]
16:01:49,087 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A2A 00C300]
16:01:49,107 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A2A 00C30000000000000000000000000000]
5: unknown:00C3 , default: unknown:00A9 => unknown:00C3
mse, reprogrammable, divertable, pos:0, group:3, gmask:7
16:01:49,107 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A1A 060000]
16:01:49,127 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A1A 00C4009D310003070100000000000000]
16:01:49,127 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A2C 00C400]
16:01:49,147 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A2C 00C40000000000000000000000000000]
6: unknown:00C4 , default: unknown:009D => unknown:00C4
mse, reprogrammable, divertable, pos:0, group:3, gmask:7
16:01:49,147 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A1C 070000]
16:01:49,167 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A1C 00D700B4A00004000300000000000000]
16:01:49,167 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 0A2C 00D700]
16:01:49,187 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 0A2C 00D70000000000000000000000000000]
7: unknown:00D7 , default: unknown:00B4 => unknown:00D7
divertable, virtual, pos:0, group:4, gmask:0
16:01:49,187 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 01 070B 000000]
16:01:49,207 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 01 070B 32140000000000000000000000000000]
16:01:49,207 DEBUG [MainThread] logitech_receiver.hidpp20: device 1 battery 50% charged, next level 20% charge, status 0 = discharging
Battery: 50%, discharging.
16:01:49,207 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 83B5 210000]
16:01:49,213 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 FF 83B5 210814406E0402010700000000000000]
16:01:49,213 INFO [MainThread] logitech_receiver.receiver: <UnifyingReceiver(/dev/hidraw0,3)>: found new device 2 (406E)
16:01:49,213 DEBUG [MainThread] logitech_receiver.base: (3) pinging device 2
16:01:49,213 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 001F 0000F4]
16:01:49,245 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 001F 0405F400000000000000000000000000]
2: Wireless Illuminated Keyboard K800 new
Codename : new
Kind : keyboard
Wireless PID : 406E
Protocol : HID++ 4.5
Polling rate : 20 ms (50Hz)
16:01:49,245 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 FF 83B5 310000]
16:01:49,251 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 FF 83B5 31636E14131A40000007000000000000]
Serial number: 636E1413
16:01:49,251 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000A 000100]
16:01:49,285 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000A 01000100000000000000000000000000]
16:01:49,285 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 010B 000000]
16:01:49,325 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 010B 18000000000000000000000000000000]
16:01:49,325 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0009 000300]
16:01:49,365 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0009 02000200000000000000000000000000]
16:01:49,365 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 020C 000000]
16:01:49,405 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 020C 0254FC62F90004406E00000000010000]
16:01:49,405 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 021E 000000]
16:01:49,446 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 021E 01424F546000000200406ED4E7454501]
16:01:49,446 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 021C 010000]
16:01:49,487 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 021C 0052514B6801000901406ED4E7454501]
Bootloader: BOT 60.00.B0002
Firmware: RQK 68.01.B0009
The power switch is located on the top right corner.
Supports 25 HID++ 2.0 features:
16:01:49,487 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000F 000000]
16:01:49,527 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000F 00000100000000000000000000000000]
0: ROOT {0000}
16:01:49,527 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000F 000100]
16:01:49,567 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000F 01000100000000000000000000000000]
1: FEATURE SET {0001}
16:01:49,568 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000C 000300]
16:01:49,607 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000C 02000200000000000000000000000000]
2: DEVICE FW VERSION {0003}
16:01:49,607 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011A 030000]
16:01:49,647 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011A 00050000000000000000000000000000]
16:01:49,647 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000D 000500]
16:01:49,687 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000D 03000000000000000000000000000000]
3: DEVICE NAME {0005}
16:01:49,687 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011C 040000]
16:01:49,729 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011C 1D4B0000000000000000000000000000]
16:01:49,729 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000D 1D4B00]
16:01:49,770 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000D 04000000000000000000000000000000]
4: WIRELESS DEVICE STATUS {1D4B}
16:01:49,770 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0119 050000]
16:01:49,809 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0119 00200000000000000000000000000000]
16:01:49,809 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000D 002000]
16:01:49,849 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000D 05000000000000000000000000000000]
5: RESET {0020}
16:01:49,849 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0118 060000]
16:01:49,889 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0118 10000000000000000000000000000000]
16:01:49,889 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0009 100000]
16:01:49,929 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0009 06000000000000000000000000000000]
6: BATTERY STATUS {1000}
16:01:49,929 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011D 070000]
16:01:49,969 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011D 19830000000000000000000000000000]
16:01:49,969 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000B 198300]
16:01:50,009 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000B 07000000000000000000000000000000]
7: unknown:1983 {1983}
16:01:50,010 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011F 080000]
16:01:50,051 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011F 1B040003000000000000000000000000]
16:01:50,051 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000E 1B0400]
16:01:50,091 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000E 08000300000000000000000000000000]
8: REPROG CONTROLS V4 {1B04}
16:01:50,091 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0119 090000]
16:01:50,131 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0119 40A00000000000000000000000000000]
16:01:50,131 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0009 40A000]
16:01:50,171 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0009 09000000000000000000000000000000]
9: FN INVERSION {40A0}
16:01:50,171 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011C 0A0000]
16:01:50,211 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011C 41000000000000000000000000000000]
16:01:50,211 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000A 410000]
16:01:50,251 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000A 0A000000000000000000000000000000]
10: ENCRYPTION {4100}
16:01:50,251 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0118 0B0000]
16:01:50,293 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0118 45210000000000000000000000000000]
16:01:50,293 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000F 452100]
16:01:50,333 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000F 0B000000000000000000000000000000]
11: KEYBOARD DISABLE {4521}
16:01:50,334 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011E 0C0000]
16:01:50,373 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011E 00C20000000000000000000000000000]
16:01:50,373 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000F 00C200]
16:01:50,413 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000F 0C000000000000000000000000000000]
12: unknown:00C2 {00C2}
16:01:50,414 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0118 0D0000]
16:01:50,453 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0118 18036000000000000000000000000000]
16:01:50,454 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0008 180300]
16:01:50,493 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0008 0D600000000000000000000000000000]
13: unknown:1803 {1803} internal, hidden
16:01:50,494 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011D 0E0000]
16:01:50,533 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011D 18066001000000000000000000000000]
16:01:50,533 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000C 180600]
16:01:50,575 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000C 0E600100000000000000000000000000]
14: unknown:1806 {1806} internal, hidden
16:01:50,576 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011A 0F0000]
16:01:50,615 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011A 18116000000000000000000000000000]
16:01:50,615 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0008 181100]
16:01:50,655 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0008 0F600000000000000000000000000000]
15: unknown:1811 {1811} internal, hidden
16:01:50,656 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011B 100000]
16:01:50,695 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011B 18306000000000000000000000000000]
16:01:50,696 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000F 183000]
16:01:50,735 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000F 10600000000000000000000000000000]
16: unknown:1830 {1830} internal, hidden
16:01:50,736 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0119 110000]
16:01:50,775 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0119 18906000000000000000000000000000]
16:01:50,776 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000A 189000]
16:01:50,815 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000A 11600000000000000000000000000000]
17: unknown:1890 {1890} internal, hidden
16:01:50,816 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0118 120000]
16:01:50,858 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0118 18A16000000000000000000000000000]
16:01:50,858 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000F 18A100]
16:01:50,897 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000F 12600000000000000000000000000000]
18: unknown:18A1 {18A1} internal, hidden
16:01:50,898 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0118 130000]
16:01:50,937 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0118 1DF36000000000000000000000000000]
16:01:50,938 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000B 1DF300]
16:01:50,977 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000B 13600000000000000000000000000000]
19: unknown:1DF3 {1DF3} internal, hidden
16:01:50,978 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011B 140000]
16:01:51,017 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011B 1E004000000000000000000000000000]
16:01:51,018 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000E 1E0000]
16:01:51,057 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000E 14400000000000000000000000000000]
20: unknown:1E00 {1E00} hidden
16:01:51,058 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011B 150000]
16:01:51,097 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011B 1EB06000000000000000000000000000]
16:01:51,098 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000F 1EB000]
16:01:51,137 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000F 15600000000000000000000000000000]
21: unknown:1EB0 {1EB0} internal, hidden
16:01:51,138 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011D 160000]
16:01:51,179 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011D 18616000000000000000000000000000]
16:01:51,180 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000E 186100]
16:01:51,220 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000E 16600000000000000000000000000000]
22: unknown:1861 {1861} internal, hidden
16:01:51,220 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 011D 170000]
16:01:51,260 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 011D 1A206000000000000000000000000000]
16:01:51,260 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0008 1A2000]
16:01:51,300 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0008 17600000000000000000000000000000]
23: unknown:1A20 {1A20} internal, hidden
16:01:51,300 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0118 180000]
16:01:51,339 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0118 18B06000000000000000000000000000]
16:01:51,340 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 000E 18B000]
16:01:51,379 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 000E 18600000000000000000000000000000]
24: unknown:18B0 {18B0} internal, hidden
16:01:51,380 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 080E 000000]
16:01:51,419 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 080E 0F000000000000000000000000000000]
Has 15 reprogrammable keys:
16:01:51,420 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 081C 000000]
16:01:51,461 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 081C 0022001A3A0100000000000000000000]
16:01:51,462 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 082F 002200]
16:01:51,501 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 082F 00220000000000000000000000000000]
0: MY HOME , default: HomePage => MY HOME
is FN, FN sensitive, reprogrammable, divertable, pos:1, group:0, gmask:0
16:01:51,502 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0819 010000]
16:01:51,541 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0819 000E000E3A0200000000000000000000]
16:01:51,542 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0829 000E00]
16:01:51,581 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0829 000E0000000000000000000000000000]
1: Mail , default: Email => Mail
is FN, FN sensitive, reprogrammable, divertable, pos:2, group:0, gmask:0
16:01:51,582 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0818 020000]
16:01:51,621 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0818 003E002D3A0300000000000000000000]
16:01:51,622 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0828 003E00]
16:01:51,661 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0828 003E0000000000000000000000000000]
2: SEARCH , default: SearchForFiles => SEARCH
is FN, FN sensitive, reprogrammable, divertable, pos:3, group:0, gmask:0
16:01:51,662 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 081B 030000]
16:01:51,701 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 081B 000800083A0400000000000000000000]
16:01:51,702 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 082E 000800]
16:01:51,743 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 082E 00080000000000000000000000000000]
3: Application Switcher , default: Application Switcher => Application Switcher
is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, gmask:0
16:01:51,744 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 081D 040000]
16:01:51,784 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 081D 00E200C12A0500000000000000000000]
16:01:51,784 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 082E 00E200]
16:01:51,824 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 082E 00E20000000000000000000000000000]
4: unknown:00E2 , default: unknown:00C1 => unknown:00E2
is FN, FN sensitive, divertable, pos:5, group:0, gmask:0
16:01:51,824 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 081A 050000]
16:01:51,864 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 081A 00E300C22A0600000000000000000000]
16:01:51,864 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 082B 00E300]
16:01:51,904 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 082B 00E30000000000000000000000000000]
5: unknown:00E3 , default: unknown:00C2 => unknown:00E3
is FN, FN sensitive, divertable, pos:6, group:0, gmask:0
16:01:51,904 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0818 060000]
16:01:51,943 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0818 0040002F3A0800000000000000000000]
16:01:51,944 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 082E 004000]
16:01:51,984 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 082E 00400000000000000000000000000000]
6: SLEEP , default: Sleep => SLEEP
is FN, FN sensitive, reprogrammable, divertable, pos:8, group:0, gmask:0
16:01:51,984 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 081D 070000]
16:01:52,025 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 081D 0028001D3A0900000000000000000000]
16:01:52,026 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0828 002800]
16:01:52,065 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0828 00280000000000000000000000000000]
7: MEDIA PLAYER , default: Music => MEDIA PLAYER
is FN, FN sensitive, reprogrammable, divertable, pos:9, group:0, gmask:0
16:01:52,066 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 081F 080000]
16:01:52,106 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 081F 000600062A0A00000000000000000000]
16:01:52,106 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0828 000600]
16:01:52,145 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0828 00060000000000000000000000000000]
8: Previous , default: Previous => Previous
is FN, FN sensitive, divertable, pos:10, group:0, gmask:0
16:01:52,146 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 081F 090000]
16:01:52,186 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 081F 000400042A0B00000000000000000000]
16:01:52,186 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 082B 000400]
16:01:52,225 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 082B 00040000000000000000000000000000]
9: Play/Pause , default: Play/Pause => Play/Pause
is FN, FN sensitive, divertable, pos:11, group:0, gmask:0
16:01:52,226 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 081B 0A0000]
16:01:52,265 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 081B 000500052A0C00000000000000000000]
16:01:52,266 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0829 000500]
16:01:52,308 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0829 00050000000000000000000000000000]
10: Next , default: Next => Next
is FN, FN sensitive, divertable, pos:12, group:0, gmask:0
16:01:52,308 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0818 0B0000]
16:01:52,348 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0818 00010001240000000000000000000000]
16:01:52,348 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 082C 000100]
16:01:52,387 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 082C 00010000000000000000000000000000]
11: Volume Up , default: Volume Up => Volume Up
nonstandard, divertable, pos:0, group:0, gmask:0
16:01:52,388 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 081C 0C0000]
16:01:52,427 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 081C 00020002240000000000000000000000]
16:01:52,428 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 082C 000200]
16:01:52,468 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 082C 00020000000000000000000000000000]
12: Volume Down , default: Volume Down => Volume Down
nonstandard, divertable, pos:0, group:0, gmask:0
16:01:52,468 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 0819 0D0000]
16:01:52,507 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 0819 00030003240000000000000000000000]
16:01:52,508 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 082D 000300]
16:01:52,547 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 082D 00030000000000000000000000000000]
13: Mute , default: Mute => Mute
nonstandard, divertable, pos:0, group:0, gmask:0
16:01:52,548 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 081B 0E0000]
16:01:52,589 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 081B 000A000A340000000000000000000000]
16:01:52,590 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 082F 000A00]
16:01:52,630 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 082F 000A0000000000000000000000000000]
14: Calculator , default: Calculator => Calculator
nonstandard, reprogrammable, divertable, pos:0, group:0, gmask:0
16:01:52,630 DEBUG [MainThread] logitech_receiver.base: (3) <= w[10 02 060C 000000]
16:01:52,670 DEBUG [MainThread] logitech_receiver.base: (3) => r[11 02 060C 32140000000000000000000000000000]
16:01:52,670 DEBUG [MainThread] logitech_receiver.hidpp20: device 2 battery 50% charged, next level 20% charge, status 0 = discharging
Battery: 50%, discharging.

52
docs/devices/k800.txt Normal file
View File

@@ -0,0 +1,52 @@
# 0x00 - Enabled Notifications. rw (see HID++ 1.0 spec)
<< ( 0.055) [10 02 8100 000000] '\x10\x02\x81\x00\x00\x00\x00'
>> ( 0.084) [10 02 8100 000000] '\x10\x02\x81\x00\x00\x00\x00'
# 0x01 - Keyboard hand detection. rw, last param is 00 when hand detection is
# enabled, 30 when disabled. (when enabled, keyboard will light up if not
# already when hovering over the front)
<< ( 1.085) [10 02 8101 000000] '\x10\x02\x81\x01\x00\x00\x00'
>> ( 1.114) [10 02 8101 000000] '\x10\x02\x81\x01\x00\x00\x00'
# 0x07 - Battery status (3 = one bar; 1 = red/critical; 5=two bars; 7=three
# bars/full. Second returned param is 25 when keyboard is charging )
<< ( 7.327) [10 02 8107 000000] '\x10\x02\x81\x07\x00\x00\x00'
>> ( 7.368) [10 02 8107 030000] '\x10\x02\x81\x07\x03\x00\x00'
# 0x09 - F key function. rw (read: status, set/get: 00 01 00 means swap
# functions, 00 00 00 means do not swap functions)
<< ( 9.411) [10 02 8109 000000] '\x10\x02\x81\t\x00\x00\x00'
>> ( 9.440) [10 02 8109 000000] '\x10\x02\x81\t\x00\x00\x00'
# 0x17 - Illumination info r/w. Last param: 02 to disable backlight, 01 to
# enable backlight
<< ( 24.965) [10 02 8117 000000] '\x10\x02\x81\x17\x00\x00\x00'
>> ( 24.988) [10 02 8117 3C0001] '\x10\x02\x81\x17<\x00\x01'
# 0x51 - ?
<< ( 99.294) [10 02 8151 000000] '\x10\x02\x81Q\x00\x00\x00'
>> ( 99.543) [10 02 8151 000000] '\x10\x02\x81Q\x00\x00\x00'
# 0x54 - ?
<< ( 103.046) [10 02 8154 000000] '\x10\x02\x81T\x00\x00\x00'
>> ( 103.295) [10 02 8154 FF0000] '\x10\x02\x81T\xff\x00\x00'
# 0xD0 - ?
<< ( 253.860) [10 02 81D0 000000] '\x10\x02\x81\xd0\x00\x00\x00'
>> ( 253.883) [10 02 81D0 000000] '\x10\x02\x81\xd0\x00\x00\x00'
# 0xF1 - Version info (params 0n 00 00 where n is 1..4)
<< ( 289.991) [10 02 81F1 000000] '\x10\x02\x81\xf1\x00\x00\x00'
>> ( 290.032) [10 02 8F81 F10300] '\x10\x02\x8f\x81\xf1\x03\x00'
# 0xF3 - ?
<< ( 292.075) [10 02 81F3 000000] '\x10\x02\x81\xf3\x00\x00\x00'
>> ( 292.116) [10 02 81F3 000000] '\x10\x02\x81\xf3\x00\x00\x00'
# 0x0F - This changes, the last commented line was observed in an earlier run
<< ( 17.728) [10 02 830F 000000] '\x10\x02\x83\x0f\x00\x00\x00'
>> ( 17.976) [11 02 830F FFFB00000240025C000000000FF90080] '\x11\x02\x83\x0f\xff\xfb\x00\x00\x02@\x02\\\x00\x00\x00\x00\x0f\xf9\x00\x80'
#>> ( 17.999) [11 02 830F FFFC007F0243025D000000000FF60080] '\x11\x02\x83\x0f\xff\xfc\x00\x7f\x02C\x02]\x00\x00\x00\x00\x0f\xf6\x00\x80'
# See also https://git.lekensteyn.nl/ltunify/tree/registers.txt for a verbose
# meaning of registers and params.

41
docs/devices/k830.txt Normal file
View File

@@ -0,0 +1,41 @@
# Provided by Mikkel Munch Mortensen
(solaar)
3: Illuminated Living-Room Keyboard K830
Codename : K830
Kind : keyboard
Wireless PID : 4032
Protocol : HID++ 4.1
Polling rate : 8 ms (125Hz)
Serial number: 9F7C6FD7
Firmware: RQK 56.00.B0020
The power switch is located on the edge of top right corner.
Supports 27 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: WIRELESS DEVICE STATUS {1D4B}
5: unknown:0020 {0020}
6: BATTERY STATUS {1000}
7: BACKLIGHT {1981}
8: unknown:1B04 {1B04}
9: unknown:2005 {2005}
10: NEW FN INVERSION {40A2}
11: ENCRYPTION {4100}
12: unknown:4521 {4521}
13: TOUCHPAD RAW XY {6100} hidden
14: unknown:6501 {6501}
15: unknown:00C1 {00C1}
16: unknown:1811 {1811} internal, hidden
17: unknown:1830 {1830} internal, hidden
18: unknown:1890 {1890} internal, hidden
19: unknown:18A0 {18A0} internal, hidden
20: unknown:1DF3 {1DF3} internal, hidden
21: unknown:1E00 {1E00} hidden
22: unknown:1EB0 {1EB0} internal, hidden
23: unknown:1861 {1861} internal, hidden
24: unknown:1A20 {1A20} internal, hidden
25: unknown:18B0 {18B0} internal, hidden
26: unknown:1F07 {1F07} internal, hidden
Battery: 50%, discharging.

49
docs/devices/m185_new.txt Normal file
View File

@@ -0,0 +1,49 @@
P/N: 810-005238
Unifying Receiver
Device path : /dev/hidraw3
USB id : 046d:c534
Serial : 0
Firmware : 29.01.B0016
Has 1 paired device(s) out of a maximum of 6.
Notifications: (none)
2: Wireless Mouse M185
Codename : M185
Kind : mouse
Wireless PID : 4054
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
Serial number: 1377ED51
Firmware: RQM 64.00.B0008
The power switch is located on the base.
Supports 20 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: RESET {0020}
5: REPROG CONTROLS V4 {1B04}
6: WIRELESS DEVICE STATUS {1D4B}
7: LOWRES WHEEL {2130}
8: POINTER SPEED {2205}
9: unknown:1802 {1802} internal, hidden
10: unknown:1810 {1810} internal, hidden
11: unknown:1830 {1830} internal, hidden
12: unknown:1850 {1850} internal, hidden
13: unknown:1869 {1869} internal, hidden
14: unknown:1890 {1890} internal, hidden
15: unknown:18B1 {18B1} internal, hidden
16: unknown:1DF3 {1DF3} internal, hidden
17: unknown:1E00 {1E00} hidden
18: unknown:1F03 {1F03} internal, hidden
19: unknown:1E80 {1E80} internal, hidden
Has 3 reprogrammable keys:
0: LEFT CLICK , default: LeftClick => LEFT CLICK
mse, reprogrammable, pos:0, group:1, gmask:1
1: RIGHT CLICK , default: RightClick => RIGHT CLICK
mse, reprogrammable, pos:0, group:1, gmask:1
2: MIDDLE BUTTON , default: MiddleMouseButton => MIDDLE BUTTON
divertable, mse, reprogrammable, pos:0, group:2, gmask:3
Battery status unavailable.

51
docs/devices/m185_old.txt Normal file
View File

@@ -0,0 +1,51 @@
P/N: 810-003496
Unifying Receiver
Device path : /dev/hidraw3
USB id : 046d:c52f
Serial : 6D0342C5
Firmware : 30.00.B0009
Has 1 paired device(s) out of a maximum of 1.
Notifications: (none)
1: Wireless Mouse
Codename : Wireless Mouse
Kind : mouse
Wireless PID : 4055
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
Serial number: 6D0342C5
Firmware: RQM 65.00.B0003
The power switch is located on the base.
Supports 22 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: RESET {0020}
5: BATTERY STATUS {1000}
6: unknown:1810 {1810} internal, hidden
7: unknown:1830 {1830} internal, hidden
8: unknown:1802 {1802} internal, hidden
9: unknown:1862 {1862} internal, hidden
10: unknown:1890 {1890} internal, hidden
11: unknown:18A0 {18A0} internal, hidden
12: unknown:18B1 {18B1} internal, hidden
13: REPROG CONTROLS V4 {1B04}
14: WIRELESS DEVICE STATUS {1D4B}
15: unknown:1DF0 {1DF0} hidden
16: unknown:1DF3 {1DF3} internal, hidden
17: unknown:1E00 {1E00} hidden
18: unknown:1EB0 {1EB0} internal, hidden
19: unknown:1F03 {1F03} internal, hidden
20: LOWRES WHEEL {2130}
21: POINTER SPEED {2205}
Has 3 reprogrammable keys:
0: LEFT CLICK , default: LeftClick => LEFT CLICK
mse, reprogrammable, pos:0, group:1, gmask:1
1: RIGHT CLICK , default: RightClick => RIGHT CLICK
mse, reprogrammable, pos:0, group:1, gmask:1
2: MIDDLE BUTTON , default: MiddleMouseButton => MIDDLE BUTTON
divertable, mse, reprogrammable, pos:0, group:2, gmask:3
Battery: 5%, discharging.

40
docs/devices/m235.txt Normal file
View File

@@ -0,0 +1,40 @@
Wireless Mouse M235
Codename : M235
Kind : mouse
Wireless PID : 4055
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
Serial number: 00000000
Firmware: RQM 65.00.B0003
The power switch is located on the base.
Supports 22 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: RESET {0020}
5: BATTERY STATUS {1000}
6: unknown:1810 {1810} internal, hidden
7: unknown:1830 {1830} internal, hidden
8: unknown:1802 {1802} internal, hidden
9: unknown:1862 {1862} internal, hidden
10: unknown:1890 {1890} internal, hidden
11: unknown:18A0 {18A0} internal, hidden
12: unknown:18B1 {18B1} internal, hidden
13: REPROG CONTROLS V4 {1B04}
14: WIRELESS DEVICE STATUS {1D4B}
15: unknown:1DF0 {1DF0} hidden
16: unknown:1DF3 {1DF3} internal, hidden
17: unknown:1E00 {1E00} hidden
18: unknown:1EB0 {1EB0} internal, hidden
19: unknown:1F03 {1F03} internal, hidden
20: LOWRES WHEEL {2130}
21: POINTER SPEED {2205}
Has 3 reprogrammable keys:
0: LEFT CLICK , default: LeftClick => LEFT CLICK
divertable, mse, pos:0, group:1, gmask:1
1: RIGHT CLICK , default: RightClick => RIGHT CLICK
divertable, mse, pos:0, group:1, gmask:1
2: MIDDLE BUTTON , default: MiddleMouseButton => MIDDLE BUTTON
divertable, mse, reprogrammable, pos:0, group:2, gmask:3
Battery: 70%, discharging.

29
docs/devices/m325.txt Normal file
View File

@@ -0,0 +1,29 @@
Wireless Mouse M325
Codename : M325
Kind : mouse
Wireless PID : 400A
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: ABB05E01
Firmware: RQM 27.02.B0028
The power switch is located on the base.
Supports 13 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: WIRELESS DEVICE STATUS {1D4B}
6: unknown:1DF3 {1DF3} hidden
7: REPROG CONTROLS {1B00}
8: unknown:1DF0 {1DF0} hidden
9: unknown:1F03 {1F03} hidden
10: VERTICAL SCROLLING {2100}
11: HI RES SCROLLING {2120}
12: MOUSE POINTER {2200}
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 => Back mse, reprogrammable
4: FORWARD AS BUTTON 5 => BrowserForward mse, reprogrammable

56
docs/devices/m345.txt Normal file
View File

@@ -0,0 +1,56 @@
Receiver
LZ141AX-DJ
M/N: C-U0008
(ltunify)
Serial number: 574197D3
Firmware version: 024.000.00018
Bootloader version: BL.000.006
Mouse
HID++ version: 2.0
Device index 1
Mouse
Name: M345
Wireless Product ID: 4017
Serial number: 920DC223
Device was unavailable, version information not available.
Total number of HID++ 2.0 features: 12
0: [0000] IRoot
1: [0001] IFeatureSet
2: [0003] IFirmwareInfo
3: [0005] GetDeviceNameType
4: [1000] batteryLevelStatus
5: [1D4B] WirelessDeviceStatus
6: [1DF3] H unknown
7: [1B00] SpecialKeysMSEButtons
8: [1DF0] H unknown
9: [1F03] H unknown
10: [2100] VerticalScrolling
11: [2120] HiResScrolling
12: [2200] MousePointer
(O = obsolete feature; H = SW hidden feature)
(solaar-cli)
1: Wireless Mouse M345
Codename : M345
Kind : mouse
Wireless PID : 4017
Protocol : HID++ 2.0
Polling rate : 8 ms
Serial number: 920DC223
Firmware: RQM 27.02.B0028
The power switch is located on the base.
Supports 13 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: WIRELESS DEVICE STATUS {1D4B}
6: unknown:1DF3 {1DF3} hidden
7: REPROG CONTROLS {1B00}
8: unknown:1DF0 {1DF0} hidden
9: unknown:1F03 {1F03} hidden
10: VERTICAL SCROLLING {2100}
11: HI RES SCROLLING {2120}
12: MOUSE POINTER {2200}
Battery: 90%, discharging,

View File

@@ -1,8 +1,8 @@
# ?
# notification flags
<< ( 0.001) [10 01 8100 000000] '\x10\x01\x81\x00\x00\x00\x00'
>> ( 0.062) [10 01 8100 000000] '\x10\x01\x81\x00\x00\x00\x00'
# ?
# smooth scroll
<< ( 1.063) [10 01 8101 000000] '\x10\x01\x81\x01\x00\x00\x00'
>> ( 1.078) [10 01 8101 820000] '\x10\x01\x81\x01\x82\x00\x00'
@@ -10,7 +10,7 @@
<< ( 2.079) [10 01 8102 000000] '\x10\x01\x81\x02\x00\x00\x00'
>> ( 2.094) [10 01 8102 000080] '\x10\x01\x81\x02\x00\x00\x80'
# ?
# battery status
<< ( 7.263) [10 01 8107 000000] '\x10\x01\x81\x07\x00\x00\x00'
>> ( 7.278) [10 01 8107 050000] '\x10\x01\x81\x07\x05\x00\x00'

34
docs/devices/m515.txt Normal file
View File

@@ -0,0 +1,34 @@
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,

56
docs/devices/m525.txt Normal file
View File

@@ -0,0 +1,56 @@
Mouse
(ltunify)
HID++ version: 2.0
Device index 1
Mouse
Name: M525
Wireless Product ID: 4013
Serial number: DAFA335E
Device was unavailable, version information not available.
Total number of HID++ 2.0 features: 12
0: [0000] IRoot
1: [0001] IFeatureSet
2: [0003] IFirmwareInfo
3: [0005] GetDeviceNameType
4: [1000] batteryLevelStatus
5: [1D4B] WirelessDeviceStatus
6: [1DF3] H unknown
7: [1B00] SpecialKeysMSEButtons
8: [1DF0] H unknown
9: [1F03] H unknown
10: [2100] VerticalScrolling
11: [2120] HiResScrolling
12: [2200] MousePointer
(O = obsolete feature; H = SW hidden feature;
I = reserved for internal use)
(solaar)
1: Wireless Mouse M525
Codename : M525
Kind : mouse
Wireless PID : 4013
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: DAFA335E
Firmware: RQM 27.02.B0028
The power switch is located on the base.
Supports 13 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: WIRELESS DEVICE STATUS {1D4B}
6: unknown:1DF3 {1DF3} hidden
7: REPROG CONTROLS {1B00}
8: unknown:1DF0 {1DF0} hidden
9: unknown:1F03 {1F03} hidden
10: VERTICAL SCROLLING {2100}
11: HI RES SCROLLING {2120}
12: MOUSE POINTER {2200}
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 => Back mse, reprogrammable
4: FORWARD AS BUTTON 5 => BrowserForward mse, reprogrammable
Battery: 90%, discharging.

41
docs/devices/m560.txt Normal file
View File

@@ -0,0 +1,41 @@
1: Wireless Mouse M560
Codename : M560
Kind : mouse
Wireless PID : 402D
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: 16E6E42A
Firmware: RQM 48.00.B0015
The power switch is located on the base.
Supports 22 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: unknown:1830 {1830} internal, hidden
6: unknown:1850 {1850} internal, hidden
7: unknown:1860 {1860} internal, hidden
8: unknown:1890 {1890} internal, hidden
9: unknown:18A0 {18A0} internal, hidden
10: REPROG CONTROLS V3 {1B03}
11: WIRELESS DEVICE STATUS {1D4B}
12: unknown:1DF3 {1DF3} internal, hidden
13: REPROG CONTROLS {1B00}
14: unknown:1DF0 {1DF0} hidden
15: unknown:1E00 {1E00} hidden
16: unknown:18B0 {18B0} internal, hidden
17: unknown:1E90 {1E90} internal, hidden
18: unknown:1F03 {1F03} internal, hidden
19: VERTICAL SCROLLING {2100}
20: HI RES SCROLLING {2120}
21: MOUSE POINTER {2200}
Has 7 reprogrammable keys:
0: LEFT CLICK => LeftClick mse, reprogrammable
1: RIGHT CLICK => RightClick mse, reprogrammable
2: BACK AS BUTTON 4 => Win8BackHorzLeft mse, reprogrammable
3: FORWARD AS BUTTON 5 => Win8ForwardHorzRight mse, reprogrammable
4: unknown:00B0 => Win8MetroWin7Forward mse, reprogrammable
5: SHOW DESKTOP HPP => Win8ShowDesktopWin7Back mse, reprogrammable
6: unknown:00AF => Win8Charm Appswitch GifAnimation mse, reprogrammable, unknown:000020
Battery: 70%, discharging.

25
docs/devices/m570.txt Normal file
View File

@@ -0,0 +1,25 @@
Unifying Receiver
Device path : /dev/hidraw0
USB id : 046d:c52b
Serial : BAFF9007
Firmware : 12.03.B0025
Bootloader : 02.15
Other : AA.AA
Has 1 paired device(s) out of a maximum of 6.
Notifications: wireless, software present (0x000900)
Device activity counters: 1=221
1: Wireless Trackball M570
Codename : M570
Kind : mouse
Wireless PID : 1028
Protocol : HID++ 1.0
Polling rate : 8 ms (125Hz)
Serial number: 891DC05A
Firmware: 26.00.B0003
Bootloader: 02.06
Other: 00.01
The power switch is located on the base.
Notifications: battery status (0x100000).
Battery: 100%, discharging.

83
docs/devices/m585.txt Normal file
View File

@@ -0,0 +1,83 @@
Unifying Receiver
Device path : /dev/hidraw0
USB id : 046d:c52b
Serial : E21FAD57
Firmware : 24.06.B0030
Bootloader : 01.08
Other : AA.AC
Has 2 paired device(s) out of a maximum of 6.
Notifications: wireless, software present (0x000900)
Device activity counters: 1=190, 2=66
2: Multi Device Silent Mouse M585/M590
Codename : M585/M590
Kind : mouse
Wireless PID : 406B
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
Serial number: 22AEB299
Bootloader: BOT 48.01.B0002
Firmware: MPM 05.10.B0011
Other:
The power switch is located on the base.
Supports 35 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: WIRELESS DEVICE STATUS {1D4B}
5: RESET {0020}
6: unknown:0021 {0021}
7: unknown:0007 {0007}
8: BATTERY STATUS {1000}
9: CHANGE HOST {1814}
10: unknown:1815 {1815}
11: REPROG CONTROLS V4 {1B04}
12: unknown:1C00 {1C00}
13: POINTER SPEED {2205}
Pointer Speed: 1.31640625
14: VERTICAL SCROLLING {2100}
Roller type: standard
Ratchet per turn: 18
Scroll lines: 0
15: unknown:00C2 {00C2}
16: unknown:1802 {1802} internal, hidden
17: unknown:1803 {1803} internal, hidden
18: unknown:1806 {1806} internal, hidden
19: unknown:1805 {1805} internal, hidden
20: unknown:1813 {1813} internal, hidden
21: unknown:1830 {1830} internal, hidden
22: unknown:1861 {1861} internal, hidden
23: unknown:1890 {1890} internal, hidden
24: unknown:1891 {1891} internal, hidden
25: unknown:18A1 {18A1} internal, hidden
26: unknown:1DF3 {1DF3} internal, hidden
27: unknown:1E00 {1E00} hidden
28: unknown:1EB0 {1EB0} internal, hidden
29: unknown:18B1 {18B1} internal, hidden
30: unknown:1850 {1850} internal, hidden
31: unknown:1E22 {1E22}
32: unknown:1F03 {1F03} internal, hidden
33: unknown:18C0 {18C0} internal, hidden
34: LOWRES WHEEL {2130}
Wheel Reports: HID
Has 8 reprogrammable keys:
0: LEFT CLICK , default: LeftClick => LEFT CLICK
mse, reprogrammable, pos:0, group:1, gmask:1
1: RIGHT CLICK , default: RightClick => RIGHT CLICK
mse, reprogrammable, pos:0, group:1, gmask:1
2: MIDDLE BUTTON , default: MiddleMouseButton => MIDDLE BUTTON
divertable, mse, persistently divertable, reprogrammable, pos:0, group:2, gmask:3
3: BACK AS BUTTON 4 , default: BackEx => BACK AS BUTTON 4
divertable, mse, persistently divertable, reprogrammable, pos:0, group:2, gmask:3
4: FORWARD AS BUTTON 5 , default: BrowserForwardEx => FORWARD AS BUTTON 5
divertable, mse, persistently divertable, reprogrammable, pos:0, group:2, gmask:3
5: LEFT SCROLL AS AC PAN , default: HorzScrollLeftSet => LEFT SCROLL AS AC PAN
divertable, mse, persistently divertable, reprogrammable, pos:0, group:2, gmask:3
6: RIGHT SCROLL AS AC PAN , default: HorzScrollRightSet => RIGHT SCROLL AS AC PAN
divertable, mse, persistently divertable, reprogrammable, pos:0, group:2, gmask:3
7: unknown:00D7 , default: unknown:00B4 => unknown:00D7
divertable, virtual, pos:0, group:3, gmask:0
Battery: 50%, discharging.

View File

@@ -36,7 +36,7 @@ registers:
<< ( 259.270) [10 02 81F1 000000] '\x10\x02\x81\xf1\x00\x00\x00'
>> ( 259.283) [10 02 8F81 F10300] '\x10\x02\x8f\x81\xf1\x03\x00'
# writing 01 here will trigger an avalance of events, most likely
# writing 01 here will trigger an avalanche of events, most likely
# raw input from the mouse; disable by writing 00
<< ( 261.300) [10 02 81F3 000000] '\x10\x02\x81\xf3\x00\x00\x00'
>> ( 261.315) [10 02 81F3 000000] '\x10\x02\x81\xf3\x00\x00\x00'

View File

@@ -0,0 +1,82 @@
Unifying Receiver
Device path : /dev/hidraw1
USB id : 046d:c534
Serial : 0
Firmware : 29.00.B0015
Has 2 paired device(s) out of a maximum of 6.
Notifications: (none)
1: Wireless Keyboard MK270
Codename : MK270
Kind : keyboard
Wireless PID : 4023
Protocol : HID++ 2.0
Polling rate : 20 ms (50Hz)
Serial number: 00000000
Firmware: RQK 49.00.B0029
Supports 18 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: REPROG CONTROLS {1B00}
6: WIRELESS DEVICE STATUS {1D4B}
7: FN INVERSION {40A0}
8: ENCRYPTION {4100}
9: KEYBOARD LAYOUT {4520}
10: unknown:1810 {1810} internal, hidden
11: unknown:1830 {1830} internal, hidden
12: unknown:1890 {1890} internal, hidden
13: unknown:18A0 {18A0} internal, hidden
14: unknown:18B0 {18B0} internal, hidden
15: unknown:1DF3 {1DF3} internal, hidden
16: unknown:1E00 {1E00} hidden
17: unknown:1868 {1868} internal, hidden
Has 11 reprogrammable keys:
0: MY HOME => HomePage is FN, FN sensitive, reprogrammable
1: Mail => Email is FN, FN sensitive, reprogrammable
2: SEARCH => Search is FN, FN sensitive, reprogrammable
3: Calculator => Calculator is FN, FN sensitive, reprogrammable
4: MEDIA PLAYER => Music is FN, FN sensitive, reprogrammable
5: Previous => Previous is FN, FN sensitive
6: Play/Pause => Play/Pause is FN, FN sensitive
7: Next => Next is FN, FN sensitive
8: Mute => Mute is FN, FN sensitive
9: Volume Down => Volume Down is FN, FN sensitive
10: Volume Up => Volume Up is FN, FN sensitive
Battery: 30%, discharging.
2: Wireless Mouse
Codename :
Kind : mouse
Wireless PID : 4022
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: 00000000
Firmware: RQM 38.00.B0044
Supports 18 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: REPROG CONTROLS {1B00}
6: WIRELESS DEVICE STATUS {1D4B}
7: VERTICAL SCROLLING {2100}
8: MOUSE POINTER {2200}
9: unknown:1810 {1810} internal, hidden
10: unknown:1830 {1830} internal, hidden
11: unknown:1850 {1850} internal, hidden
12: unknown:1890 {1890} internal, hidden
13: unknown:18B0 {18B0} internal, hidden
14: unknown:1DF3 {1DF3} internal, hidden
15: unknown:1868 {1868} internal, hidden
16: unknown:1869 {1869} internal, hidden
17: unknown:1E00 {1E00} hidden
Has 3 reprogrammable keys:
0: LEFT CLICK => LeftClick mse, reprogrammable
1: RIGHT CLICK => RightClick mse, reprogrammable
2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable
Battery: 30%, discharging.

78
docs/devices/mk220.txt Normal file
View File

@@ -0,0 +1,78 @@
Unifying Receiver
Device path : /dev/hidraw1
USB id : 046d:c52e
Serial : 758596BF
Firmware : 23.01.B0006
Has 2 paired device(s) out of a maximum of 2.
Notifications: wireless, software present (0x000900)
1: Wireless Mouse M150
Codename : M150
Kind : mouse
Wireless PID : 400C
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: 93850883
Firmware: RQM 29.00.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: unknown:1850 {1850} hidden
5: unknown:1860 {1860} hidden
6: BATTERY STATUS {1000}
7: WIRELESS DEVICE STATUS {1D4B}
8: unknown:1DF3 {1DF3} hidden
9: REPROG CONTROLS {1B00}
10: unknown:1DF0 {1DF0} hidden
11: unknown:1E00 {1E00} hidden
12: unknown:1E80 {1E80} hidden
13: unknown:1F03 {1F03} hidden
14: VERTICAL SCROLLING {2100}
15: MOUSE POINTER {2200}
Has 3 reprogrammable keys:
0: LEFT CLICK => LeftClick mse, reprogrammable
1: RIGHT CLICK => RightClick mse, reprogrammable
2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable
Battery: 90%, discharging.
2: Wireless Keyboard K220
Codename : K220
Kind : keyboard
Wireless PID : 4005
Protocol : HID++ 2.0
Polling rate : 20 ms (50Hz)
Serial number: 5BB1D72E
Firmware: RQK 37.00.B0011
Supports 14 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: FEATURE INFO {0002}
3: DEVICE FW VERSION {0003}
4: DEVICE NAME {0005}
5: BATTERY STATUS {1000}
6: unknown:1820 {1820} hidden
7: REPROG CONTROLS {1B00}
8: REPROG CONTROLS V2 {1B01}
9: WIRELESS DEVICE STATUS {1D4B}
10: unknown:1DF0 {1DF0} hidden
11: unknown:1DF3 {1DF3} hidden
12: ENCRYPTION {4100}
13: KEYBOARD LAYOUT {4520}
Has 12 reprogrammable keys:
0: FN F1 => Do Nothing One is FN, reprogrammable
1: FN F2 => Do Nothing One is FN, reprogrammable
2: FN F3 => Do Nothing One is FN, reprogrammable
3: FN F4 => Do Nothing One is FN, reprogrammable
4: FN F5 => Do Nothing One is FN, reprogrammable
5: FN F6 => Do Nothing One is FN, reprogrammable
6: FN F7 => Do Nothing One is FN, reprogrammable
7: FN F8 => Do Nothing One is FN, reprogrammable
8: FN F9 => Do Nothing One is FN, reprogrammable
9: Mute => Mute is FN
10: Volume Down => Volume Down is FN
11: Volume Up => Volume Up is FN
Battery: 90%, discharging.

129
docs/devices/mk240-nano.md Normal file
View File

@@ -0,0 +1,129 @@
# Logitech MK240 NANO Device Information
## `solaar show all` Dump
```
Unifying Receiver (NOTE: NOT claimed to be supporting Unifying from the package box, the only advanced feature that may be related is 128-bit AES encryption) (M/N: C-U0010)
Device path : /dev/hidraw0
USB id : 046d:c534
Serial : 0
Firmware : 29.01.B0016
Has 2 paired device(s) out of a maximum of 6.
Notifications: wireless, software present (0x000900)
1: Wireless Keyboard MK270 (NOTE: The Product is actually "MK240 NANO Wireless Keyboard and Mouse Combo" with the "K240"(M/N: Y-R0036) keyboard model)
Codename : MK270
Kind : keyboard
Wireless PID : 4023
Protocol : HID++ 2.0
Polling rate : 20 ms (50Hz)
Serial number: 4BBBBA4A
Firmware: RQK 49.00.B0029
Supports 18 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: REPROG CONTROLS {1B00}
6: WIRELESS DEVICE STATUS {1D4B}
7: FN INVERSION {40A0}
8: ENCRYPTION {4100}
9: KEYBOARD LAYOUT {4520}
10: unknown:1810 {1810} internal, hidden
11: unknown:1830 {1830} internal, hidden
12: unknown:1890 {1890} internal, hidden
13: unknown:18A0 {18A0} internal, hidden
14: unknown:18B0 {18B0} internal, hidden
15: unknown:1DF3 {1DF3} internal, hidden
16: unknown:1E00 {1E00} hidden
17: unknown:1868 {1868} internal, hidden
Has 11 reprogrammable keys:
0: MY HOME => HomePage is FN, FN sensitive, reprogrammable
1: Mail => Email is FN, FN sensitive, reprogrammable
2: SEARCH => Search is FN, FN sensitive, reprogrammable
3: Calculator => Calculator is FN, FN sensitive, reprogrammable
4: MEDIA PLAYER => Music is FN, FN sensitive, reprogrammable
5: Previous => Previous is FN, FN sensitive
6: Play/Pause => Play/Pause is FN, FN sensitive
7: Next => Next is FN, FN sensitive
8: Mute => Mute is FN, FN sensitive
9: Volume Down => Volume Down is FN, FN sensitive
10: Volume Up => Volume Up is FN, FN sensitive
Battery: 30%, discharging. (NOTE: Capacity readings appears to be faked, or in extremely low sensitivity)
2: Wireless Mouse M150 (NOTE: The Product is actually "MK240 NANO Wireless Keyboard and Mouse Combo" with the "M212"(M/N: M-R0041) mouse model)
Codename : M150
Kind : mouse
Wireless PID : 4022
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: 00000000
Firmware: RQM 38.00.B0044
Supports 18 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: REPROG CONTROLS {1B00}
6: WIRELESS DEVICE STATUS {1D4B}
7: VERTICAL SCROLLING {2100}
8: MOUSE POINTER {2200}
9: unknown:1810 {1810} internal, hidden
10: unknown:1830 {1830} internal, hidden
11: unknown:1850 {1850} internal, hidden
12: unknown:1890 {1890} internal, hidden
13: unknown:18B0 {18B0} internal, hidden
14: unknown:1DF3 {1DF3} internal, hidden
15: unknown:1868 {1868} internal, hidden
16: unknown:1869 {1869} internal, hidden
17: unknown:1E00 {1E00} hidden
Has 3 reprogrammable keys:
0: LEFT CLICK => LeftClick mse, reprogrammable
1: RIGHT CLICK => RightClick mse, reprogrammable
2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable
Battery: 30%, discharging. (NOTE: Capacity readings appears to be faked, or in extremely low sensitivity, in the Logitech SetPoint utility battery level is displayed as "HIGH")
```
## Connect Utility Report
```
Re-Connect Software Version : 2.00.3
Dj Api Version : 2, 50, 25
接收器(Receiver)
Name : 無線接收器(Wireless Receiver)
ModelId : 0x46dc534
Serial Number :
Handle : 0xff000001
Wireless Status : 0x3
Firmware version : 029.001.00016
Bootloader version :
Dfu Status : 0x1
Is Dfu Cancellable : Yes
Max Device Capacity : 6
滑鼠(Mouse)
Name :
ModelId : 0x0
Serial Number : 4022-00-00-00-00
Handle : 0x2000003
Wireless Status : 0x0
Firmware version : 038.000.00044
Bootloader version :
Dfu Status : 0x1
Is Dfu Cancellable : No
Battery Status : 0x2
Parent Handle : 0xff000001
鍵盤(Keyboard)
Name :
ModelId : 0x0
Serial Number : 4023-4B-BB-BA-4A
Handle : 0x1000002
Wireless Status : 0x0
Firmware version : 049.000.00029
Bootloader version :
Dfu Status : 0x1
Is Dfu Cancellable : No
Battery Status : 0x2
Parent Handle : 0xff000001
```

86
docs/devices/mk270.txt Normal file
View File

@@ -0,0 +1,86 @@
Unifying Receiver
Device path : /dev/hidraw9
USB id : 046d:c534
Serial : 00000000
Firmware : 29.00.B0015
Has 2 paired device(s) out of a maximum of 6.
Notifications: (none)
1: Wireless Keyboard
Codename : MK270
Kind : keyboard
Wireless PID : 4023
Protocol : HID++ 2.0
Polling rate : 20 ms (50Hz)
Serial number: 00000000
Firmware: RQK 49.00.B0029
Supports 18 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: REPROG CONTROLS {1B00}
6: WIRELESS DEVICE STATUS {1D4B}
7: FN INVERSION {40A0}
8: ENCRYPTION {4100}
9: KEYBOARD LAYOUT {4520}
10: unknown:1810 {1810} internal, hidden
11: unknown:1830 {1830} internal, hidden
12: unknown:1890 {1890} internal, hidden
13: unknown:18A0 {18A0} internal, hidden
14: unknown:18B0 {18B0} internal, hidden
15: unknown:1DF3 {1DF3} internal, hidden
16: unknown:1E00 {1E00} hidden
17: unknown:1868 {1868} internal, hidden
Has 11 reprogrammable keys:
0: MY HOME => HomePage FN sensitive, is FN, reprogrammable
1: Mail => Email FN sensitive, is FN, reprogrammable
2: SEARCH => Search FN sensitive, is FN, reprogrammable
3: Calculator => Calculator FN sensitive, is FN, reprogrammable
4: MEDIA PLAYER => Music FN sensitive, is FN, reprogrammable
5: Previous => Previous FN sensitive, is FN
6: Play/Pause => Play/Pause FN sensitive, is FN
7: Next => Next FN sensitive, is FN
8: Mute => Mute FN sensitive, is FN
9: Volume Down => Volume Down FN sensitive, is FN
10: Volume Up => Volume Up FN sensitive, is FN
Battery: 30%, discharging.
2: Wireless Mouse
Codename : M185
Kind : mouse
Wireless PID : 4038
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: 00000000
Firmware: RQM 54.00.B0004
Supports 22 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: unknown:1830 {1830} internal, hidden
6: unknown:1850 {1850} internal, hidden
7: unknown:1860 {1860} internal, hidden
8: unknown:1890 {1890} internal, hidden
9: unknown:18A0 {18A0} internal, hidden
10: unknown:18C0 {18C0} internal, hidden
11: WIRELESS DEVICE STATUS {1D4B}
12: unknown:1DF3 {1DF3} internal, hidden
13: REPROG CONTROLS {1B00}
14: unknown:1DF0 {1DF0} hidden
15: unknown:1E00 {1E00} hidden
16: unknown:1E80 {1E80} internal, hidden
17: unknown:1E90 {1E90} internal, hidden
18: unknown:1F03 {1F03} internal, hidden
19: VERTICAL SCROLLING {2100}
20: MOUSE POINTER {2200}
21: unknown:18B0 {18B0} internal, hidden
Has 3 reprogrammable keys:
0: LEFT CLICK => LeftClick mse, reprogrammable
1: RIGHT CLICK => RightClick mse, reprogrammable
2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable
Battery: 70%, discharging.

61
docs/devices/mk520.txt Normal file
View File

@@ -0,0 +1,61 @@
Unifying Receiver
Device path : /dev/hidraw3
USB id : 046d:c52b
Serial : AF9C98A0
Firmware : 12.03.B0025
Bootloader : 02.15
Other : AA.AA
Has 2 paired device(s) out of a maximum of 6.
Notifications: wireless, software present (0x000900)
Device activity counters: 1=22, 2=167
1: Wireless Mouse M310/M310t
Codename : M310/M310t
Kind : mouse
Wireless PID : 4031
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: 03E8C0B4
Firmware: RQM 40.01.B0017
The power switch is located on the base.
Supports 21 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: unknown:1830 {1830} internal, hidden
6: unknown:1850 {1850} internal, hidden
7: unknown:1860 {1860} internal, hidden
8: unknown:1890 {1890} internal, hidden
9: unknown:18A0 {18A0} internal, hidden
10: unknown:18C0 {18C0} internal, hidden
11: WIRELESS DEVICE STATUS {1D4B}
12: unknown:1DF3 {1DF3} internal, hidden
13: REPROG CONTROLS {1B00}
14: unknown:1DF0 {1DF0} hidden
15: unknown:1E00 {1E00} hidden
16: unknown:1E80 {1E80} internal, hidden
17: unknown:1E90 {1E90} internal, hidden
18: unknown:1F03 {1F03} internal, hidden
19: VERTICAL SCROLLING {2100}
20: MOUSE POINTER {2200}
Has 3 reprogrammable keys:
0: LEFT CLICK => LeftClick mse, reprogrammable
1: RIGHT CLICK => RightClick mse, reprogrammable
2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable
Battery: 70%, discharging.
2: Wireless Keyboard K520
Codename : K520
Kind : keyboard
Wireless PID : 2011
Protocol : HID++ 1.0
Polling rate : 20 ms (50Hz)
Serial number: ACDE97EF
Firmware: 26.00.B0012
Other: 00.07
The power switch is located on the top case.
Notifications: (none).
Battery: full, discharging.

26
docs/devices/mk700.txt Normal file
View File

@@ -0,0 +1,26 @@
# Enabled Notifications
# 10 - battery status
# 02 + 01 - remap FN keys (multimedia + power buttons)
>> ( 1.412) [10 02 8100 130000] '\x10\x02\x81\x00\x13\x00\x00'
<< ( 0.011) [10 02 8101 000000] '\x10\x02\x81\x01\x00\x00\x00'
>> ( 0.276) [10 02 8101 000000] '\x10\x02\x81\x01\x00\x00\x00'
# Battery status
<< ( 6.033) [10 02 8107 000000] '\x10\x02\x81\x07\x00\x00\x00'
>> ( 6.344) [10 02 8107 070000] '\x10\x02\x81\x07\x07\x00\x00'
# FN status
<< ( 8.055) [10 02 8109 000000] '\x10\x02\x81\t\x00\x00\x00'
>> ( 8.144) [10 02 8109 000000] '\x10\x02\x81\t\x00\x00\x00'
# ?
<< ( 208.316) [10 02 81D0 000000] '\x10\x02\x81\xd0\x00\x00\x00'
>> ( 208.353) [10 02 81D0 000000] '\x10\x02\x81\xd0\x00\x00\x00'
# version info
<< ( 237.436) [10 02 81F1 000000] '\x10\x02\x81\xf1\x00\x00\x00'
>> ( 237.744) [10 02 8F81 F10300] '\x10\x02\x8f\x81\xf1\x03\x00'
# ?
<< ( 239.459) [10 02 81F3 000000] '\x10\x02\x81\xf3\x00\x00\x00'
>> ( 239.766) [10 02 81F3 000000] '\x10\x02\x81\xf3\x00\x00\x00'

View File

@@ -0,0 +1,84 @@
Unifying Receiver
Device path : /dev/hidraw7
USB id : 046d:c52b
Serial : BB7D9447
Firmware : 24.01.B0023
Bootloader : 01.08
Other : AA.AD
Has 2 paired device(s) out of a maximum of 6.
Notifications: wireless, software present (0x000900)
Device activity counters: 2=156
1: Wireless Mouse MX Master 2S
Codename : MX Master 2S
Kind : mouse
Wireless PID : 4069
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
Serial number: EAB71F76
Bootloader: BOT 56.01.B0006
Firmware: MPM 12.01.B0006
Firmware: MPM 12.01.B0006
Other:
The power switch is located on the base.
Supports 32 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: WIRELESS DEVICE STATUS {1D4B}
5: RESET {0020}
6: unknown:0021 {0021}
7: BATTERY STATUS {1000}
8: unknown:1806 {1806} internal, hidden
9: CHANGE HOST {1814}
10: REPROG CONTROLS V4 {1B04}
11: ADJUSTABLE DPI {2201}
12: VERTICAL SCROLLING {2100}
Roller type: 3G
Ratchet per turn: 24
Scroll lines: 0
13: SMART SHIFT {2110}
14: HIRES WHEEL {2121}
Multiplier: 8
Has invert
Normal wheel motion
Has ratchet switch
Normal wheel mode
High resolution mode
HID notification
15: GESTURE 2 {6501}
16: unknown:00C2 {00C2}
17: unknown:1813 {1813} 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:18C0 {18C0} internal, hidden
23: unknown:1DF3 {1DF3} internal, hidden
24: unknown:1E00 {1E00} hidden
25: unknown:1EB0 {1EB0} internal, hidden
26: unknown:1803 {1803} internal, hidden
27: unknown:1861 {1861} internal, hidden
28: unknown:9001 {9001} internal, hidden
29: unknown:9200 {9200} internal, hidden
30: unknown:9202 {9202} internal, hidden
31: unknown:1805 {1805} internal, hidden
Has 8 reprogrammable keys:
0: LEFT CLICK , default: LeftClick => LEFT CLICK
mse, pos:0, group:1, gmask:1
1: RIGHT CLICK , default: RightClick => RIGHT CLICK
mse, pos:0, group:1, gmask:1
2: MIDDLE BUTTON , default: MiddleMouseButton => MIDDLE BUTTON
mse, reprogrammable, divertable, pos:0, group:3, gmask:7
3: BACK AS BUTTON 4 , default: BackEx => BACK AS BUTTON 4
mse, reprogrammable, divertable, pos:0, group:2, gmask:3
4: FORWARD AS BUTTON 5 , default: BrowserForwardEx => FORWARD AS BUTTON 5
mse, reprogrammable, divertable, pos:0, group:2, gmask:3
5: unknown:00C3 , default: unknown:00A9 => unknown:00C3
mse, reprogrammable, divertable, pos:0, group:3, gmask:7
6: unknown:00C4 , default: unknown:009D => unknown:00C4
mse, reprogrammable, divertable, pos:0, group:3, gmask:7
7: unknown:00D7 , default: unknown:00B4 => unknown:00D7
divertable, virtual, pos:0, group:4, gmask:0
Battery: 50%, discharging.

View File

@@ -0,0 +1,83 @@
Unifying Receiver
Device path : /dev/hidraw0
USB id : 046d:c52b
Serial : 32A29DF4
Firmware : 12.09.B0030
Bootloader : 04.16
Other : AA.AA
Has 1 paired device(s) out of a maximum of 6.
Notifications: wireless (0x000100)
Device activity counters: 1=18
1: Wireless Mouse MX Master 3
Codename : MX Master 3
Kind : mouse
Wireless PID : 4082
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
Serial number: B0C9EC6E
Bootloader: BOT 95.00.B0013
Firmware: MPM 19.00.B0013
Other:
The power switch is located on the base.
Supports 34 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: WIRELESS DEVICE STATUS {1D4B}
5: RESET {0020}
6: unknown:0021 {0021}
7: BATTERY STATUS {1000}
8: REPROG CONTROLS V4 {1B04}
9: CHANGE HOST {1814}
10: unknown:2250 {2250}
11: ADJUSTABLE DPI {2201}
12: SMART SHIFT {2110}
13: HIRES WHEEL {2121}
Multiplier: 15
Has invert
Normal wheel motion
Has ratchet switch
Normal wheel mode
Low resolution mode
HID notification
14: unknown:2150 {2150}
15: unknown:2251 {2251}
16: unknown:00C2 {00C2}
17: unknown:1802 {1802} internal, hidden
18: unknown:1803 {1803} internal, hidden
19: unknown:1806 {1806} internal, hidden
20: unknown:1813 {1813} internal, hidden
21: unknown:1805 {1805} internal, hidden
22: unknown:1830 {1830} internal, hidden
23: unknown:1890 {1890} internal, hidden
24: unknown:1891 {1891} internal, hidden
25: unknown:18A1 {18A1} 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:9001 {9001} internal, hidden
31: unknown:9203 {9203} internal, hidden
32: unknown:9205 {9205} internal, hidden
33: unknown:9300 {9300} internal, hidden
Has 8 reprogrammable keys:
0: LEFT CLICK , default: LeftClick => LEFT CLICK
mse, pos:0, group:1, gmask:1
1: RIGHT CLICK , default: RightClick => RIGHT CLICK
mse, pos:0, group:1, gmask:1
2: MIDDLE BUTTON , default: MiddleMouseButton => MIDDLE BUTTON
divertable, mse, reprogrammable, pos:0, group:3, gmask:7
3: BACK AS BUTTON 4 , default: BackEx => BACK AS BUTTON 4
divertable, mse, reprogrammable, pos:0, group:2, gmask:3
4: FORWARD AS BUTTON 5 , default: BrowserForwardEx => FORWARD AS BUTTON 5
divertable, mse, reprogrammable, pos:0, group:2, gmask:3
5: unknown:00C3 , default: unknown:00A9 => unknown:00C3
divertable, mse, reprogrammable, pos:0, group:3, gmask:7
6: unknown:00C4 , default: unknown:009D => unknown:00C4
divertable, mse, reprogrammable, pos:0, group:3, gmask:7
7: unknown:00D7 , default: unknown:00B4 => unknown:00D7
divertable, virtual, pos:0, group:4, gmask:0
Battery: 100%, discharging.

View File

@@ -0,0 +1,54 @@
Unifying Receiver
Device path : /dev/hidraw3
USB id : 046d:c52b
Serial : 0E039B8F
Firmware : 24.01.B0023
Bootloader : 01.08
Other : AA.AC
Has 1 paired device(s) out of a maximum of 6.
Notifications: wireless, software present (0x000900)
Device activity counters: 1=134
1: Wireless Mouse MX Master
Codename : MX Master
Kind : mouse
Wireless PID : 4041
Protocol : HID++ 4.5
Polling rate : 8 ms (125Hz)
Serial number: A975E230
Bootloader: BOT 18.00.B0012
Firmware: MPM 11.00.B0012
Firmware: MPM 11.00.B0012
Other:
The power switch is located on the base.
Supports 29 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: WIRELESS DEVICE STATUS {1D4B}
5: RESET {0020}
6: BATTERY STATUS {1000}
7: CHANGE HOST {1814}
8: REPROG CONTROLS V4 {1B04}
9: ADJUSTABLE DPI {2201}
10: VERTICAL SCROLLING {2100}
11: SMART SHIFT {2110}
12: HIRES WHEEL {2121}
13: GESTURE 2 {6501}
14: DFUCONTROL 2 {00C1}
15: unknown:1813 {1813} internal, hidden
16: unknown:1830 {1830} internal, hidden
17: unknown:1890 {1890} internal, hidden
18: unknown:18A1 {18A1} internal, hidden
19: unknown:18C0 {18C0} internal, hidden
20: unknown:1DF3 {1DF3} internal, hidden
21: unknown:1E00 {1E00} hidden
22: unknown:1EB0 {1EB0} internal, hidden
23: unknown:1803 {1803} internal, hidden
24: unknown:1861 {1861} internal, hidden
25: unknown:9000 {9000} internal, hidden
26: unknown:9200 {9200} internal, hidden
27: unknown:9240 {9240} internal, hidden
28: unknown:1805 {1805} internal, hidden
Battery: 50%, discharging.

View File

@@ -1,12 +1,40 @@
# Notifications (r1_bit0 = battery status?)
<< ( 0.113) [10 01 8100 000000] '\x10\x01\x81\x00\x00\x00\x00'
>> ( 0.157) [10 01 8100 100000] '\x10\x01\x81\x00\x10\x00\x00'
short register 0x63: values 0x81 .. 0x8F
set DPI as 100 .. 1500
# ?
<< ( 1.050) [10 01 8101 000000] '\x10\x01\x81\x01\x00\x00\x00'
>> ( 1.097) [10 01 8101 020000] '\x10\x01\x81\x01\x02\x00\x00'
# battery (07 means full)
<< ( 7.335) [10 01 8107 000000] '\x10\x01\x81\x07\x00\x00\x00'
>> ( 7.382) [10 01 8107 070000] '\x10\x01\x81\x07\x07\x00\x00'
short register 0x51: set leds
value: ab cd 00
where a/b/c/d values are 1=off, 2=on, 3=flash
a = lower led
b = red led
c = upper led
d = middle led
# Set LEDS - ab cd 00, where a/b/c/d values are 1=off, 2=on, 3=flash
# a = lower led
# b = red led
# c = upper led
# d = middle led
# below: all leds are off
<< ( 86.592) [10 01 8151 000000] '\x10\x01\x81Q\x00\x00\x00'
>> ( 86.639) [10 01 8151 111100] '\x10\x01\x81Q\x11\x11\x00'
# DPI (values in range 0x81..0x8F; logical value: 100..1500)
<< ( 108.430) [10 01 8163 000000] '\x10\x01\x81c\x00\x00\x00'
>> ( 108.477) [10 01 8163 890000] '\x10\x01\x81c\x89\x00\x00'
# ?
<< ( 240.505) [10 01 81D0 000000] '\x10\x01\x81\xd0\x00\x00\x00'
>> ( 240.550) [10 01 81D0 000000] '\x10\x01\x81\xd0\x00\x00\x00'
# ?
<< ( 245.690) [10 01 81D4 000000] '\x10\x01\x81\xd4\x00\x00\x00'
>> ( 245.737) [10 01 81D4 000012] '\x10\x01\x81\xd4\x00\x00\x12'
# Firmware/bootloader version
<< ( 281.016) [10 01 81F1 000000] '\x10\x01\x81\xf1\x00\x00\x00'
>> ( 282.177) [10 01 8F81 F10300] '\x10\x01\x8f\x81\xf1\x03\x00'
# ?
<< ( 284.106) [10 01 81F3 000000] '\x10\x01\x81\xf3\x00\x00\x00'
>> ( 284.153) [10 01 81F3 000000] '\x10\x01\x81\xf3\x00\x00\x00'

109
docs/devices/t400.txt Normal file
View File

@@ -0,0 +1,109 @@
Receiver
LZ2388S-DJ
M/N:C-U0007
(ltunify)
Serial number: E6B794F8
Firmware version: 012.001.00019
Bootloader version: BL.002.014
Mouse
(ltunify)
HID++ version: 2.0
Device index 1
Mouse
Name: T400
Wireless Product ID: 4026
Serial number: 131A3093
Device was unavailable, version information not available.
Total number of HID++ 2.0 features: 27
0: [0000] IRoot
1: [0001] IFeatureSet
2: [0002] unknown
3: [0003] IFirmwareInfo
4: [0005] GetDeviceNameType
5: [00C0] DFUControl
6: [1000] batteryLevelStatus
7: [1802] HI unknown
8: [1810] HI unknown
9: [1830] HI unknown
10: [1850] HI unknown
11: [1860] HI unknown
12: [1890] HI unknown
13: [18A0] HI unknown
14: [18E3] HI unknown
15: [1B00] SpecialKeysMSEButtons
16: [1D4B] WirelessDeviceStatus
17: [1DF3] HI unknown
18: [1E00] H unknown
19: [1E80] HI unknown
20: [1F03] HI unknown
21: [1F04] HI unknown
22: [2100] VerticalScrolling
23: [2101] H unknown
24: [2120] HiResScrolling
25: [2200] MousePointer
26: [6110] H TouchmouseRawPoints
27: [1B03] ReprogControlsV3
(O = obsolete feature; H = SW hidden feature;
I = reserved for internal use)
(solaar)
Unifying Receiver
Device path : /dev/hidraw2
USB id : 046d:c52b
Serial : E6B794F8
Firmware : 12.01.B0019
Bootloader : 02.14
Has 1 paired device(s) out of a maximum of 6.
Notifications: (none)
Device activity counters: 1=134
1: Zone Touch Mouse T400
Codename : T400
Kind : mouse
Wireless PID : 4026
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: 131A3093
Firmware: RQM 39.00.B0029
Bootloader: BL 03.00
Hardware: 72
Other:
The power switch is located on the base.
Supports 28 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: FEATURE INFO {0002}
3: DEVICE FW VERSION {0003}
4: DEVICE NAME {0005}
5: DFUCONTROL {00C0}
6: BATTERY STATUS {1000}
7: unknown:1802 {1802} internal, hidden
8: unknown:1810 {1810} internal, hidden
9: unknown:1830 {1830} internal, hidden
10: unknown:1850 {1850} internal, hidden
11: unknown:1860 {1860} internal, hidden
12: unknown:1890 {1890} internal, hidden
13: unknown:18A0 {18A0} internal, hidden
14: unknown:18E3 {18E3} internal, hidden
15: REPROG CONTROLS {1B00}
16: WIRELESS DEVICE STATUS {1D4B}
17: unknown:1DF3 {1DF3} internal, hidden
18: unknown:1E00 {1E00} hidden
19: unknown:1E80 {1E80} internal, hidden
20: unknown:1F03 {1F03} internal, hidden
21: unknown:1F04 {1F04} internal, hidden
22: VERTICAL SCROLLING {2100}
23: unknown:2101 {2101} hidden
24: HI RES SCROLLING {2120}
25: MOUSE POINTER {2200}
26: TOUCHMOUSE RAW POINTS {6110} hidden
27: REPROG CONTROLS V3 {1B03}
Has 7 reprogrammable keys:
0: LEFT CLICK => LeftClick mse, reprogrammable
1: RIGHT CLICK => RightClick mse, reprogrammable
2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable
3: METRO START SCREEN => MetroStartScreen mse, reprogrammable
4: ZOOMIN => Do Nothing mse, reprogrammable
5: ZOOMOUT => Do Nothing mse, reprogrammable
6: BACK HSCROLL => TouchBackForwardHorzScroll
Battery: 100%, discharging.

94
docs/devices/t650.txt Normal file
View File

@@ -0,0 +1,94 @@
Receiver
LZ2458D-DJ
M/N:C-U0008
(ltunify)
Serial number: 28E69A3E
Firmware version: 024.000.00018
Bootloader version: BL.000.006
Touchpad
(ltunify)
HID++ version: 2.0
Device index 1
Touchpad
Name: T650
Wireless Product ID: 4101
Serial number: 22205A4D
Device was unavailable, version information not available.
Total number of HID++ 2.0 features: 22
0: [0000] IRoot
1: [0001] IFeatureSet
2: [0002] unknown
3: [0003] IFirmwareInfo
4: [0005] GetDeviceNameType
5: [1000] batteryLevelStatus
6: [1D4B] WirelessDeviceStatus
7: [1DF3] HI unknown
8: [1B00] SpecialKeysMSEButtons
9: [1F03] HI unknown
10: [2100] VerticalScrolling
11: [2120] HiResScrolling
12: [2200] MousePointer
13: [00C0] DFUControl
14: [1E80] HI unknown
15: [6100] TouchpadRawXy
16: [1860] HI unknown
17: [1E00] H unknown
18: [1B01] ReprogControlsV2
19: [1890] HI unknown
20: [18E5] HI unknown
21: [18A0] HI unknown
22: [1830] HI unknown
(O = obsolete feature; H = SW hidden feature;
I = reserved for internal use)
(solaar)
Unifying Receiver
Device path : /dev/hidraw2
USB id : 046d:c52b
Serial : 28E69A3E
Firmware : 24.00.B0018
Bootloader : 00.06
Has 1 paired device(s) out of a maximum of 6.
Notifications: (none)
Device activity counters: 1=221
1: Wireless Rechargeable Touchpad T650
Codename : T650
Kind : touchpad
Wireless PID : 4101
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: 22205A4D
Firmware: RQM 41.01.B0037
Bootloader: BL 03.00
Hardware: 72
Other:
The power switch is located on the base.
Supports 23 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: FEATURE INFO {0002}
3: DEVICE FW VERSION {0003}
4: DEVICE NAME {0005}
5: BATTERY STATUS {1000}
6: WIRELESS DEVICE STATUS {1D4B}
7: unknown:1DF3 {1DF3} internal, hidden
8: REPROG CONTROLS {1B00}
9: unknown:1F03 {1F03} internal, hidden
10: VERTICAL SCROLLING {2100}
11: HI RES SCROLLING {2120}
12: MOUSE POINTER {2200}
13: DFUCONTROL {00C0}
14: unknown:1E80 {1E80} internal, hidden
15: TOUCHPAD RAW XY {6100}
16: unknown:1860 {1860} internal, hidden
17: unknown:1E00 {1E00} hidden
18: REPROG CONTROLS V2 {1B01}
19: unknown:1890 {1890} internal, hidden
20: unknown:18E5 {18E5} internal, hidden
21: unknown:18A0 {18A0} internal, hidden
22: unknown:1830 {1830} internal, hidden
Has 2 reprogrammable keys:
0: LEFT CLICK => LeftClick mse, reprogrammable
1: RIGHT CLICK => RightClick mse, reprogrammable
Battery: 50%, discharging.

112
docs/features.md Normal file
View File

@@ -0,0 +1,112 @@
---
title: List of HID++ 2.0 features
layout: page
---
# Feature status
See functions in hidpp20.py and settings_templates.py
Feature | ID | Status | Notes
---------------------------------------|----------|:------------------:|------
`ROOT` | `0x0000` | :heavy_check_mark: | System
`FEATURE_SET` | `0x0001` | :heavy_check_mark: | System
`FEATURE_INFO` | `0x0002` | :heavy_check_mark: | System
`DEVICE_FW_VERSION` | `0x0003` | :heavy_check_mark: | `get_firmware()`
`DEVICE_UNIT_ID` | `0x0004` | :x: |
`DEVICE_NAME` | `0x0005` | :heavy_check_mark: | `get_kind()`, `get_name()`
`DEVICE_GROUPS` | `0x0006` | :x: |
`DEVICE_FRIENDLY_NAME` | `0x0007` | :x: |
`KEEP_ALIVE` | `0x0008` | :x: |
`RESET` | `0x0020` | :x: | aka "Config Change"
`CRYPTO_ID` | `0x0021` | :x: |
`TARGET_SOFTWARE` | `0x0030` | :x: |
`WIRELESS_SIGNAL_STRENGTH` | `0x0080` | :x: |
`DFUCONTROL_LEGACY` | `0x00C0` | :x: |
`DFUCONTROL_UNSIGNED` | `0x00C1` | :x: |
`DFUCONTROL_SIGNED` | `0x00C2` | :x: |
`DFU` | `0x00D0` | :x: |
`BATTERY_STATUS` | `0x1000` | :heavy_check_mark: | `get_battery()`
`BATTERY_VOLTAGE` | `0x1001` | :x: |
`CHARGING_CONTROL` | `0x1010` | :x: |
`LED_CONTROL` | `0x1300` | :x: |
`GENERIC_TEST` | `0x1800` | :x: |
`DEVICE_RESET` | `0x1802` | :x: |
`OOBSTATE` | `0x1805` | :x: |
`CONFIG_DEVICE_PROPS` | `0x1806` | :x: |
`CHANGE_HOST` | `0x1814` | :x: |
`HOSTS_INFO` | `0x1815` | :x: |
`BACKLIGHT` | `0x1981` | :x: |
`BACKLIGHT2` | `0x1982` | :x: |
`BACKLIGHT3` | `0x1983` | :x: |
`PRESENTER_CONTROL` | `0x1A00` | :x: |
`SENSOR_3D` | `0x1A01` | :x: |
`REPROG_CONTROLS` | `0x1B00` | :heavy_plus_sign: | Partially, only listing. `get_keys()`
`REPROG_CONTROLS_V2` | `0x1B01` | :x: |
`REPROG_CONTROLS_V2_2` | `0x1B02` | :x: |
`REPROG_CONTROLS_V3` | `0x1B03` | :x: |
`REPROG_CONTROLS_V4` | `0x1B04` | :heavy_plus_sign: | Partially, only listing. `get_keys()`
`REPORT_HID_USAGE` | `0x1BC0` | :x: |
`PERSISTENT_REMAPPABLE_ACTION` | `0x1C00` | :x: |
`WIRELESS_DEVICE_STATUS` | `0x1D4B` | :x: |
`REMAINING_PAIRING` | `0x1DF0` | :x: |
`FIRMWARE_PROPERTIES` | `0x1F1F` | :x: |
`ADC_MEASUREMENT` | `0x1F20` | :x: |
`LEFT_RIGHT_SWAP` | `0x2001` | :x: |
`SWAP_BUTTON_CANCEL` | `0x2005` | :x: |
`POINTER_AXIS_ORIENTATION` | `0x2006` | :x: |
`VERTICAL_SCROLLING` | `0x2100` | :heavy_check_mark: | `get_vertical_scrolling_info()`
`SMART_SHIFT` | `0x2110` | :heavy_check_mark: | `_feature_smart_shift()`
`HI_RES_SCROLLING` | `0x2120` | :heavy_check_mark: | `get_hi_res_scrolling_info()`, `_feature_hi_res_scroll()`
`HIRES_WHEEL` | `0x2121` | :heavy_check_mark: | `get_hires_wheel()`, `_feature_hires_smooth_invert()`, `_feature_hires_smooth_resolution()`
`LOWRES_WHEEL` | `0x2130` | :heavy_check_mark: | `get_lowres_wheel_status()`, `_feature_lowres_smooth_scroll()`
`THUMB_WHEEL` | `0x2150` | :x: |
`MOUSE_POINTER` | `0x2200` | :heavy_check_mark: | `get_mouse_pointer_info()`
`ADJUSTABLE_DPI` | `0x2201` | :heavy_check_mark: | `_feature_adjustable_dpi()`
`POINTER_SPEED` | `0x2205` | :heavy_check_mark: | `get_pointer_speed_info()`, `_feature_pointer_speed()`
`ANGLE_SNAPPING` | `0x2230` | :x: |
`SURFACE_TUNING` | `0x2240` | :x: |
`HYBRID_TRACKING` | `0x2400` | :x: |
`FN_INVERSION` | `0x40A0` | :heavy_check_mark: | `_feature_fn_swap()`
`NEW_FN_INVERSION` | `0x40A2` | :heavy_check_mark: | `_feature_new_fn_swap()`
`K375S_FN_INVERSION` | `0x40A3` | :heavy_check_mark: | `_feature_k375s_fn_swap()`
`ENCRYPTION` | `0x4100` | :x: |
`LOCK_KEY_STATE` | `0x4220` | :x: |
`SOLAR_DASHBOARD` | `0x4301` | :x: |
`KEYBOARD_LAYOUT` | `0x4520` | :x: |
`KEYBOARD_DISABLE` | `0x4521` | :x: |
`KEYBOARD_DISABLE_BY_USAGE` | `0x4522` | :x: |
`DUALPLATFORM` | `0x4530` | :x: |
`MULTIPLATFORM` | `0x4531` | :x: |
`KEYBOARD_LAYOUT_2` | `0x4540` | :x: |
`CROWN` | `0x4600` | :x: |
`TOUCHPAD_FW_ITEMS` | `0x6010` | :x: |
`TOUCHPAD_SW_ITEMS` | `0x6011` | :x: |
`TOUCHPAD_WIN8_FW_ITEMS` | `0x6012` | :x: |
`TAP_ENABLE` | `0x6020` | :x: |
`TAP_ENABLE_EXTENDED` | `0x6021` | :x: |
`CURSOR_BALLISTIC` | `0x6030` | :x: |
`TOUCHPAD_RESOLUTION` | `0x6040` | :x: |
`TOUCHPAD_RAW_XY` | `0x6100` | :x: |
`TOUCHMOUSE_RAW_POINTS` | `0x6110` | :x: |
`TOUCHMOUSE_6120` | `0x6120` | :x: |
`GESTURE` | `0x6500` | :x: |
`GESTURE_2` | `0x6501` | :x: |
`GKEY` | `0x8010` | :x: |
`MKEYS` | `0x8020` | :x: |
`MR` | `0x8030` | :x: |
`BRIGHTNESS_CONTROL` | `0x8040` | :x: |
`REPORT_RATE` | `0x8060` | :x: |
`COLOR_LED_EFFECTS` | `0x8070` | :x: |
`RGB_EFFECTS` | `0X8071` | :x: |
`PER_KEY_LIGHTING` | `0x8080` | :x: |
`PER_KEY_LIGHTING_V2` | `0x8081` | :x: |
`MODE_STATUS` | `0x8090` | :x: |
`ONBOARD_PROFILES` | `0x8100` | :x: |
`MOUSE_BUTTON_SPY` | `0x8110` | :x: |
`LATENCY_MONITORING` | `0x8111` | :x: |
`GAMING_ATTACHMENTS` | `0x8120` | :x: |
`FORCE_FEEDBACK` | `0x8123` | :x: |
`SIDETONE` | `0x8300` | :x: |
`EQUALIZER` | `0x8310` | :x: |
`HEADSET_OUT` | `0x8320` | :x: |

58
docs/i18n.md Normal file
View File

@@ -0,0 +1,58 @@
# Translating Solaar
First, make sure you have installed the `gettext` package.
Here are the steps to add/update a translation (you should run all scripts from
the source root):
1. Get an up-to-date copy of the source files. Preferably, make a clone on
GitHub and clone it locally on your machine; this way you can later make a
pull request to the main project.
2. Run `./tools/po-update.sh <language>`; it will create/update the file
`./po/<language>.po`.
3. Edit `./po/<language>.po` with your favourite editor (just make sure it saves
the file with the UTF-8 encoding). For each string in english (msgid), edit
the translation (msgstr); if you leave msgstr empty, the string will remain
untranslated.
Alternatively, you can use the excellent `poedit`.
4. Run `./tools/po-compile.sh`. It will bring up-to-date all the compiled
language files, necessary at runtime.
5. Start Solaar (`./bin/solaar`). By default it will pick up the system language
from your environment; to start it in another language, run
`LANGUAGE=<language> ./bin/solaar`.
You can edit the translation iteratively, just repeat from step 3.
If the upstream changes, do a `git pull` and then repeat from step 2.
Before opening a pull request, please run `./tools/po-update.sh` again. It will
format and sort the translation file, and ensure a minimal diff when updating
a translation.
# Supported languages
Currently Solaar has been translated in the following languages:
- Français: [Papoteur][papoteur], [David Geiger][david-geiger],
[Damien Lallement][damsweb]
- Italiano: [Michele Olivo][micheleolivo]
- Polski: [Adrian Piotrowicz][nexces]
- Portuguese-BR: [Drovetto][drovetto], [Josenivaldo Benito Jr.][jrbenito]
- Română: Daniel Pavel
- Russian: [Dimitriy Ryazantcev][DJm00n]
- Svensk: [Daniel Zippert][zipperten], Emelie Snecker
[papoteur]: http://github.com/papoteur
[david-geiger]: http://github.com/david-geiger
[damsweb]: http://github.com/damsweb
[DJm00n]: https://github.com/DJm00n
[nexces]: http://github.com/nexces
[zipperten]: http://github.com/zipperten
[micheleolivo]: http://github.com/micheleolivo
[drovetto]: https://github.com/drovetto
[jrbenito]: https://github.com/jrbenito/

34
docs/icons_names.txt Normal file
View File

@@ -0,0 +1,34 @@
# battery icon names across various icon themes
B = 'battery'
CG = 'charging'
GB = 'gpm-battery'
theme (unknown) 0 0-CG 20 20-CG 40 40-CG 60 60-CG 80 80-CG 100 100-CG 100-full
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
gnome B-missing B-empty - B-caution B-caution-CG B-low B-low-CG - - B-good B-good-CG B-full B-full-CG B-full-charged
Humanity GB-missing GB-000 GB-000-CG GB-020 GB-020-CG GB-040 GB-040-CG GB-060 GB-060-CG GB-080 GB-080-CG GB-100 GB-100-CG GB-charged
(gnome) - B_empty - B-caution - B-low - B_two_thirds - B_third_fourth - B_full B_plugged B_charged
elementary B-missing B-000 B-000-CG B-020 B-020-CG B-040 B-040-CG B-060 B-060-CG B-080 B-080-CG B-100 B-100-CG B-charged
(gnome) - B-empty - B-caution B-caution-CG B-low B-low-CG - - B-good B-good-CG B-full B-full-CG B-full-charged
- B_empty - - - - - B_two_thirds - B_third_fourth - B_full B_plugged B_charged
faenza - GB-000 GB-000-CG GB-020 GB-020-CG GB-040 GB-040-CG GB-060 GB-060-CG GB-080 GB-080-CG GB-100 GB-100-CG GB-charged
(gnome) - B_empty - B_caution - B_low - B_two_thirds - B_third_fourth - B_full B_plugged B_charged
ubuntu-mono GB-missing GB-000 GB-000-CG GB-020 GB-020-CG GB-040 GB-040-CG GB-060 GB-060-CG GB-080 GB-080-CG GB-100 GB-100-CG GB-charged
(Humanity) B-000 B-000-CG B-020 B-020-CG B-040 B-040-CG B-060 B-060-CG B-080 B-080-CG B-100 B-100-CG B-charged
B_empty - B-caution - B-low - - - - - B_full - B_charged
oxygen B-missing B-low B-CG-low B-caution B-CG-caution B-040 B-CG-040 B-060 B-CG-060 B-080 B-CG-080 B-100 B-CG -
moblin - - - B-low - B-caution - - - B-good - B-full B-charging -
nuvola B-missing B-low - - - - - - - - - - B-charging -
# weather icons (for lux)

136
docs/index.md Normal file
View File

@@ -0,0 +1,136 @@
---
title: Solaar
layout: default
---
**Solaar** is a Linux manager for Logitech's devices that connect via a USB
[Unifying][unifying], Lightspeed, or Nano receiver.
Solaar does not work with Logitech peripherals that
use Bluetooth or peripherals from other companies.
Solaar can be used as a GUI application or via its command-line interface.
Both interfaces are able to list the devices paired to a receiver and
show information about each device, including battery status for devices that support this feature.
Solaar's GUI normally uses an icon in the system tray and starts with its main window hidden.
If Solaar is invoked with the `--window=show` option (the default) Solaar starts with its main window visible.
If Solaar is invoked with the `--window=hide` option Solaar starts with its main window hidden.
If solaar is invoked with the `--window=only` option Solaar does not set up an icon in the
system tray and also starts with its main window showing.
For more information on Solaar's command-line interface use the help option,
as in `solaar --help`.
Solaar is able to pair and unpair devices with
receivers as supported by the receiver. Solaar can also control
some of the changeable features of devices, such as smooth scrolling or
function key behavior.
For more information on how to use Solaar see
[docs/usage.md](https://pwr-solaar.github.io/Solaar/usage).
For more information on the capabilities of Solaar see
[docs/capabilities.md](https://pwr-solaar.github.io/Solaar/capabilities).
Solaar does not process normal input from the devices. Solaar is thus unable
to fix problems that arise from incorrect handling of mouse movements or keycodes
by Linux drivers or other software.
Solaar has progressed past version 1.0. Problems with earlier versions should
not be reported as bugs. Instead upgrade to a recent version or manually install
the current version from [GitHub](https://github.com/pwr-Solaar/Solaar).
Some of the capabilities of Solaar have been developed by observing the behavior of
Logitech receivers and devices and generalizing from these observations.
If your Logitech receiver or device behaves in a strange way this may be caused by
an incorrect behavior generalization.
Please report such experiences by creating an issue in
[the Solaar repository](https://github.com/pwr-Solaar/Solaar/issues).
[unifying]: https://en.wikipedia.org/wiki/Logitech_Unifying_receiver
## Supported Devices
**Solaar** will detect all devices paired with your Unifying, Lightspeed, or Nano
receiver, and at the very least display some basic information about them.
Solaar can pair and unpair a Logitech device showing the Unifying logo (Solaar's version of the [logo][logo])
with any Unifying receiver and can pair and unpair devices with Lightspeed receivers.
Solaar can pair some Logitech
devices with Logitech Nano receivers but not all Logitech devices can be
paired with Nano receivers. Logitech devices without a Unifying logo
generally cannot be paired with Unifying receivers.
For some devices, extra settings (usually not available through the standard
Linux system configuration) are supported. For a list of supported devices
and their features, see [docs/devices.md](https://pwr-solaar.github.io/Solaar/devices).
[logo]: https://pwr-solaar.github.io/Solaar/assets/solaar.svg
## Pre-built packages
Pre-built packages are available for a few Linux distros.
Solaar has progressed beyond version 1.0 but some distros or repositories
version 0.9.2, which is very old. Installing the current version will
provide significant improvements. 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 [community repository][arch]
* Debian 7 (Wheezy) or higher: packages in this [repository](https://pwr-solaar.github.io/Solaar/debian)
* Ubuntu/Kubuntu 16.04+: use the solaar package from [universe repository][universe repository]
* Ubuntu/Kubuntu stable packages: use the [Solaar stable ppa][ppa2], courtesy of [gogo][ppa4]
* Ubuntu/Kubuntu git build packages: use the [Solaar git ppa][ppa1], courtesy of [gogo][ppa4]
* a [Fedora package][fedora], courtesy of Eric Smith
* a [Gentoo package][gentoo], courtesy of Carlos Silva and Tim Harder
* a [Mageia package][mageia], courtesy of David Geiger
* an [OpenSUSE rpm][opensuse], courtesy of Mathias Homann
Solaar uses a standard system tray implementation; solaar-gnome3 is no longer required for gnome or unity integration.
[ppa4]: https://launchpad.net/~trebelnik-stefina
[ppa2]: https://launchpad.net/~solaar-unifying/+archive/ubuntu/stable
[ppa1]: https://launchpad.net/~solaar-unifying/+archive/ubuntu/ppa
[ppa]: http://launchpad.net/~daniel.pavel/+archive/solaar
[arch]: https://www.archlinux.org/packages/community/any/solaar/
[fedora]: https://apps.fedoraproject.org/packages/solaar
[gentoo]: https://packages.gentoo.org/packages/app-misc/solaar
[mageia]: http://mageia.madb.org/package/show/release/cauldron/application/0/name/solaar
[opensuse]: http://software.opensuse.org/package/Solaar
[universe repository]: http://packages.ubuntu.com/search?keywords=solaar&searchon=names&suite=all&section=all
## Manual installation
See [docs/installation.md](https://pwr-solaar.github.io/Solaar/installation) for the step-by-step procedure for manual installation.
## Known Issues
- KDE/Kubuntu: if some icons appear broken in the application, make sure you've
properly configured the Gtk theme and icon theme in KDE's control panel.
- Running the command-line application while the GUI
application is also running *may* occasionally cause either of them to become
confused about the state of the devices.
## License
This software is distributed under the terms of the
[GNU Public License, v2](COPYING).
## Thanks
This project began as a third-hand clone of [Noah K. Tilton](https://github.com/noah)'s
logitech-solar-k750 project on GitHub (no longer available). It was developed
further thanks to the diggings in Logitech's HID++ protocol done by many other
people:
- [Julien Danjou](http://julien.danjou.info/blog/2012/logitech-k750-linux-support),
who also provided some internal
[Logitech documentation](http://julien.danjou.info/blog/2012/logitech-unifying-upower)
- [Lars-Dominik Braun](http://6xq.net/git/lars/lshidpp.git)
- [Alexander Hofbauer](http://derhofbauer.at/blog/blog/2012/08/28/logitech-performance-mx)
- [Clach04](http://bitbucket.org/clach04/logitech-unifying-receiver-tools)
- [Peter Wu](https://lekensteyn.nl/logitech-unifying.html)
- [Nestor Lopez Casado](http://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28)
provided some more Logitech specifications for the HID++ protocol
Also thanks to Douglas Wagner, Julien Gascard and Peter Wu for helping with
application testing and supporting new devices.

106
docs/installation.md Normal file
View File

@@ -0,0 +1,106 @@
---
title: Manual Installation
layout: page
---
# Manual installation
## Downloading
Clone solaar from GitHub via `git clone https://github.com/pwr-Solaar/Solaar.git`
## Requirements for running Solaar
Installing Solaar from a repository should have set up all these requirements
so in this situation you should be able to skip this section.
Solaar needs a reasonably new kernel (5.0+ should work fine), with kernel modules `hid-logitech-dj`
and `hid-logitech-hidpp` loaded. Also, the `udev` package must be installed
and its daemon running. If you have a recent Linux distribution, you are
most likely good to go.
Solaar requires Python 3.2+
and the `python3-pyudev` package.
To run the GUI, solaar also requires Gtk3, and its GObject
introspection bindings.
The Debian/Ubuntu packages that need to be installed are
`python3-gi` and `gir1.2-gtk-3.0`;
in Fedora you need `gtk3` and `python3-gobject`;
if you're using another
distribution the required packages are most likely named something similar.
If the desktop notifications bindings are also installed
(`gir1.2-notify-0.7` for Debian/Ubuntu),
you will also get desktop notifications when devices come online/go offline.
For GNOME Shell/Budgie Desktop/KDE/XFCE support, you also need to have
`gir1.2-ayatanaappindicator3-0.1` installed in Debian/Ubuntu. Although it is
recommended to install and use `gir1.2-ayatanaappindicator3-0.1` if it is
available, you can also use `gir1.2-appindicator3-0.1` if necessary (e.g.,
for Unity in Ubuntu).
### Installing Solaar's udev Rule
Solaar needs to write to the receiver's HID device.
To be able to do this without running as root requires udev rule
that gives seated users write access to the HID devices for Logitech receivers.
You can install this rule by copying, as root,
`rules.d/42-logitech-unify-permissions.rules` from Solaar to
`/etc/udev/rules.d`.
The udev daemon will automatically pick up this file using inotify.
For this rule to set up the correct permissions for your receiver
you will then need to either physically remove the receiver and
re-insert it or reboot your computer.
## Running from the Download Directories
If Solaar's udev rule is installed,
you can just go to the solaar directory and run `bin/solaar` for the GUI
or `bin/solaar <command> <arguments>` for the CLI.
Otherwise you will need to run Solaar as root via
`sudo bin/solaar` for the GUI
or `sudo bin/solaar <command> <arguments>` for the CLI.
## Installing Solaar
Python programs are usually installed using [pip][pip].
The pip instructions for solaar are in `setup.py`, the standard place to put such instructions.
To install solaar for yourself only run `pip install --user .` from the solaar directory.
This tells pip to install into your `.local` directory, but does not install Solaar's udev rule.
(See above for installing the udev rule.)
You can then run solaar as `sudo ~/.local/bin/solaar` (or just `~/.local/bin/solaar`
if the udev rule has been installed).
Installing python programs to system directories using pip is generally frowned on both
because this runs arbitrary code as root and because this can override existing python libraries
that other users or even the system depend on. If you want to install solaar to /usr/local run
`sudo bash -c 'umask 022 ; pip install .'` in the solaar directory.
(The umask is needed so that the created files and directories can be read and executed by everyone.)
This will also install the udev rule and the Solaar autostart desktop file.
Then solaar can be run as /usr/local/bin/solaar.
[pip]: https://en.wikipedia.org/wiki/Pip_(package_manager)
## Running Solaar at Startup
Solaar is run automatically at user login via the desktop file
`/etc/xdg/autostart/solaar.desktop`.
If you install Solaar yourself you may need to create or modify this file.
## Using PyPI
As an alternative to downloading and installing you can install the most recent release
(but not the current github version) of Solaar from PyPI.
Just run `pip install --user solaar` or `sudo pip install solaar`.
The `--user` flag will not install the Solaar udev rule or the Solaar autostart file.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,26 @@
The battery/charging level and status is reported only if the related
reporting flag in register 0x00 is enabled by the host. The
"Battery/Charging Level" byte indicates the battery level if the
"Charging State" indicates 0x00 ("Not Charging"). If "Charging State"
indicates 0x21 to 0x23 ("Charging"), the "Battery/Charging Level" byte
indicates the level of charging.
10 ix 07 r0 r1 r2 00
r0 -> Battery/Charging Level
0x00 = Reserved/Unknown
0x01 = Critical
0x02 = Critical (legacy value, don't use)
0x03 = Low
0x04 = Low (legacy value, don't use)
0x05 = Good
0x06 = Good (legacy value, don't use)
0x07 = Full
0x08..0xFF = Reserved
r1 -> Charging state
0x00 = Not charging
0x01..0x1F = Reserved (not charging)
0x20 = Unknown charging state
0x21 = Charging
0x22 = Charging complete
0x23 = Charging error
0x24..0xFF = Reserved

Binary file not shown.

88
docs/usage.md Normal file
View File

@@ -0,0 +1,88 @@
---
title: Solaar Usage
layout: page
---
# Solaar usage
Under normal usage Solaar creates an icon in your system tray. This icon is
usually a battery icon showing the approximate battery level for your device
with the lowest known battery level. If there is no battery information to
show the icon is one of the Solaar icons.
Solaar also has a main window. To show the main window if it is not visible
click on the icon in the system tray to bring up the Solaar menu and then
click on a receiver or device in the menu.
Here is an example of the Solaar icon (in the system tray) and the Solaar menu:
![Solaar-menu](Solaar-menu.png)
Clicking on "Quit" in the Solaar menu terminates Solaar.
Clicking on "About Solaar" pops up a window with information on Solaar.
## Solaar options
There are several options that affect how Solaar behaves:
* `--help` shows a help message and then quits
* `---window=show` starts Solaar with the main window showing
* `---window=hide` starts Solaar with the main window not showing
* `---window=only` starts Solaar with no system tray icon and the main window showing
* `--battery-icons=symbolic` uses symbolic icons for battery levels
## Solaar main window
The Solaar main window shows your Logitech receivers and devices that Solaar
knows about and can be used to pair new devices, unpair paired devices, and
view and change some settings of the selected receiver or device.
To select a receiver or device click on it in the left side of the window.
Closing the main window does not terminate Solaar (unless Solaar is not using the system tray).
Clicking on "Quit Solaar" terminates Solaar.
Clicking on "About Solaar" pops up a window with information on Solaar.
Clicking on the lightbulb (or similar icon) displays detailed information
about the selected receiver or device (mostly only useful for debugging).
When a receiver is selected in the main window you can pair a new device by
clicking on the "Pair new device" button.
Then turn on the device and it should pair with the receiver if that is possible.
![Solaar-main-window-receiver](Solaar-main-window-receiver.png)
Some receivers can only pair with certain kinds of devices. Some receivers
pair a new device by replacing an existing paired device of the same kind.
Some receivers can only pair a limited number of times.
A receiver with the Unifying logo should be able to pair with any device
with the Unifying logo. If there are no open pairing slots, however, you may
not be able to pair a new device. In this case to pair a new device you
first need to unpair a device.
When a device is selected you can unpair the device if your receiver supports
unpairing. To unpair the device, just click on the "Unpair" button and
confirm in the window that pops up.
When a device is selected you can see the approximate battery level of the
device, if that is reported by the device, and the status of the link
between the device and its receiver.
You can also see some settings of the device and change
some of these. Changing settings is performed by clicking on buttons or
moving sliders.
![Solaar-main-window-keyboard](Solaar-main-window-keyboard.png)
![Solaar-main-window-mouse](Solaar-main-window-mouse.png)
If the selected device is off or otherwise disconnected its settings cannot be changed
but it still can be unpaired if its receiver allows unpairing.
![Solaar-main-window-offline](Solaar-main-window-offline.png)
## Solaar command line interface
Solaar also has a command line interface that can do most of what can be
done using the Solaar main window. For more information on the Solaar
command line interface, run `solaar --help` to see the Solaar commands and
then `solaar <command> --help` to see the arguments to any of the commands.

14
docs/usb-ids.txt Normal file
View File

@@ -0,0 +1,14 @@
Unifying receiver:
046d:c52b interface: 2 driver: logitech-djreceiver
046d:c532 interface: 2 driver: logitech-djreceiver
Nano receiver, Advanced/Unifying ready:
046d:c52f interface: 1 driver: hid-generic
Nano receiver:
046d:c51a interface: 1 driver: hid-generic
046d:c526 interface: 1 driver: hid-generic
046d:c52e interface: 1 driver: hid-generic
046d:c531 interface: 1 driver: hid-generic

429
docs/usb.ids.txt Normal file
View File

@@ -0,0 +1,429 @@
#
# List of USB ID's
#
# Maintained by Stephen J. Gowdy <linux.usb.ids@gmail.com>
# If you have any new entries, please submit them via
# http://www.linux-usb.org/usb-ids.html
# or send entries as patches (diff -u old new) in the
# body of your email (a bot will attempt to deal with it).
# The latest version can be obtained from
# http://www.linux-usb.org/usb.ids
#
# Version: 2019.11.05
# Date: 2019-11-05 20:34:06
#
# Vendors, devices and interfaces. Please keep sorted.
# Syntax:
# vendor vendor_name
# device device_name <-- single tab
# interface interface_name <-- two tabs
046d Logitech, Inc.
0082 Acer Aspire 5672 Webcam
0200 WingMan Extreme Joystick
0203 M2452 Keyboard
0242 Chillstream for Xbox 360
0301 M4848 Mouse
0401 HP PageScan
0402 NEC PageScan
040f Logitech/Storm PageScan
0430 Mic (Cordless)
0801 QuickCam Home
0802 Webcam C200
0804 Webcam C250
0805 Webcam C300
0807 Webcam B500
0808 Webcam C600
0809 Webcam Pro 9000
080a Portable Webcam C905
080f Webcam C120
0810 QuickCam Pro
0819 Webcam C210
081a Webcam C260
081b Webcam C310
081d HD Webcam C510
0820 QuickCam VC
0821 HD Webcam C910
0823 HD Webcam B910
0825 Webcam C270
0826 HD Webcam C525
0828 HD Webcam B990
082b Webcam C170
082c HD Webcam C615
082d HD Pro Webcam C920
0830 QuickClip
0836 B525 HD Webcam
0837 BCC950 ConferenceCam
0840 QuickCam Express
0843 Webcam C930e
0850 QuickCam Web
085c C922 Pro Stream Webcam
0870 QuickCam Express
0890 QuickCam Traveler
0892 OrbiCam
0894 CrystalCam
0895 QuickCam for Dell Notebooks
0896 OrbiCam
0897 QuickCam for Dell Notebooks
0899 QuickCam for Dell Notebooks
089d QuickCam E2500 series
08a0 QuickCam IM
08a1 QuickCam IM with sound
08a2 Labtec Webcam Pro
08a3 QuickCam QuickCam Chat
08a6 QuickCam IM
08a7 QuickCam Image
08a9 Notebook Deluxe
08aa Labtec Notebooks
08ac QuickCam Cool
08ad QuickCam Communicate STX
08ae QuickCam for Notebooks
08af QuickCam Easy/Cool
08b0 QuickCam 3000 Pro [pwc]
08b1 QuickCam Notebook Pro
08b2 QuickCam Pro 4000
08b3 QuickCam Zoom
08b4 QuickCam Zoom
08b5 QuickCam Sphere
08b9 QuickCam IM
08bd Microphone (Pro 4000)
08c0 QuickCam Pro 3000
08c1 QuickCam Fusion
08c2 QuickCam PTZ
08c3 Camera (Notebooks Pro)
08c5 QuickCam Pro 5000
08c6 QuickCam for DELL Notebooks
08c7 QuickCam OEM Cisco VT Camera II
08c9 QuickCam Ultra Vision
08ca Mic (Fusion)
08cb Mic (Notebooks Pro)
08cc Mic (PTZ)
08ce QuickCam Pro 5000
08cf QuickCam UpdateMe
08d0 QuickCam Express
08d7 QuickCam Communicate STX
08d8 QuickCam for Notebook Deluxe
08d9 QuickCam IM/Connect
08da QuickCam Messenger
08dd QuickCam for Notebooks
08e0 QuickCam Express
08e1 Labtec Webcam
08f0 QuickCam Messenger
08f1 QuickCam Express
08f2 Microphone (Messenger)
08f3 QuickCam Express
08f4 Labtec Webcam
08f5 QuickCam Messenger Communicate
08f6 QuickCam Messenger Plus
0900 ClickSmart 310
0901 ClickSmart 510
0903 ClickSmart 820
0905 ClickSmart 820
0910 QuickCam Cordless
0920 QuickCam Express
0921 Labtec Webcam
0922 QuickCam Live
0928 QuickCam Express
0929 Labtec Webcam Pro
092a QuickCam for Notebooks
092b Labtec Webcam Plus
092c QuickCam Chat
092d QuickCam Express / Go
092e QuickCam Chat
092f QuickCam Express Plus
0950 Pocket Camera
0960 ClickSmart 420
0970 Pocket750
0990 QuickCam Pro 9000
0991 QuickCam Pro for Notebooks
0992 QuickCam Communicate Deluxe
0994 QuickCam Orbit/Sphere AF
09a1 QuickCam Communicate MP/S5500
09a2 QuickCam Communicate Deluxe/S7500
09a4 QuickCam E 3500
09a5 Quickcam 3000 For Business
09a6 QuickCam Vision Pro
09b0 Acer OrbiCam
09b2 Fujitsu Webcam
09c0 QuickCam for Dell Notebooks Mic
09c1 QuickCam Deluxe for Notebooks
0a01 USB Headset
0a02 Premium Stereo USB Headset 350
0a03 Logitech USB Microphone
0a04 V20 portable speakers (USB powered)
0a07 Z-10 Speakers
0a0b ClearChat Pro USB
0a0c Clear Chat Comfort USB Headset
0a13 Z-5 Speakers
0a14 USB Headset
0a15 G35 Headset
0a17 G330 Headset
0a1f G930
0a29 H600 [Wireless Headset]
0a37 USB Headset H540
0a38 Headset H340
0a44 Headset H390
0a45 960 Headset
0a4d G430 Surround Sound Gaming Headset
0a5b G933 Wireless Headset Dongle
0a66 [G533 Wireless Headset Dongle]
0b02 C-UV35 [Bluetooth Mini-Receiver] (HID proxy mode)
8801 Video Camera
b014 Bluetooth Mouse M336/M337/M535
b305 BT Mini-Receiver
bfe4 Premium Optical Wheel Mouse
c000 N43 [Pilot Mouse]
c001 N48/M-BB48/M-UK96A [FirstMouse Plus]
c002 M-BA47 [MouseMan Plus]
c003 MouseMan
c004 WingMan Gaming Mouse
c005 WingMan Gaming Wheel Mouse
c00b MouseMan Wheel
c00c Optical Wheel Mouse
c00d MouseMan Wheel+
c00e M-BJ58/M-BJ69 Optical Wheel Mouse
c00f MouseMan Traveler/Mobile
c011 Optical MouseMan
c012 Mouseman Dual Optical
c014 Corded Workstation Mouse
c015 Corded Workstation Mouse
c016 Optical Wheel Mouse
c018 Optical Wheel Mouse
c019 Optical Tilt Wheel Mouse
c01a M-BQ85 Optical Wheel Mouse
c01b MX310 Optical Mouse
c01c Optical Mouse
c01d MX510 Optical Mouse
c01e MX518 Optical Mouse
c024 MX300 Optical Mouse
c025 MX500 Optical Mouse
c030 iFeel Mouse
c031 iFeel Mouse+
c032 MouseMan iFeel
c033 iFeel MouseMan+
c034 MouseMan Optical
c035 Mouse
c036 Mouse
c037 Mouse
c038 Mouse
c03d M-BT96a Pilot Optical Mouse
c03e Premium Optical Wheel Mouse (M-BT58)
c03f M-BT85 [UltraX Optical Mouse]
c040 Corded Tilt-Wheel Mouse
c041 G5 Laser Mouse
c042 G3 Laser Mouse
c043 MX320/MX400 Laser Mouse
c044 LX3 Optical Mouse
c045 Optical Mouse
c046 RX1000 Laser Mouse
c047 Laser Mouse M-UAL120
c048 G9 Laser Mouse
c049 G5 Laser Mouse
c050 RX 250 Optical Mouse
c051 G3 (MX518) Optical Mouse
c053 Laser Mouse
c054 Bluetooth mini-receiver
c058 M115 Mouse
c05a M90/M100 Optical Mouse
c05b M-U0004 810-001317 [B110 Optical USB Mouse]
c05d Optical Mouse
c05f M115 Optical Mouse
c061 RX1500 Laser Mouse
c062 M-UAS144 [LS1 Laser Mouse]
c063 DELL Laser Mouse
c064 M110 corded optical mouse (M-B0001)
c066 G9x Laser Mouse
c068 G500 Laser Mouse
c069 M-U0007 [Corded Mouse M500]
c06a USB Optical Mouse
c06b G700 Wireless Gaming Mouse
c06c Optical Mouse
c077 M105 Optical Mouse
c07c M-R0017 [G700s Rechargeable Gaming Mouse]
c07d G502 Mouse
c07e G402 Gaming Mouse
c080 G303 Gaming Mouse
c083 G403 Prodigy Gaming Mouse
c084 G203 Gaming Mouse
c101 UltraX Media Remote
c110 Harmony 785/880/885 Remote
c111 Harmony 525 Remote
c112 Harmony 890 Remote
c11f Harmony 900/1100 Remote
c121 Harmony One Remote
c122 Harmony 650/700 Remote
c124 Harmony 300/350 Remote
c125 Harmony 200 Remote
c126 Harmony Link
c129 Harmony Hub
c12b Harmony Touch/Ultimate Remote
c201 WingMan Extreme Joystick with Throttle
c202 WingMan Formula
c207 WingMan Extreme Digital 3D
c208 WingMan Gamepad Extreme
c209 WingMan Gamepad
c20a WingMan RumblePad
c20b WingMan Action Pad
c20c WingMan Precision
c20d WingMan Attack 2
c20e WingMan Formula GP
c211 iTouch Cordless Receiver
c212 WingMan Extreme Digital 3D
c213 J-UH16 (Freedom 2.4 Cordless Joystick)
c214 ATK3 (Attack III Joystick)
c215 Extreme 3D Pro
c216 F310 Gamepad [DirectInput Mode]
c218 F510 Gamepad [DirectInput Mode]
c219 F710 Gamepad [DirectInput Mode]
c21a Precision Gamepad
c21c G13 Advanced Gameboard
c21d F310 Gamepad [XInput Mode]
c21e F510 Gamepad [XInput Mode]
c21f F710 Wireless Gamepad [XInput Mode]
c221 G11/G15 Keyboard / Keyboard
c222 G15 Keyboard / LCD
c223 G11/G15 Keyboard / USB Hub
c225 G11/G15 Keyboard / G keys
c226 G15 Refresh Keyboard
c227 G15 Refresh Keyboard
c228 G19 Gaming Keyboard
c229 G19 Gaming Keyboard Macro Interface
c22a Gaming Keyboard G110
c22b Gaming Keyboard G110 G-keys
c22d G510 Gaming Keyboard
c22e G510 Gaming Keyboard onboard audio
c231 G13 Virtual Mouse
c245 G400 Optical Mouse
c246 Gaming Mouse G300
c248 G105 Gaming Keyboard
c24a G600 Gaming Mouse
c24c G400s Optical Mouse
c24d G710 Gaming Keyboard
c24e G500s Laser Gaming Mouse
c281 WingMan Force
c283 WingMan Force 3D
c285 WingMan Strike Force 3D
c286 Force 3D Pro
c287 Flight System G940
c291 WingMan Formula Force
c293 WingMan Formula Force GP
c294 Driving Force
c295 Momo Force Steering Wheel
c298 Driving Force Pro
c299 G25 Racing Wheel
c29b G27 Racing Wheel
c29c Speed Force Wireless Wheel for Wii
c2a0 Wingman Force Feedback Mouse
c2a1 WingMan Force Feedback Mouse
c2ab G13 Joystick
c301 iTouch Keyboard
c302 iTouch Pro Keyboard
c303 iTouch Keyboard
c305 Internet Keyboard
c307 Internet Keyboard
c308 Internet Navigator Keyboard
c309 Y-BF37 [Internet Navigator Keyboard]
c30a iTouch Composite
c30b NetPlay Keyboard
c30c Internet Keys (X)
c30d Internet Keys
c30e UltraX Keyboard (Y-BL49)
c30f Logicool HID-Compliant Keyboard (106 key)
c311 Y-UF49 [Internet Pro Keyboard]
c312 DeLuxe 250 Keyboard
c313 Internet 350 Keyboard
c315 Classic Keyboard 200
c316 HID-Compliant Keyboard
c317 Wave Corded Keyboard
c318 Illuminated Keyboard
c31a Comfort Wave 450
c31b Compact Keyboard K300
c31c Keyboard K120
c31d Media Keyboard K200
c31f Comfort Keyboard K290
c326 Washable Keyboard K310
c328 Corded Keyboard K280e
c332 G502 Proteus Spectrum Optical Mouse
c335 G910 Orion Spectrum Mechanical Keyboard
c33a G413 Gaming Keyboard
c401 TrackMan Marble Wheel
c402 Marble Mouse (2-button)
c403 Turbo TrackMan Marble FX
c404 TrackMan Wheel
c408 Marble Mouse (4-button)
c501 Cordless Mouse Receiver
c502 Cordless Mouse & iTouch Keys
c503 Cordless Mouse+Keyboard Receiver
c504 Cordless Mouse+Keyboard Receiver
c505 Cordless Mouse+Keyboard Receiver
c506 MX700 Cordless Mouse Receiver
c508 Cordless Trackball
c509 Cordless Keyboard & Mouse
c50a Cordless Mouse
c50b Cordless Desktop Optical
c50c Cordless Desktop S510
c50d Cordless Mouse
c50e Cordless Mouse Receiver
c510 Cordless Mouse
c512 LX-700 Cordless Desktop Receiver
c513 MX3000 Cordless Desktop Receiver
c514 Cordless Mouse
c515 Cordless 2.4 GHz Presenter Presentation remote control
c517 LX710 Cordless Desktop Laser
c518 MX610 Laser Cordless Mouse
c51a MX Revolution/G7 Cordless Mouse
c51b V220 Cordless Optical Mouse for Notebooks
c521 Cordless Mouse Receiver
c525 MX Revolution Cordless Mouse
c526 Nano Receiver
c529 Logitech Keyboard + Mice
c52b Unifying Receiver
c52d R700 Remote Presenter receiver
c52e MK260 Wireless Combo Receiver
c52f Unifying Receiver
c531 C-U0007 [Unifying Receiver]
c532 Unifying Receiver
c534 Unifying Receiver
c603 3Dconnexion Spacemouse Plus XT
c605 3Dconnexion CADman
c606 3Dconnexion Spacemouse Classic
c621 3Dconnexion Spaceball 5000
c623 3Dconnexion Space Traveller 3D Mouse
c625 3Dconnexion Space Pilot 3D Mouse
c626 3Dconnexion Space Navigator 3D Mouse
c627 3Dconnexion Space Explorer 3D Mouse
c628 3Dconnexion Space Navigator for Notebooks
c629 3Dconnexion SpacePilot Pro 3D Mouse
c62b 3Dconnexion Space Mouse Pro
c640 NuLOOQ navigator
c702 Cordless Presenter
c703 Elite Keyboard Y-RP20 + Mouse MX900 (Bluetooth)
c704 diNovo Wireless Desktop
c705 MX900 Bluetooth Wireless Hub (C-UJ16A)
c707 Bluetooth wireless hub
c708 Bluetooth wireless hub
c709 BT Mini-Receiver (HCI mode)
c70a MX5000 Cordless Desktop
c70b BT Mini-Receiver (HID proxy mode)
c70c BT Mini-Receiver (HID proxy mode)
c70d Bluetooth wireless hub
c70e MX1000 Bluetooth Laser Mouse
c70f Bluetooth wireless hub
c712 Bluetooth wireless hub
c714 diNovo Edge Keyboard
c715 Bluetooth wireless hub
c71a Bluetooth wireless hub
c71d Bluetooth wireless hub
c71f diNovo Mini Wireless Keyboard
c720 Bluetooth wireless hub
ca03 MOMO Racing
ca04 Formula Vibration Feedback Wheel
ca84 Cordless Controller for Xbox
ca88 Thunderpad for Xbox
ca8a Precision Vibration Feedback Wheel for Xbox
caa3 DriveFX Racing Wheel
cab1 Cordless Keyboard for Wii HID Receiver
d001 QuickCam Pro
f301 Controller

BIN
jekyll/images/bg_hr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,9 +1,37 @@
# -*- 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.
"""Generic Human Interface Device API."""
from __future__ import absolute_import, division, print_function, unicode_literals
__author__ = "Daniel Pavel"
__license__ = "GPL"
__version__ = "0.5"
__version__ = '0.9'
from hidapi.udev import *
from hidapi.udev import (
enumerate,
open,
close,
open_path,
monitor_glib,
read,
write,
get_manufacturer,
get_product,
get_serial,
)

View File

@@ -1,4 +1,21 @@
#!/usr/bin/env python -u
# -*- 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.
from __future__ import absolute_import, division, print_function, unicode_literals
@@ -7,20 +24,36 @@ import sys
from select import select as _select
import time
from binascii import hexlify, unhexlify
import hidapi as _hid
#
#
#
try:
read_packet = raw_input
except NameError:
# Python 3 equivalent of raw_input
read_packet = input
interactive = os.isatty(0)
start_time = 0
try: # python3 support
read_packet = raw_input
except:
read_packet = input
prompt = '?? Input: ' if interactive else ''
start_time = time.time()
strhex = lambda d: hexlify(d).decode('ascii').upper()
try:
unicode
# this is certanly Python 2
is_string = lambda d: isinstance(d, unicode)
# no easy way to distinguish between b'' and '' :(
# or (isinstance(d, str) \
# and not any((chr(k) in d for k in range(0x00, 0x1F))) \
# and not any((chr(k) in d for k in range(0x80, 0xFF))) \
# )
except:
# this is certanly Python 3
# In Py3, unicode and str are equal (the unicode object does not exist)
is_string = lambda d: isinstance(d, str)
#
#
@@ -28,48 +61,54 @@ strhex = lambda d: hexlify(d).decode('ascii').upper()
from threading import Lock
print_lock = Lock()
del Lock
def _print(marker, data, scroll=False):
t = time.time() - start_time
if type(data) == unicode:
if is_string(data):
s = marker + ' ' + data
else:
hexs = strhex(data)
s = '%s (% 8.3f) [%s %s %s %s] %s' % (marker, t, hexs[0:2], hexs[2:4], hexs[4:8], hexs[8:], repr(data))
print_lock.acquire()
with print_lock:
# allow only one thread at a time to write to the console, otherwise
# the output gets garbled, especially with ANSI codes.
if interactive and scroll:
# scroll the entire screen above the current line up by 1 line
sys.stdout.write('\033[s' # save cursor position
'\033[S' # scroll up
'\033[A' # cursor up
'\033[L' # insert 1 line
'\033[G') # move cursor to column 1
sys.stdout.write(s)
if interactive and scroll:
# restore cursor position
sys.stdout.write('\033[u')
else:
sys.stdout.write('\n')
if interactive and scroll:
# scroll the entire screen above the current line up by 1 line
sys.stdout.write('\033[s' # save cursor position
'\033[S' # scroll up
'\033[A' # cursor up
'\033[L' # insert 1 line
'\033[G') # move cursor to column 1
sys.stdout.write(s)
if interactive and scroll:
# restore cursor position
sys.stdout.write('\033[u')
else:
sys.stdout.write('\n')
print_lock.release()
# flush stdout manually...
# because trying to open stdin/out unbuffered programmatically
# works much too differently in Python 2/3
sys.stdout.flush()
def _error(text, scroll=False):
_print("!!", text, scroll)
_print('!!', text, scroll)
def _continuous_read(handle, timeout=2000):
while True:
try:
reply = hidapi.read(handle, 128, timeout)
reply = _hid.read(handle, 128, timeout)
except OSError as e:
_error("Read failed, aborting: " + str(e), True)
break
assert reply is not None
if reply:
_print(">>", reply, True)
_print('>>', reply, True)
def _validate_input(line, hidpp=False):
@@ -104,9 +143,11 @@ def _validate_input(line, hidpp=False):
return data
def _open(device, hidpp):
if hidpp and not device:
for d in hidapi.enumerate(vendor_id=0x046d):
def _open(args):
device = args.device
if args.hidpp and not device:
for d in _hid.enumerate(vendor_id=0x046d):
if d.driver == 'logitech-djreceiver':
device = d.path
break
@@ -116,19 +157,24 @@ def _open(device, hidpp):
sys.exit("!! Device path required.")
print (".. Opening device", device)
handle = hidapi.open_path(device)
handle = _hid.open_path(device)
if not handle:
sys.exit("!! Failed to open %s, aborting." % device)
print (".. Opened handle %s, vendor %s product %s serial %s." % (
repr(handle),
repr(hidapi.get_manufacturer(handle)),
repr(hidapi.get_product(handle)),
repr(hidapi.get_serial(handle))))
print (".. Opened handle %r, vendor %r product %r serial %r." % (
handle,
_hid.get_manufacturer(handle),
_hid.get_product(handle),
_hid.get_serial(handle)))
if args.hidpp:
if hidapi.get_manufacturer(handle) != 'Logitech':
if _hid.get_manufacturer(handle) != b'Logitech':
sys.exit("!! Only Logitech devices support the HID++ protocol.")
print (".. HID++ validation enabled.")
else:
if (_hid.get_manufacturer(handle) == b'Logitech' and
b'Receiver' in _hid.get_product(handle)):
args.hidpp = True
print (".. Logitech receiver detected, HID++ validation enabled.")
return handle
@@ -136,17 +182,19 @@ def _open(device, hidpp):
#
#
if __name__ == '__main__':
def _parse_arguments():
import argparse
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('--history', help='history file (default ~/.hidconsole-history)')
arg_parser.add_argument('--hidpp', action='store_true', help='ensure input data is a valid HID++ request')
arg_parser.add_argument('device', nargs='?', help='linux device to connect to (/dev/hidrawX); '
'may be omitted if --hidpp is given, in which case it looks for the first Logitech receiver')
args = arg_parser.parse_args()
arg_parser.add_argument('--history', help="history file (default ~/.hidconsole-history)")
arg_parser.add_argument('--hidpp', action='store_true', help="ensure input data is a valid HID++ request")
arg_parser.add_argument('device', nargs='?', help="linux device to connect to (/dev/hidrawX); "
"may be omitted if --hidpp is given, in which case it looks for the first Logitech receiver")
return arg_parser.parse_args()
import hidapi
handle = _open(args.device, args.hidpp)
def main():
args = _parse_arguments()
handle = _open(args)
if interactive:
print (".. Press ^C/^D to exit, or type hex bytes to write to the device.")
@@ -154,15 +202,13 @@ if __name__ == '__main__':
import readline
if args.history is None:
import os.path
args.history = os.path.join(os.path.expanduser("~"), ".hidconsole-history")
args.history = os.path.join(os.path.expanduser('~'), '.hidconsole-history')
try:
readline.read_history_file(args.history)
except:
# file may not exist yet
pass
start_time = time.time()
try:
from threading import Thread
t = Thread(target=_continuous_read, args=(handle,))
@@ -176,6 +222,7 @@ if __name__ == '__main__':
while t.is_alive():
line = read_packet(prompt)
line = line.strip().replace(' ', '')
# print ("line", line)
if not line:
continue
@@ -183,24 +230,29 @@ if __name__ == '__main__':
if data is None:
continue
_print("<<", data)
hidapi.write(handle, data)
_print('<<', data)
_hid.write(handle, data)
# wait for some kind of reply
if args.hidpp and not interactive:
rlist, wlist, xlist = _select([handle], [], [], 1)
if data[1:2] == b'\xFF':
# the receiver will reply very fast, in a few milliseconds
time.sleep(0.010)
else:
# the devices might reply quite slow
rlist, wlist, xlist = _select([handle], [], [], 1)
time.sleep(1)
time.sleep(0.700)
except EOFError:
if interactive:
print ("")
except Exception as e:
print ('%s: %s' % (type(e).__name__, e))
else:
time.sleep(1)
print (".. Closing handle", repr(handle))
hidapi.close(handle)
if interactive:
readline.write_history_file(args.history)
finally:
print (".. Closing handle %r" % handle)
_hid.close(handle)
if interactive:
readline.write_history_file(args.history)
if __name__ == '__main__':
main()

View File

@@ -1,384 +0,0 @@
"""Generic Human Interface Device API.
It is little more than a thin ctypes layer over a native hidapi implementation.
The docstrings are mostly copied from the hidapi API header, with changes where
necessary.
The native HID API implemenation is available at
https://github.com/signal11/hidapi.
The native implementation comes in two flavors, hidraw (``libhidapi-hidraw.so``)
and libusb (``libhidapi-libusb.so``). For this API to work, at least one of them
must be in ``LD_LIBRARY_PATH``; otherwise an ImportError will be raised.
Using the native hidraw implementation is recommended.
Currently the native libusb implementation (temporarily) detaches the device's
USB driver from the kernel, and it may cause the device to become unresponsive.
"""
#
# LEGACY, no longer supported
#
__version__ = '0.3-hidapi-0.7.0'
import ctypes as _C
from struct import pack as _pack
#
# look for a native implementation in the same directory as this file
#
# The CDLL native library object.
_native = None
for native_implementation in ('hidraw', 'libusb'):
try:
_native = _C.cdll.LoadLibrary('libhidapi-' + native_implementation + '.so')
break
except OSError:
pass
if _native is None:
raise ImportError('hidapi: failed to load any HID API native implementation')
#
# Structures used by this API.
#
# used by the native implementation when enumerating, no need to expose it
class _NativeDeviceInfo(_C.Structure):
pass
_NativeDeviceInfo._fields_ = [
('path', _C.c_char_p),
('vendor_id', _C.c_ushort),
('product_id', _C.c_ushort),
('serial', _C.c_wchar_p),
('release', _C.c_ushort),
('manufacturer', _C.c_wchar_p),
('product', _C.c_wchar_p),
('usage_page', _C.c_ushort),
('usage', _C.c_ushort),
('interface', _C.c_int),
('next_device', _C.POINTER(_NativeDeviceInfo))
]
# the tuple object we'll expose when enumerating devices
from collections import namedtuple
DeviceInfo = namedtuple('DeviceInfo', [
'path',
'vendor_id',
'product_id',
'serial',
'release',
'manufacturer',
'product',
'interface',
'driver',
])
del namedtuple
# create a DeviceInfo tuple from a hid_device object
def _makeDeviceInfo(native_device_info):
return DeviceInfo(
path=native_device_info.path.decode('ascii'),
vendor_id=hex(native_device_info.vendor_id)[2:].zfill(4),
product_id=hex(native_device_info.product_id)[2:].zfill(4),
serial=native_device_info.serial if native_device_info.serial else None,
release=hex(native_device_info.release)[2:],
manufacturer=native_device_info.manufacturer,
product=native_device_info.product,
interface=native_device_info.interface,
driver=None)
#
# set-up arguments and return types for each hidapi function
#
_native.hid_init.argtypes = None
_native.hid_init.restype = _C.c_int
_native.hid_exit.argtypes = None
_native.hid_exit.restype = _C.c_int
_native.hid_enumerate.argtypes = [_C.c_ushort, _C.c_ushort]
_native.hid_enumerate.restype = _C.POINTER(_NativeDeviceInfo)
_native.hid_free_enumeration.argtypes = [_C.POINTER(_NativeDeviceInfo)]
_native.hid_free_enumeration.restype = None
_native.hid_open.argtypes = [_C.c_ushort, _C.c_ushort, _C.c_wchar_p]
_native.hid_open.restype = _C.c_void_p
_native.hid_open_path.argtypes = [_C.c_char_p]
_native.hid_open_path.restype = _C.c_void_p
_native.hid_close.argtypes = [_C.c_void_p]
_native.hid_close.restype = None
_native.hid_write.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t]
_native.hid_write.restype = _C.c_int
_native.hid_read.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t]
_native.hid_read.restype = _C.c_int
_native.hid_read_timeout.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t, _C.c_int]
_native.hid_read_timeout.restype = _C.c_int
_native.hid_set_nonblocking.argtypes = [_C.c_void_p, _C.c_int]
_native.hid_set_nonblocking.restype = _C.c_int
_native.hid_send_feature_report.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t]
_native.hid_send_feature_report.restype = _C.c_int
_native.hid_get_feature_report.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t]
_native.hid_get_feature_report.restype = _C.c_int
_native.hid_get_manufacturer_string.argtypes = [_C.c_void_p, _C.c_wchar_p, _C.c_size_t]
_native.hid_get_manufacturer_string.restype = _C.c_int
_native.hid_get_product_string.argtypes = [_C.c_void_p, _C.c_wchar_p, _C.c_size_t]
_native.hid_get_product_string.restype = _C.c_int
_native.hid_get_serial_number_string.argtypes = [_C.c_void_p, _C.c_wchar_p, _C.c_size_t]
_native.hid_get_serial_number_string.restype = _C.c_int
_native.hid_get_indexed_string.argtypes = [_C.c_void_p, _C.c_int, _C.c_wchar_p, _C.c_size_t]
_native.hid_get_indexed_string.restype = _C.c_int
_native.hid_error.argtypes = [_C.c_void_p]
_native.hid_error.restype = _C.c_wchar_p
#
# exposed API
# docstrings mostly copied from hidapi.h
#
def init():
"""Initialize the HIDAPI library.
This function initializes the HIDAPI library. Calling it is not strictly
necessary, as it will be called automatically by enumerate() and any of the
open_*() functions if it is needed. This function should be called at the
beginning of execution however, if there is a chance of HIDAPI handles
being opened by different threads simultaneously.
:returns: ``True`` if successful.
"""
return _native.hid_init() == 0
def exit():
"""Finalize the HIDAPI library.
This function frees all of the static data associated with HIDAPI. It should
be called at the end of execution to avoid memory leaks.
:returns: ``True`` if successful.
"""
return _native.hid_exit() == 0
def enumerate(vendor_id=None, product_id=None, interface_number=None):
"""Enumerate the HID Devices.
List all the HID devices attached to the system, optionally filtering by
vendor_id, product_id, and/or interface_number.
:returns: an iterable of matching ``DeviceInfo`` tuples.
"""
devices = _native.hid_enumerate(vendor_id, product_id)
d = devices
while d:
if interface_number is None or interface_number == d.contents.interface:
yield _makeDeviceInfo(d.contents)
d = d.contents.next_device
if devices:
_native.hid_free_enumeration(devices)
def open(vendor_id, product_id, serial=None):
"""Open a HID device by its Vendor ID, Product ID and optional serial number.
If no serial is provided, the first device with the specified IDs is opened.
:returns: an opaque device handle, or ``None``.
"""
return _native.hid_open(vendor_id, product_id, serial) or None
def open_path(device_path):
"""Open a HID device by its path name.
:param device_path: the path of a ``DeviceInfo`` tuple returned by
enumerate().
:returns: an opaque device handle, or ``None``.
"""
if type(device_path) == str:
device_path = device_path.encode('ascii')
return _native.hid_open_path(device_path) or None
def close(device_handle):
"""Close a HID device.
:param device_handle: a device handle returned by open() or open_path().
"""
_native.hid_close(device_handle)
def write(device_handle, data):
"""Write an Output report to a HID device.
:param device_handle: a device handle returned by open() or open_path().
:param data: the data bytes to send including the report number as the
first byte.
The first byte of data[] must contain the Report ID. For
devices which only support a single report, this must be set
to 0x0. The remaining bytes contain the report data. Since
the Report ID is mandatory, calls to hid_write() will always
contain one more byte than the report contains. For example,
if a hid report is 16 bytes long, 17 bytes must be passed to
hid_write(), the Report ID (or 0x0, for devices with a
single report), followed by the report data (16 bytes). In
this example, the length passed in would be 17.
write() will send the data on the first OUT endpoint, if
one exists. If it does not, it will send the data through
the Control Endpoint (Endpoint 0).
:returns: ``True`` if the write was successful.
"""
bytes_written = _native.hid_write(device_handle, _C.c_char_p(data), len(data))
return bytes_written > -1
def read(device_handle, bytes_count, timeout_ms=-1):
"""Read an Input report from a HID device.
:param device_handle: a device handle returned by open() or open_path().
:param bytes_count: maximum number of bytes to read.
:param timeout_ms: can be -1 (default) to wait for data indefinitely, 0 to
read whatever is in the device's input buffer, or a positive integer to
wait that many milliseconds.
Input reports are returned to the host through the INTERRUPT IN endpoint.
The first byte will contain the Report number if the device uses numbered
reports.
:returns: the data packet read, an empty bytes string if a timeout was
reached, or None if there was an error while reading.
"""
out_buffer = _C.create_string_buffer(b'\x00' * (bytes_count + 1))
bytes_read = _native.hid_read_timeout(device_handle, out_buffer, bytes_count, timeout_ms)
if bytes_read == -1:
return None
if bytes_read == 0:
return b''
return out_buffer[:bytes_read]
def send_feature_report(device_handle, data, report_number=None):
"""Send a Feature report to the device.
:param device_handle: a device handle returned by open() or open_path().
:param data: the data bytes to send including the report number as the
first byte.
:param report_number: if set, it is sent as the first byte with the data.
Feature reports are sent over the Control endpoint as a
Set_Report transfer. The first byte of data[] must
contain the Report ID. For devices which only support a
single report, this must be set to 0x0. The remaining bytes
contain the report data. Since the Report ID is mandatory,
calls to send_feature_report() will always contain one
more byte than the report contains. For example, if a hid
report is 16 bytes long, 17 bytes must be passed to
send_feature_report(): the Report ID (or 0x0, for
devices which do not use numbered reports), followed by the
report data (16 bytes).
:returns: ``True`` if the report was successfully written to the device.
"""
if report_number is not None:
data = _pack(b'!B', report_number) + data
bytes_written = _native.hid_send_feature_report(device_handle, _C.c_char_p(data), len(data))
return bytes_written > -1
def get_feature_report(device_handle, bytes_count, report_number=None):
"""Get a feature report from a HID device.
:param device_handle: a device handle returned by open() or open_path().
:param bytes_count: how many bytes to read.
:param report_number: if set, it is sent as the report number.
:returns: the feature report data.
"""
out_buffer = _C.create_string_buffer('\x00' * (bytes_count + 2))
if report_number is not None:
out_buffer[0] = _pack(b'!B', report_number)
bytes_read = _native.hid_get_feature_report(device_handle, out_buffer, bytes_count)
if bytes_read > -1:
return out_buffer[:bytes_read]
def _read_wchar(func, device_handle, index=None):
_BUFFER_SIZE = 64
buf = _C.create_unicode_buffer('\x00' * _BUFFER_SIZE)
if index is None:
ok = func(device_handle, buf, _BUFFER_SIZE)
else:
ok = func(device_handle, index, buf, _BUFFER_SIZE)
if ok == 0:
return buf.value
def get_manufacturer(device_handle):
"""Get the Manufacturer String from a HID device.
:param device_handle: a device handle returned by open() or open_path().
"""
return _read_wchar(_native.hid_get_manufacturer_string, device_handle)
def get_product(device_handle):
"""Get the Product String from a HID device.
:param device_handle: a device handle returned by open() or open_path().
"""
return _read_wchar(_native.hid_get_product_string, device_handle)
def get_serial(device_handle):
"""Get the serial number from a HID device.
:param device_handle: a device handle returned by open() or open_path().
"""
serial = _read_wchar(_native.hid_get_serial_number_string, device_handle)
if serial is not None:
return ''.join(hex(ord(c)) for c in serial)
def get_indexed_string(device_handle, index):
"""Get a string from a HID device, based on its string index.
Note: currently not working in the ``hidraw`` native implementation.
:param device_handle: a device handle returned by open() or open_path().
:param index: the index of the string to get.
"""
return _read_wchar(_native.hid_get_indexed_string, device_handle, index)

View File

@@ -1,3 +1,22 @@
# -*- 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.
"""Generic Human Interface Device API.
It is currently a partial pure-Python implementation of the native HID API
@@ -11,8 +30,10 @@ from __future__ import absolute_import, division, print_function, unicode_litera
import os as _os
import errno as _errno
from time import sleep
from select import select as _select
from pyudev import Context as _Context, Device as _Device
from pyudev import Context as _Context, Monitor as _Monitor, Device as _Device
from pyudev import DeviceNotFoundError
native_implementation = 'udev'
@@ -57,7 +78,126 @@ def exit():
return True
def enumerate(vendor_id=None, product_id=None, interface_number=None):
# The filter is used to determine whether this is a device of interest to Solaar
def _match(action, device, filter):
vendor_id=filter.get('vendor_id')
product_id=filter.get('product_id')
interface_number=filter.get('usb_interface')
hid_driver=filter.get('hid_driver')
usb_device = device.find_parent('usb', 'usb_device')
# print ("* parent", action, device, "usb:", usb_device)
if not usb_device:
return
vid = usb_device.get('ID_VENDOR_ID')
pid = usb_device.get('ID_MODEL_ID')
if vid is None or pid is None:
return # there are reports that sometimes the usb_device isn't set up right so be defensive
if not ((vendor_id is None or vendor_id == int(vid, 16)) and
(product_id is None or product_id == int(pid, 16))):
return
if action == 'add':
hid_device = device.find_parent('hid')
if not hid_device:
return
hid_driver_name = hid_device.get('DRIVER')
# print ("** found hid", action, device, "hid:", hid_device, hid_driver_name)
if hid_driver:
if isinstance(hid_driver, tuple):
if hid_driver_name not in hid_driver:
return
elif hid_driver_name != hid_driver:
return
intf_device = device.find_parent('usb', 'usb_interface')
# print ("*** usb interface", action, device, "usb_interface:", intf_device)
if interface_number is None:
usb_interface = None if intf_device is None else intf_device.attributes.asint('bInterfaceNumber')
else:
usb_interface = None if intf_device is None else intf_device.attributes.asint('bInterfaceNumber')
if usb_interface is None or interface_number != usb_interface:
return
attrs = usb_device.attributes
d_info = DeviceInfo(path=device.device_node,
vendor_id=vid[-4:],
product_id=pid[-4:],
serial=hid_device.get('HID_UNIQ'),
release=attrs.get('bcdDevice'),
manufacturer=attrs.get('manufacturer'),
product=attrs.get('product'),
interface=usb_interface,
driver=hid_driver_name)
return d_info
elif action == 'remove':
# print (dict(device), dict(usb_device))
d_info = DeviceInfo(path=device.device_node,
vendor_id=vid[-4:],
product_id=pid[-4:],
serial=None,
release=None,
manufacturer=None,
product=None,
interface=None,
driver=None)
return d_info
def monitor_glib(callback, *device_filters):
from gi.repository import GLib
c = _Context()
# already existing devices
# for device in c.list_devices(subsystem='hidraw'):
# # print (device, dict(device), dict(device.attributes))
# for filter in device_filters:
# d_info = _match('add', device, *filter)
# if d_info:
# GLib.idle_add(callback, 'add', d_info)
# break
m = _Monitor.from_netlink(c)
m.filter_by(subsystem='hidraw')
def _process_udev_event(monitor, condition, cb, filters):
if condition == GLib.IO_IN:
event = monitor.receive_device()
if event:
action, device = event
# print ("***", action, device)
if action == 'add':
for filter in filters:
d_info = _match(action, device, filter)
if d_info:
GLib.idle_add(cb, action, d_info)
break
elif action == 'remove':
# the GLib notification does _not_ match!
pass
return True
try:
# io_add_watch_full may not be available...
GLib.io_add_watch_full(m, GLib.PRIORITY_LOW, GLib.IO_IN, _process_udev_event, callback, device_filters)
# print ("did io_add_watch_full")
except AttributeError:
try:
# and the priority parameter appeared later in the API
GLib.io_add_watch(m, GLib.PRIORITY_LOW, GLib.IO_IN, _process_udev_event, callback, device_filters)
# print ("did io_add_watch with priority")
except:
GLib.io_add_watch(m, GLib.IO_IN, _process_udev_event, callback, device_filters)
# print ("did io_add_watch")
m.start()
def enumerate(usb_id):
"""Enumerate the HID Devices.
List all the HID devices attached to the system, optionally filtering by
@@ -65,46 +205,11 @@ def enumerate(vendor_id=None, product_id=None, interface_number=None):
:returns: a list of matching ``DeviceInfo`` tuples.
"""
for dev in _Context().list_devices(subsystem='hidraw'):
hid_dev = dev.find_parent('hid')
if not hid_dev:
continue
assert 'HID_ID' in hid_dev
bus, vid, pid = hid_dev['HID_ID'].split(':')
if vendor_id is not None and vendor_id != int(vid, 16):
continue
if product_id is not None and product_id != int(pid, 16):
continue
if bus == '0003': # USB
intf_dev = dev.find_parent('usb', 'usb_interface')
if not intf_dev:
continue
interface = intf_dev.attributes.asint('bInterfaceNumber')
if interface_number is not None and interface_number != interface:
continue
serial = hid_dev['HID_UNIQ'] if 'HID_UNIQ' in hid_dev else None
usb_dev = dev.find_parent('usb', 'usb_device')
assert usb_dev
attrs = usb_dev.attributes
d_info = DeviceInfo(path=dev.device_node,
vendor_id=vid[-4:],
product_id=pid[-4:],
serial=serial,
release=attrs['bcdDevice'],
manufacturer=attrs['manufacturer'],
product=attrs['product'],
interface=interface,
driver=hid_dev['DRIVER'])
yield d_info
elif bus == '0005': # BLUETOOTH
# TODO
pass
dev_info = _match('add', dev, usb_id)
if dev_info:
yield dev_info
def open(vendor_id, product_id, serial=None):
@@ -163,9 +268,21 @@ def write(device_handle, data):
the Control Endpoint (Endpoint 0).
"""
assert device_handle
bytes_written = _os.write(device_handle, data)
assert data
assert isinstance(data, bytes), (repr(data), type(data))
retrycount = 0
bytes_written = 0
while(retrycount < 3):
try:
bytes_written = _os.write(device_handle, data)
retrycount += 1
except IOError as e:
if e.errno == _errno.EPIPE:
sleep(0.1)
else:
break
if bytes_written != len(data):
raise OSError(errno=_errno.EIO, strerror='written %d bytes out of expected %d' % (bytes_written, len(data)))
raise IOError(_errno.EIO, 'written %d bytes out of expected %d' % (bytes_written, len(data)))
def read(device_handle, bytes_count, timeout_ms=-1):
@@ -190,12 +307,13 @@ def read(device_handle, bytes_count, timeout_ms=-1):
if xlist:
assert xlist == [device_handle]
raise OSError(errno=_errno.EIO, strerror='exception on file descriptor %d' % device_handle)
raise IOError(_errno.EIO, 'exception on file descriptor %d' % device_handle)
if rlist:
assert rlist == [device_handle]
data = _os.read(device_handle, bytes_count)
assert data is not None
assert isinstance(data, bytes), (repr(data), type(data))
return data
else:
return b''
@@ -241,27 +359,31 @@ def get_indexed_string(device_handle, index):
:param device_handle: a device handle returned by open() or open_path().
:param index: the index of the string to get.
:returns: the value corresponding to index, or None if no value found
:rtype: bytes or NoneType
"""
if index not in _DEVICE_STRINGS:
return None
try:
key = _DEVICE_STRINGS[index]
except KeyError:
return None
assert device_handle
stat = _os.fstat(device_handle)
dev = _Device.from_device_number(_Context(), 'char', stat.st_rdev)
if dev:
hid_dev = dev.find_parent('hid')
if hid_dev:
assert 'HID_ID' in hid_dev
bus, _, _ = hid_dev['HID_ID'].split(':')
try:
dev = _Device.from_device_number(_Context(), 'char', stat.st_rdev)
except (DeviceNotFoundError, ValueError):
return None
if bus == '0003': # USB
usb_dev = dev.find_parent('usb', 'usb_device')
assert usb_dev
key = _DEVICE_STRINGS[index]
attrs = usb_dev.attributes
if key in attrs:
return attrs[key]
hid_dev = dev.find_parent('hid')
if hid_dev:
assert 'HID_ID' in hid_dev
bus, _ignore, _ignore = hid_dev['HID_ID'].split(':')
elif bus == '0005': # BLUETOOTH
# TODO
pass
if bus == '0003': # USB
usb_dev = dev.find_parent('usb', 'usb_device')
assert usb_dev
return usb_dev.attributes.get(key)
elif bus == '0005': # BLUETOOTH
# TODO
pass

View File

@@ -1,9 +0,0 @@
#
#
#
from __future__ import absolute_import, division, print_function, unicode_literals
__author__ = "Daniel Pavel"
__license__ = "GPL"
__version__ = "0.8"

View File

@@ -1,34 +0,0 @@
"""Low-level interface for devices connected through a Logitech Universal
Receiver (UR).
Uses the HID api exposed through hidapi.py, a Python thin layer over a native
implementation.
Incomplete. Based on a bit of documentation, trial-and-error, and guesswork.
References:
http://julien.danjou.info/blog/2012/logitech-k750-linux-support
http://6xq.net/git/lars/lshidpp.git/plain/doc/
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import logging
_DEBUG = logging.DEBUG
_log = logging.getLogger('LUR')
_log.setLevel(logging.root.level)
# if logging.root.level > logging.DEBUG:
# _log.addHandler(logging.NullHandler())
# _log.propagate = 0
del logging
from .common import strhex
from .base import NoReceiver, NoSuchDevice, DeviceUnreachable
from .receiver import Receiver, PairedDevice, MAX_PAIRED_DEVICES
from .hidpp20 import FeatureNotSupported, FeatureCallError
from . import listener
from . import status

View File

@@ -1,99 +0,0 @@
#
#
#
from __future__ import absolute_import, division, print_function, unicode_literals
from collections import namedtuple
from .common import NamedInts as _NamedInts
from . import hidpp10 as _hidpp10
from . import hidpp20 as _hidpp20
from . import settings as _settings
#
# common strings for settings
#
_SMOOTH_SCROLL = ('smooth-scroll', 'Smooth Scrolling', 'High-sensitivity mode for vertical scroll with the wheel.')
_DPI = ('dpi', 'Sensitivity (DPI)', None)
_FN_SWAP = ('fn-swap', 'Swap Fx function', ('When set, the F1..F12 keys will activate their special function,\n'
'and you must hold the FN key to activate their standard function.\n'
'\n'
'When unset, the F1..F12 keys will activate their standard function,\n'
'and you must hold the FN key to activate their special function.'))
def _register_smooth_scroll(register, true_value, mask):
return _settings.register_toggle(_SMOOTH_SCROLL[0], register, true_value=true_value, mask=mask,
label=_SMOOTH_SCROLL[1], description=_SMOOTH_SCROLL[2])
def _register_dpi(register, choices):
return _settings.register_choices(_DPI[0], register, choices,
label=_DPI[1], description=_DPI[2])
def check_features(device, already_known):
if _hidpp20.FEATURE.FN_STATUS in device.features and not any(s.name == 'fn-swap' for s in already_known):
tfn = _settings.feature_toggle(_FN_SWAP[0], _hidpp20.FEATURE.FN_STATUS, write_returns_value=True,
label=_FN_SWAP[1], description=_FN_SWAP[2])
already_known.append(tfn(device))
#
#
#
_DeviceDescriptor = namedtuple('_DeviceDescriptor',
['name', 'kind', 'codename', 'registers', 'settings'])
DEVICES = {}
def _D(name, codename=None, kind=None, registers=None, settings=None):
if kind is None:
kind = (_hidpp10.DEVICE_KIND.mouse if 'Mouse' in name
else _hidpp10.DEVICE_KIND.keyboard if 'Keyboard' in name
else _hidpp10.DEVICE_KIND.touchpad if 'Touchpad' in name
else _hidpp10.DEVICE_KIND.trackball if 'Trackball' in name
else None)
assert kind is not None
if codename is None:
codename = name.split(' ')[-1]
assert codename is not None
DEVICES[codename] = _DeviceDescriptor(name, kind, codename, registers, settings)
_D('Wireless Mouse M315')
_D('Wireless Mouse M325')
_D('Wireless Mouse M505')
_D('Wireless Mouse M510')
_D('Couch Mouse M515')
_D('Wireless Mouse M525')
_D('Wireless Trackball M570')
_D('Touch Mouse M600')
_D('Marathon Mouse M705',
settings=[
_register_smooth_scroll(0x01, true_value=0x40, mask=0x40),
# _register_dpi(0x63, _NamedInts.range(9, 11, lambda x: '_' + str(x * 100))),
],
)
_D('Wireless Keyboard K230')
_D('Wireless Keyboard K270')
_D('Wireless Keyboard K350')
_D('Wireless Keyboard K360')
_D('Wireless Touch Keyboard K400')
_D('Wireless Solar Keyboard K750')
_D('Wireless Illuminated Keyboard K800')
_D('Zone Touch Mouse T400')
_D('Wireless Rechargeable Touchpad T650')
_D('Logitech Cube', kind='mouse')
_D('Anywhere Mouse MX', codename='Anywhere MX')
_D('Performance Mouse MX', codename='Performance MX',
settings=[
_register_dpi(0x63, _NamedInts.range(0x81, 0x8F, lambda x: '_' + str((x - 0x80) * 100))),
],
)
del namedtuple

View File

@@ -1,129 +0,0 @@
#
#
#
from __future__ import absolute_import, division, print_function, unicode_literals
from logging import getLogger # , DEBUG as _DEBUG
_log = getLogger('LUR').getChild('hidpp10')
del getLogger
from .common import (strhex as _strhex,
NamedInts as _NamedInts,
FirmwareInfo as _FirmwareInfo)
from .hidpp20 import FIRMWARE_KIND
#
# constants
#
DEVICE_KIND = _NamedInts(
keyboard=0x01,
mouse=0x02,
numpad=0x03,
presenter=0x04,
trackball=0x08,
touchpad=0x09)
POWER_SWITCH_LOCATION = _NamedInts(
base=0x01,
top_case=0x02,
edge_of_top_right_corner=0x03,
top_left_corner=0x05,
bottom_left_corner=0x06,
top_right_corner=0x07,
bottom_right_corner=0x08,
top_edge=0x09,
right_edge=0x0A,
left_edge=0x0B,
bottom_edge=0x0C)
NOTIFICATION_FLAG = _NamedInts(
battery_status=0x100000,
wireless=0x000100,
software_present=0x0000800)
ERROR = _NamedInts(
invalid_SubID__command=0x01,
invalid_address=0x02,
invalid_value=0x03,
connection_request_failed=0x04,
too_many_devices=0x05,
already_exists=0x06,
busy=0x07,
unknown_device=0x08,
resource_error=0x09,
request_unavailable=0x0A,
unsupported_parameter_value=0x0B,
wrong_pin_code=0x0C)
PAIRING_ERRORS = _NamedInts(
device_timeout=0x01,
device_not_supported=0x02,
too_many_devices=0x03,
sequence_timeout=0x06)
#
# functions
#
def get_register(device, name, default_number=-1):
known_register = device.registers[name]
register = known_register or default_number
if register > 0:
reply = device.request(0x8100 + (register & 0xFF))
if reply:
return reply
if not known_register and device.ping():
_log.warn("%s: failed to read '%s' from default register 0x%02X, blacklisting", device, name, default_number)
device.registers[-default_number] = name
def get_battery(device):
"""Reads a device's battery level, if provided by the HID++ 1.0 protocol."""
reply = get_register(device, 'battery', 0x0D)
if reply:
charge = ord(reply[:1])
status = ord(reply[2:3]) & 0xF0
status = ('discharging' if status == 0x30
else 'charging' if status == 0x50
else 'fully charged' if status == 0x90
else None)
return charge, status
def get_serial(device):
if device.kind is None:
dev_id = 0x03
receiver = device
else:
dev_id = 0x30 + device.number - 1
receiver = device.receiver
serial = receiver.request(0x83B5, dev_id)
if serial:
return _strhex(serial[1:5])
def get_firmware(device):
firmware = []
reply = device.request(0x81F1, 0x01)
if reply:
fw_version = _strhex(reply[1:3])
fw_version = '%s.%s' % (fw_version[0:2], fw_version[2:4])
reply = device.request(0x81F1, 0x02)
if reply:
fw_version += '.B' + _strhex(reply[1:3])
fw = _FirmwareInfo(FIRMWARE_KIND.Firmware, '', fw_version, None)
firmware.append(fw)
reply = device.request(0x81F1, 0x04)
if reply:
bl_version = _strhex(reply[1:3])
bl_version = '%s.%s' % (bl_version[0:2], bl_version[2:4])
bl = _FirmwareInfo(FIRMWARE_KIND.Bootloader, '', bl_version, None)
firmware.append(bl)
return tuple(firmware)

View File

@@ -1,397 +0,0 @@
#
# Logitech Unifying Receiver API.
#
from __future__ import absolute_import, division, print_function, unicode_literals
from struct import pack as _pack, unpack as _unpack
from weakref import proxy as _proxy
from logging import getLogger, DEBUG as _DEBUG
_log = getLogger('LUR').getChild('hidpp20')
del getLogger
from .common import (FirmwareInfo as _FirmwareInfo,
ReprogrammableKeyInfo as _ReprogrammableKeyInfo,
KwException as _KwException,
NamedInts as _NamedInts)
#
#
#
"""Possible features available on a Logitech device.
A particular device might not support all these features, and may support other
unknown features as well.
"""
FEATURE = _NamedInts(
ROOT=0x0000,
FEATURE_SET=0x0001,
FIRMWARE=0x0003,
NAME=0x0005,
BATTERY=0x1000,
REPROGRAMMABLE_KEYS=0x1B00,
WIRELESS=0x1D4B,
FN_STATUS=0x40A0,
SOLAR_CHARGE=0x4301,
TOUCH_MOUSE=0x6110)
FEATURE._fallback = lambda x: 'unknown:%04X' % x
FEATURE_FLAG = _NamedInts(
internal=0x20,
hidden=0x40,
obsolete=0x80)
DEVICE_KIND = _NamedInts(
keyboard=0x00,
remote_control=0x01,
numpad=0x02,
mouse=0x03,
touchpad=0x04,
trackball=0x05,
presenter=0x06,
receiver=0x07)
FIRMWARE_KIND = _NamedInts(
Firmware=0x00,
Bootloader=0x01,
Hardware=0x02,
Other=0x03)
BATTERY_OK = lambda status: status < 5
BATTERY_STATUS = _NamedInts(
discharging=0x00,
recharging=0x01,
almost_full=0x02,
full=0x03,
slow_recharge=0x04,
invalid_battery=0x05,
thermal_error=0x06)
KEY = _NamedInts(
Volume_Up=0x0001,
Volume_Down=0x0002,
Mute=0x0003,
Play__Pause=0x0004,
Next=0x0005,
Previous=0x0006,
Stop=0x0007,
Application_Switcher=0x0008,
Calculator=0x000A,
Mail=0x000E,
Home=0x001A,
Music=0x001D,
Search=0x0029,
Sleep=0x002F)
KEY._fallback = lambda x: 'unknown:%04X' % x
KEY_FLAG = _NamedInts(
reprogrammable=0x10,
FN_sensitive=0x08,
nonstandard=0x04,
is_FN=0x02,
mse=0x01)
ERROR = _NamedInts(
unknown=0x01,
invalid_argument=0x02,
out_of_range=0x03,
hardware_error=0x04,
logitech_internal=0x05,
invalid_feature_index=0x06,
invalid_function=0x07,
busy=0x08,
unsupported=0x09)
#
#
#
class FeatureNotSupported(_KwException):
"""Raised when trying to request a feature not supported by the device."""
pass
class FeatureCallError(_KwException):
"""Raised if the device replied to a feature call with an error."""
pass
#
#
#
class FeaturesArray(object):
"""A sequence of features supported by a HID++ 2.0 device."""
__slots__ = ('supported', 'device', 'features')
assert int(FEATURE.ROOT) == 0x0000
def __init__(self, device):
assert device is not None
self.device = _proxy(device)
self.supported = True
self.features = None
def __del__(self):
self.supported = False
def _check(self):
# print (self.device, "check")
if self.supported:
assert self.device
if self.features is not None:
return True
protocol = self.device.protocol
if protocol == 0:
# device is not connected right now, will have to try later
return False
# I _think_ this is universally true
if protocol < 2.0:
self.supported = False
# self.device.features = None
self.device = None
return False
reply = self.device.request(0x0000, _pack(b'!H', FEATURE.FEATURE_SET))
if reply is None:
self.supported = False
else:
fs_index = ord(reply[0:1])
if fs_index:
count = self.device.request(fs_index << 8)
if count is None:
_log.warn("FEATURE_SET found, but failed to read features count")
# most likely the device is unavailable
return False
else:
count = ord(count[:1])
assert count >= fs_index
self.features = [None] * (1 + count)
self.features[0] = FEATURE.ROOT
self.features[fs_index] = FEATURE.FEATURE_SET
return True
else:
self.supported = False
return False
__bool__ = __nonzero__ = _check
def __getitem__(self, index):
if self._check():
if isinstance(index, int):
if index < 0 or index >= len(self.features):
raise IndexError(index)
if self.features[index] is None:
feature = self.device.feature_request(FEATURE.FEATURE_SET, 0x10, index)
if feature:
feature, = _unpack(b'!H', feature[:2])
self.features[index] = FEATURE[feature]
return self.features[index]
elif isinstance(index, slice):
indices = index.indices(len(self.features))
return [self.__getitem__(i) for i in range(*indices)]
def __contains__(self, value):
if self._check():
ivalue = int(value)
may_have = False
for f in self.features:
if f is None:
may_have = True
elif ivalue == int(f):
return True
elif ivalue < int(f):
break
if may_have:
reply = self.device.request(0x0000, _pack(b'!H', ivalue))
if reply:
index = ord(reply[0:1])
if index:
self.features[index] = FEATURE[ivalue]
return True
def index(self, value):
if self._check():
may_have = False
ivalue = int(value)
for index, f in enumerate(self.features):
if f is None:
may_have = True
elif ivalue == int(f):
return index
elif ivalue < int(f):
raise ValueError("%s not in list" % repr(value))
if may_have:
reply = self.device.request(0x0000, _pack(b'!H', ivalue))
if reply:
index = ord(reply[0:1])
self.features[index] = FEATURE[ivalue]
return index
raise ValueError("%s not in list" % repr(value))
def __iter__(self):
if self._check():
yield FEATURE.ROOT
index = 1
last_index = len(self.features)
while index < last_index:
yield self.__getitem__(index)
index += 1
def __len__(self):
return len(self.features) if self._check() else 0
#
#
#
class KeysArray(object):
"""A sequence of key mappings supported by a HID++ 2.0 device."""
__slots__ = ('device', 'keys')
def __init__(self, device, count):
assert device is not None
self.device = _proxy(device)
self.keys = [None] * count
def __getitem__(self, index):
if isinstance(index, int):
if index < 0 or index >= len(self.keys):
raise IndexError(index)
if self.keys[index] is None:
keydata = feature_request(self.device, FEATURE.REPROGRAMMABLE_KEYS, 0x10, index)
if keydata:
key, key_task, flags = _unpack(b'!HHB', keydata[:5])
self.keys[index] = _ReprogrammableKeyInfo(index, KEY[key], KEY[key_task], flags)
return self.keys[index]
elif isinstance(index, slice):
indices = index.indices(len(self.keys))
return [self.__getitem__(i) for i in range(*indices)]
def index(self, value):
for index, k in enumerate(self.keys):
if k is not None and int(value) == int(k.key):
return index
for index, k in enumerate(self.keys):
if k is None:
k = self.__getitem__(index)
if k is not None:
return index
def __iter__(self):
for k in range(0, len(self.keys)):
yield self.__getitem__(k)
def __len__(self):
return len(self.keys)
#
#
#
def feature_request(device, feature, function=0x00, *params):
if device.features:
if feature in device.features:
feature_index = device.features.index(int(feature))
return device.request((feature_index << 8) + (function & 0xFF), *params)
def get_firmware(device):
"""Reads a device's firmware info.
:returns: a list of FirmwareInfo tuples, ordered by firmware layer.
"""
count = feature_request(device, FEATURE.FIRMWARE)
if count:
count = ord(count[:1])
fw = []
for index in range(0, count):
fw_info = feature_request(device, FEATURE.FIRMWARE, 0x10, index)
if fw_info:
level = ord(fw_info[:1]) & 0x0F
if level == 0 or level == 1:
name, version_major, version_minor, build = _unpack(b'!3sBBH', fw_info[1:8])
version = '%02X.%02X' % (version_major, version_minor)
if build:
version += '.B%04X' % build
extras = fw_info[9:].rstrip(b'\x00') or None
fw_info = _FirmwareInfo(FIRMWARE_KIND[level], name.decode('ascii'), version, extras)
elif level == FIRMWARE_KIND.Hardware:
fw_info = _FirmwareInfo(FIRMWARE_KIND.Hardware, '', ord(fw_info[1:2]), None)
else:
fw_info = _FirmwareInfo(FIRMWARE_KIND.Other, '', '', None)
fw.append(fw_info)
# _log.debug("device %d firmware %s", devnumber, fw_info)
return tuple(fw)
def get_kind(device):
"""Reads a device's type.
:see DEVICE_KIND:
:returns: a string describing the device type, or ``None`` if the device is
not available or does not support the ``NAME`` feature.
"""
kind = feature_request(device, FEATURE.NAME, 0x20)
if kind:
kind = ord(kind[:1])
# _log.debug("device %d type %d = %s", devnumber, kind, DEVICE_KIND[kind])
return DEVICE_KIND[kind]
def get_name(device):
"""Reads a device's name.
:returns: a string with the device name, or ``None`` if the device is not
available or does not support the ``NAME`` feature.
"""
name_length = feature_request(device, FEATURE.NAME)
if name_length:
name_length = ord(name_length[:1])
name = b''
while len(name) < name_length:
fragment = feature_request(device, FEATURE.NAME, 0x10, len(name))
if fragment:
name += fragment[:name_length - len(name)]
else:
_log.error("failed to read whole name of %s (expected %d chars)", device, name_length)
return None
return name.decode('ascii')
def get_battery(device):
"""Reads a device's battery level.
:raises FeatureNotSupported: if the device does not support this feature.
"""
battery = feature_request(device, FEATURE.BATTERY)
if battery:
discharge, dischargeNext, status = _unpack(b'!BBB', battery[:3])
if _log.isEnabledFor(_DEBUG):
_log.debug("device %d battery %d%% charged, next level %d%% charge, status %d = %s",
device.number, discharge, dischargeNext, status, BATTERY_STATUS[status])
return discharge, BATTERY_STATUS[status]
def get_keys(device):
count = feature_request(device, FEATURE.REPROGRAMMABLE_KEYS)
if count:
return KeysArray(device, ord(count[:1]))

Some files were not shown because too many files have changed in this diff Show More