Compare commits
1742 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4100c83390 | ||
|
|
4e4ece278f | ||
|
|
5c44885085 | ||
|
|
39214a4f38 | ||
|
|
fbe25b4b11 | ||
|
|
f935ff1d95 | ||
|
|
5e209dcfd9 | ||
|
|
3d82075773 | ||
|
|
b5c6cf8d63 | ||
|
|
6bddebd89b | ||
|
|
b9c17474a4 | ||
|
|
a4afffe6c3 | ||
|
|
5b20a8a859 | ||
|
|
7e6ceb988a | ||
|
|
a034a0ea10 | ||
|
|
6c02417037 | ||
|
|
d115ade2ea | ||
|
|
681a06d8d7 | ||
|
|
c53c77f427 | ||
|
|
e628298c0a | ||
|
|
019997f75c | ||
|
|
d9abdb2ecd | ||
|
|
484b097664 | ||
|
|
4c7f8c831b | ||
|
|
3e6c92de70 | ||
|
|
d646e18543 | ||
|
|
12ecef004e | ||
|
|
1deb6c34e4 | ||
|
|
3d87f418cf | ||
|
|
e3788f3d1f | ||
|
|
4c683457f9 | ||
|
|
588d7ae533 | ||
|
|
f327e3ad38 | ||
|
|
54b79d9f13 | ||
|
|
6cdb2ea9eb | ||
|
|
84bdc792b7 | ||
|
|
17a7b0689e | ||
|
|
bc398a8720 | ||
|
|
df2a68c29e | ||
|
|
3c4efb4ad5 | ||
|
|
124414063b | ||
|
|
7239e3d050 | ||
|
|
c430ff6ea8 | ||
|
|
2ce5e2ba82 | ||
|
|
416080e8c4 | ||
|
|
f8bf49c1b2 | ||
|
|
71ac905d76 | ||
|
|
862fd9c110 | ||
|
|
94ff454ace | ||
|
|
ce7dcf8326 | ||
|
|
27752778ab | ||
|
|
1696733702 | ||
|
|
00176a1df8 | ||
|
|
eedf4bfffb | ||
|
|
1869f57f7f | ||
|
|
4c43910ed7 | ||
|
|
3e2be09cb5 | ||
|
|
cb7845471c | ||
|
|
faf905de9c | ||
|
|
856f40e789 | ||
|
|
c16b02e732 | ||
|
|
a94d00e418 | ||
|
|
561e9cbfea | ||
|
|
cf0a71913e | ||
|
|
19b32f7856 | ||
|
|
69046678ac | ||
|
|
e190ad39da | ||
|
|
346c643bcc | ||
|
|
7fad50a2f4 | ||
|
|
c75aaea89d | ||
|
|
55be7a67c8 | ||
|
|
f938d3430e | ||
|
|
fed9a26cb6 | ||
|
|
13e4861043 | ||
|
|
55a91f0ae4 | ||
|
|
7a9f9972a6 | ||
|
|
f6b25a9685 | ||
|
|
56936a4d0a | ||
|
|
7442c52c20 | ||
|
|
26aa1ee15f | ||
|
|
22b99ecce7 | ||
|
|
a9c4950389 | ||
|
|
25523315ab | ||
|
|
6f28a39a47 | ||
|
|
8be2ca110a | ||
|
|
2b26c9dc92 | ||
|
|
c3e88001e4 | ||
|
|
49f2c6d8b9 | ||
|
|
bf8b861275 | ||
|
|
747d2e9c17 | ||
|
|
d6c2b30760 | ||
|
|
4d8b22f764 | ||
|
|
6dd980c541 | ||
|
|
68e2b8ce6e | ||
|
|
fa0ecc6c2c | ||
|
|
573cb6e985 | ||
|
|
7dd9609942 | ||
|
|
2d2d3e3bc6 | ||
|
|
d80e34963b | ||
|
|
0bce293017 | ||
|
|
5c96d2d307 | ||
|
|
13dfac476b | ||
|
|
f5831cbda7 | ||
|
|
b9a23f133e | ||
|
|
a4e30a7190 | ||
|
|
aff80a7572 | ||
|
|
9737a85c5a | ||
|
|
cc3ec6d987 | ||
|
|
4c4f8de040 | ||
|
|
438bb9e034 | ||
|
|
29cd1109b1 | ||
|
|
6022c37325 | ||
|
|
3947a4a083 | ||
|
|
2eb6864cfb | ||
|
|
d2f44299f3 | ||
|
|
ec9f1a94ea | ||
|
|
29ff5e5924 | ||
|
|
b36b070feb | ||
|
|
ca36d2bd1a | ||
|
|
be4632f684 | ||
|
|
74fbec4209 | ||
|
|
8c32c2e63c | ||
|
|
1ace3ef4f4 | ||
|
|
12779e7061 | ||
|
|
df8e936769 | ||
|
|
3a182c4988 | ||
|
|
136c351209 | ||
|
|
b93b4f6bc3 | ||
|
|
2f702b7ca3 | ||
|
|
665b7b6194 | ||
|
|
11fa025f1d | ||
|
|
de5878d34e | ||
|
|
08eb8a06e3 | ||
|
|
a09af769d0 | ||
|
|
785675d469 | ||
|
|
2e94add3e3 | ||
|
|
9e018fc5bf | ||
|
|
8a87b9b013 | ||
|
|
5b1125cd11 | ||
|
|
69b411fc27 | ||
|
|
629afbd812 | ||
|
|
f7a0422956 | ||
|
|
65e64c1346 | ||
|
|
9315b3fcdb | ||
|
|
cb14c2eec9 | ||
|
|
6d3d3e2086 | ||
|
|
85b4495443 | ||
|
|
49e9240be9 | ||
|
|
79606c530b | ||
|
|
aa8d2fcac4 | ||
|
|
1da6f124a0 | ||
|
|
723959ba1c | ||
|
|
fce2a29a50 | ||
|
|
d9dbf53868 | ||
|
|
2ee04d89fd | ||
|
|
8ab062363e | ||
|
|
d5a6ef058a | ||
|
|
b86af20f67 | ||
|
|
174d0388ca | ||
|
|
fa83e6ebb8 | ||
|
|
c005a94a0a | ||
|
|
d57af51316 | ||
|
|
b7a1b81181 | ||
|
|
3797c3926c | ||
|
|
95b3bdb402 | ||
|
|
560419693b | ||
|
|
4505524006 | ||
|
|
c8ab8b4350 | ||
|
|
292461c168 | ||
|
|
253cfbacd5 | ||
|
|
cfe67d4f30 | ||
|
|
822bb79ac2 | ||
|
|
306e6da7e9 | ||
|
|
791f19269d | ||
|
|
8ad648b868 | ||
|
|
a45f11fa0c | ||
|
|
be2f0b809c | ||
|
|
7242f3792c | ||
|
|
07e55c188a | ||
|
|
c515de9b09 | ||
|
|
adae5a2e2b | ||
|
|
f83c927a1e | ||
|
|
ca5fd7e5d6 | ||
|
|
4c9d9e17d6 | ||
|
|
d6b685dd2c | ||
|
|
65bc7910e5 | ||
|
|
c0a264bf81 | ||
|
|
6dbdd76db2 | ||
|
|
025700f1be | ||
|
|
d8cce70a0c | ||
|
|
f16294e5aa | ||
|
|
0736dd3164 | ||
|
|
d80b2b1651 | ||
|
|
ab76053fb3 | ||
|
|
27cda8bf08 | ||
|
|
d33b407ba8 | ||
|
|
4e8fb93b31 | ||
|
|
5acc216e12 | ||
|
|
4bc3799e96 | ||
|
|
c32a6ca91c | ||
|
|
9823e5ab8a | ||
|
|
603fbe96e0 | ||
|
|
0aa9f4a22c | ||
|
|
885cefb5b6 | ||
|
|
886df1daaf | ||
|
|
2c3578a776 | ||
|
|
a96caea5e4 | ||
|
|
0df6acd67a | ||
|
|
a763be6839 | ||
|
|
89d7490bf1 | ||
|
|
fdd6229179 | ||
|
|
93c4ebe758 | ||
|
|
6c4e0333d4 | ||
|
|
cf28308a9f | ||
|
|
df83fd655c | ||
|
|
d6ba8e0b29 | ||
|
|
22bf4fafff | ||
|
|
b96d16672b | ||
|
|
57f0ae2c99 | ||
|
|
8a2d92834f | ||
|
|
10d6a98ca1 | ||
|
|
138fe4c756 | ||
|
|
c1ce3c2c5f | ||
|
|
7873f3e8d0 | ||
|
|
37d6cab569 | ||
|
|
45ae63e58d | ||
|
|
bc2f482300 | ||
|
|
5480321f49 | ||
|
|
f1d896ded3 | ||
|
|
2ca0bd9ac3 | ||
|
|
14c1eac79c | ||
|
|
2de79141e4 | ||
|
|
c763886248 | ||
|
|
116adf9959 | ||
|
|
b3c3ad02c8 | ||
|
|
a89a973419 | ||
|
|
cea3b5d5a5 | ||
|
|
81131b90e1 | ||
|
|
795b6a35fd | ||
|
|
44f5c9f93f | ||
|
|
453be19356 | ||
|
|
0fbeebf121 | ||
|
|
79565cb31e | ||
|
|
9fca203372 | ||
|
|
64d48a19a7 | ||
|
|
1d73217ad2 | ||
|
|
585a3b901a | ||
|
|
0d9fe48b0c | ||
|
|
a9adc06b7a | ||
|
|
64062a456f | ||
|
|
27f6d6c76b | ||
|
|
e82457f284 | ||
|
|
6d56dd538e | ||
|
|
5488593caa | ||
|
|
338a2687d3 | ||
|
|
83f79c55f1 | ||
|
|
2daef846e3 | ||
|
|
c5ef207961 | ||
|
|
c02a1b820b | ||
|
|
a7ddb3efdd | ||
|
|
2f870fe0f7 | ||
|
|
3ef5e63cd4 | ||
|
|
b94ae51ac8 | ||
|
|
3f33d0633a | ||
|
|
dcafaf18e2 | ||
|
|
67e40b35e8 | ||
|
|
30f56a1c0f | ||
|
|
4b97ebd649 | ||
|
|
c2de1b59ef | ||
|
|
4e76c99e0f | ||
|
|
42b83ecce8 | ||
|
|
14c2ac6959 | ||
|
|
a1874c572b | ||
|
|
ee4275f45c | ||
|
|
70a0fcd906 | ||
|
|
18d79f8dd4 | ||
|
|
cdc7a27c9e | ||
|
|
39a5350f30 | ||
|
|
538ab9c947 | ||
|
|
d898edc4a3 | ||
|
|
ed0b730e74 | ||
|
|
50392da360 | ||
|
|
85a86ec3c5 | ||
|
|
6290c84efd | ||
|
|
dbdbbf7fb3 | ||
|
|
3d65a77515 | ||
|
|
e15ce68498 | ||
|
|
011f3f556b | ||
|
|
8854ca6f23 | ||
|
|
4690ca77c4 | ||
|
|
d172d27408 | ||
|
|
67dbe5f4c8 | ||
|
|
5aedbad692 | ||
|
|
9495cc03c2 | ||
|
|
9deb7d66aa | ||
|
|
c67bd32522 | ||
|
|
ce98e89427 | ||
|
|
72b37deb52 | ||
|
|
0cfb9b8896 | ||
|
|
51c6b6f2de | ||
|
|
1c1be84e59 | ||
|
|
4edbf51f17 | ||
|
|
98b5804a21 | ||
|
|
d3799dcf41 | ||
|
|
44b1b5b6d0 | ||
|
|
f5fac6f713 | ||
|
|
be143992ff | ||
|
|
086a8252d2 | ||
|
|
39beaf8b3a | ||
|
|
3969472dd3 | ||
|
|
90bae7db84 | ||
|
|
a734a35b7e | ||
|
|
64915b09f7 | ||
|
|
7add22e861 | ||
|
|
75fec689a0 | ||
|
|
5d885f76e7 | ||
|
|
42624c7102 | ||
|
|
087b99a2de | ||
|
|
b3a6dc5b2e | ||
|
|
95dafbe3aa | ||
|
|
a1dc69d203 | ||
|
|
e32cf61fa8 | ||
|
|
f7488f67c1 | ||
|
|
6c62f975d0 | ||
|
|
62034758f0 | ||
|
|
e66a83aa36 | ||
|
|
a288caa7ee | ||
|
|
5be7541875 | ||
|
|
33a4bf8bf5 | ||
|
|
b2970186df | ||
|
|
52fcbe3b48 | ||
|
|
b34061c766 | ||
|
|
2ce8a3b249 | ||
|
|
8c5800e536 | ||
|
|
804ba267f6 | ||
|
|
6099df1b42 | ||
|
|
fc1e38d196 | ||
|
|
55ed173c39 | ||
|
|
593d27770d | ||
|
|
0dbb93e6a5 | ||
|
|
68049efc41 | ||
|
|
1d18e4d8f7 | ||
|
|
d3a18bb85f | ||
|
|
1cb8f0c874 | ||
|
|
7e360e4416 | ||
|
|
9842972d8b | ||
|
|
a4b54df433 | ||
|
|
6ed09d0643 | ||
|
|
1bd68177ab | ||
|
|
985ebd46cd | ||
|
|
3fb197b78c | ||
|
|
cb67897d15 | ||
|
|
533cd54b92 | ||
|
|
a658f2e2b0 | ||
|
|
5aa45a78c3 | ||
|
|
689d57d097 | ||
|
|
dc3f70ff86 | ||
|
|
58f1a142ec | ||
|
|
10233dac30 | ||
|
|
ec9ac9c920 | ||
|
|
5642a658ab | ||
|
|
08d571aea9 | ||
|
|
3cd76aa191 | ||
|
|
3d3d0d4ccc | ||
|
|
83f45218de | ||
|
|
69df28c155 | ||
|
|
babdb44b4f | ||
|
|
daee35de4a | ||
|
|
8d01e28138 | ||
|
|
04d79810d4 | ||
|
|
6fa1bfd044 | ||
|
|
c1a79a49f8 | ||
|
|
04775a3719 | ||
|
|
20f16e8e10 | ||
|
|
eb0d939d1a | ||
|
|
4b52b77348 | ||
|
|
8fccd84345 | ||
|
|
2ea92db3ca | ||
|
|
205047e278 | ||
|
|
c268ff7a45 | ||
|
|
7dbf92955e | ||
|
|
82a41bf46b | ||
|
|
1de3b2e472 | ||
|
|
f6b76900d9 | ||
|
|
1c6f289d91 | ||
|
|
ca0e2a0a3f | ||
|
|
111f2be5c8 | ||
|
|
f68a831c81 | ||
|
|
b722eccf04 | ||
|
|
53b7c63680 | ||
|
|
aa4456e9dc | ||
|
|
8d657f891a | ||
|
|
a688bfd9ec | ||
|
|
a47f3fa5d1 | ||
|
|
69f889e33f | ||
|
|
52049af8e1 | ||
|
|
7d0402a97f | ||
|
|
0427e5607e | ||
|
|
419a7722ad | ||
|
|
60afd53257 | ||
|
|
a99a5a544e | ||
|
|
244d48d245 | ||
|
|
808a719823 | ||
|
|
56db8fbdf9 | ||
|
|
0af12fbf2e | ||
|
|
646151ae61 | ||
|
|
66138ad7c0 | ||
|
|
d81a971455 | ||
|
|
66f3d5d02b | ||
|
|
6b8e7a2d9c | ||
|
|
504d23fab7 | ||
|
|
52109ade91 | ||
|
|
daafe5ebca | ||
|
|
8be0e21ac7 | ||
|
|
9c04bfad92 | ||
|
|
4025b83dfd | ||
|
|
bc51117f59 | ||
|
|
a8819b06c8 | ||
|
|
6f973cdc27 | ||
|
|
b548d05cad | ||
|
|
ef3d3e5290 | ||
|
|
487e1a3ded | ||
|
|
4206d370f1 | ||
|
|
29ccd55210 | ||
|
|
b399380445 | ||
|
|
1d68ef858e | ||
|
|
717213c506 | ||
|
|
0b5c263799 | ||
|
|
1379da70a8 | ||
|
|
f42ff35f24 | ||
|
|
3d8c9272fb | ||
|
|
381371c899 | ||
|
|
be590c154a | ||
|
|
30e4324906 | ||
|
|
545db1f641 | ||
|
|
5e2b2b6647 | ||
|
|
f3a276d7a3 | ||
|
|
02a7d8cadd | ||
|
|
4da7feec3b | ||
|
|
f75c9845d2 | ||
|
|
b947dd4896 | ||
|
|
ade9c816c7 | ||
|
|
8141fafb4b | ||
|
|
79b18d07c9 | ||
|
|
d92939135f | ||
|
|
733bf913e6 | ||
|
|
1162ccb897 | ||
|
|
73ddb12d8e | ||
|
|
93b5a0008b | ||
|
|
847205eb06 | ||
|
|
98b4aff33d | ||
|
|
a4e4c160c1 | ||
|
|
b97c83be97 | ||
|
|
2e4e0a0676 | ||
|
|
93fe73214c | ||
|
|
4ca2496a6f | ||
|
|
b19006104f | ||
|
|
dba9d472a8 | ||
|
|
7a7aad8977 | ||
|
|
254e2cb77e | ||
|
|
fdb1b43373 | ||
|
|
a9d6b4c319 | ||
|
|
7908a4f5a4 | ||
|
|
757c731610 | ||
|
|
612e8fb4f7 | ||
|
|
3effccf390 | ||
|
|
84e0e74709 | ||
|
|
ec8a51d353 | ||
|
|
3b6a4ed0ed | ||
|
|
815c9755b5 | ||
|
|
1e7050595e | ||
|
|
fc59c0fbf6 | ||
|
|
4874d72c16 | ||
|
|
e6cfd0a0c1 | ||
|
|
ebf7984ad0 | ||
|
|
2654b6bbe0 | ||
|
|
9f7c7209fe | ||
|
|
41fb08c059 | ||
|
|
362d43a7a1 | ||
|
|
0259e44c31 | ||
|
|
df8b6b488c | ||
|
|
825b7b6f34 | ||
|
|
b1d4b2f3cd | ||
|
|
58823763ea | ||
|
|
aeb8588e06 | ||
|
|
ebfd26b3d0 | ||
|
|
95a30a8089 | ||
|
|
dca6b4ba38 | ||
|
|
b1706fa9e2 | ||
|
|
ff5d744183 | ||
|
|
377e44c624 | ||
|
|
6e986ddf8c | ||
|
|
714f8782b3 | ||
|
|
ad57db4a39 | ||
|
|
8b5d56feb4 | ||
|
|
2153035c30 | ||
|
|
dbf6226f77 | ||
|
|
7a82b93aaf | ||
|
|
9de4d392d4 | ||
|
|
b0297694d1 | ||
|
|
7fdba7fe75 | ||
|
|
9f330479c1 | ||
|
|
36e8dcb396 | ||
|
|
708edbc444 | ||
|
|
d87bc594f4 | ||
|
|
7a65c40312 | ||
|
|
6994e1e41c | ||
|
|
1ce67954cb | ||
|
|
1e8956ff96 | ||
|
|
c8fe87ee2d | ||
|
|
aa067b2774 | ||
|
|
b3751913b2 | ||
|
|
09394cfbf5 | ||
|
|
7498febc3a | ||
|
|
4a5c0ea523 | ||
|
|
633760e261 | ||
|
|
68aebc8c1b | ||
|
|
831287ead6 | ||
|
|
1bba8b26de | ||
|
|
718c2d4039 | ||
|
|
1516daa6d0 | ||
|
|
4df84107e1 | ||
|
|
3e4c09380a | ||
|
|
e6947d95d8 | ||
|
|
f5c00a5f2a | ||
|
|
246c6cc1b2 | ||
|
|
2d29db4609 | ||
|
|
374388daf0 | ||
|
|
fe55e39560 | ||
|
|
535b1f02ce | ||
|
|
eec5df5d56 | ||
|
|
c4d2ec4008 | ||
|
|
00ea128775 | ||
|
|
b98033d558 | ||
|
|
16823092bc | ||
|
|
9a13eb0229 | ||
|
|
35114490d3 | ||
|
|
bf3aeff7d8 | ||
|
|
d027c66198 | ||
|
|
04e8281738 | ||
|
|
f5c63ccc39 | ||
|
|
9b8f96e824 | ||
|
|
5117028c52 | ||
|
|
eda0a95585 | ||
|
|
5041530952 | ||
|
|
9d0fcea02e | ||
|
|
1400473877 | ||
|
|
330fadfbce | ||
|
|
b3cc4361e8 | ||
|
|
2e1e8dc9b5 | ||
|
|
44f85d5dee | ||
|
|
78a6ae9208 | ||
|
|
4c31adb907 | ||
|
|
15b1965582 | ||
|
|
6918353a29 | ||
|
|
1973693cc8 | ||
|
|
1361af5501 | ||
|
|
6e5d36e59f | ||
|
|
95dc973748 | ||
|
|
e7047f4606 | ||
|
|
d1908694c4 | ||
|
|
b5bb04b8a2 | ||
|
|
14725e42ee | ||
|
|
5b796bae7d | ||
|
|
e4f5d75095 | ||
|
|
409065ed29 | ||
|
|
56c6a52941 | ||
|
|
fd02b33971 | ||
|
|
e763aeadb4 | ||
|
|
aaee650caf | ||
|
|
6645b5b04c | ||
|
|
e8f169f6f5 | ||
|
|
19a5fa3911 | ||
|
|
64e20533a0 | ||
|
|
86a49128b4 | ||
|
|
a579eb4ded | ||
|
|
59296f41ca | ||
|
|
0b0cf63240 | ||
|
|
5dbf691403 | ||
|
|
c1b6bf92c7 | ||
|
|
3909a79149 | ||
|
|
97caca023f | ||
|
|
11bc5bde37 | ||
|
|
fb328b3993 | ||
|
|
4fbf5aa531 | ||
|
|
07b42e2b34 | ||
|
|
95893f3aac | ||
|
|
46e6c98523 | ||
|
|
e4d3f5e61e | ||
|
|
a2ac8b46c1 | ||
|
|
d2eabe4258 | ||
|
|
204bc6e810 | ||
|
|
e436b1bd1d | ||
|
|
4dfa55c96c | ||
|
|
7f70039284 | ||
|
|
2d2e71daa3 | ||
|
|
4ce2abca0a | ||
|
|
bc6b1de472 | ||
|
|
90cc629f26 | ||
|
|
de0894bc34 | ||
|
|
e86a50cfa9 | ||
|
|
b6615d5abe | ||
|
|
323fb13161 | ||
|
|
fef22de021 | ||
|
|
5a4205d002 | ||
|
|
1c2b347512 | ||
|
|
63872b9146 | ||
|
|
c6506b3508 | ||
|
|
c9c472e391 | ||
|
|
1dc59fd374 | ||
|
|
24798ee310 | ||
|
|
e05c1aa90c | ||
|
|
fe0ab16cc8 | ||
|
|
c38d10a654 | ||
|
|
d386f4369b | ||
|
|
ae4a0eba70 | ||
|
|
72fd2f255e | ||
|
|
a8d067035d | ||
|
|
27c90fa736 | ||
|
|
bbaa144397 | ||
|
|
e751f741f7 | ||
|
|
8e89aa0038 | ||
|
|
627185079f | ||
|
|
de5514aa23 | ||
|
|
0bc58d5653 | ||
|
|
33521558ed | ||
|
|
63fa581d13 | ||
|
|
e6369e0c3c | ||
|
|
be4e88dc1a | ||
|
|
72a8d311bc | ||
|
|
cab523e122 | ||
|
|
070a2bf837 | ||
|
|
0836766bfb | ||
|
|
4379bd0613 | ||
|
|
ad2660a1bd | ||
|
|
6d16462988 | ||
|
|
e69c4c6b4f | ||
|
|
5e4c792a64 | ||
|
|
c5ca2c2818 | ||
|
|
f631f0f551 | ||
|
|
ef54a750dc | ||
|
|
c99f470dd5 | ||
|
|
1dfc4f22df | ||
|
|
68b4ca7abf | ||
|
|
09125bce2d | ||
|
|
aeb03df3f7 | ||
|
|
f191d95990 | ||
|
|
5926596298 | ||
|
|
97fdcbf3ff | ||
|
|
66c8621cab | ||
|
|
a4bf1da6f9 | ||
|
|
922414ae04 | ||
|
|
9beb13a305 | ||
|
|
89995656cd | ||
|
|
f198b2706b | ||
|
|
bd0f9ca7d7 | ||
|
|
784661bbc0 | ||
|
|
579b09619b | ||
|
|
013f383bc8 | ||
|
|
7936d2dd48 | ||
|
|
cb84d3b797 | ||
|
|
79947dca6c | ||
|
|
d41c35b1c6 | ||
|
|
093169fb23 | ||
|
|
6c77aa3b61 | ||
|
|
4a108b3ab7 | ||
|
|
fac6cd6840 | ||
|
|
edf610d235 | ||
|
|
dac9c1bd8e | ||
|
|
352375aa9a | ||
|
|
44722560d2 | ||
|
|
101e24c7bf | ||
|
|
b7e8e646b5 | ||
|
|
97fa7de28a | ||
|
|
302720b0db | ||
|
|
813c238704 | ||
|
|
354c914bd2 | ||
|
|
574aee0cc7 | ||
|
|
a3cdcf4cd1 | ||
|
|
592ced0a53 | ||
|
|
3a2593798e | ||
|
|
67b7d46844 | ||
|
|
5411e43b77 | ||
|
|
66dc0bd285 | ||
|
|
f641554ed5 | ||
|
|
beec4c2130 | ||
|
|
f5bf488ffc | ||
|
|
1deaa09142 | ||
|
|
88a0dfff6f | ||
|
|
f28da6e7c4 | ||
|
|
5290980ac8 | ||
|
|
4d23d3abac | ||
|
|
0c4e757cf9 | ||
|
|
d487a0d889 | ||
|
|
65824a4c08 | ||
|
|
58a1c7ffb0 | ||
|
|
1f896d2b9e | ||
|
|
377c954933 | ||
|
|
4744ce47b2 | ||
|
|
b01b74f2a8 | ||
|
|
6282ae05e8 | ||
|
|
b5e1f47c50 | ||
|
|
8ffaeb112f | ||
|
|
2189d4a35b | ||
|
|
706ee2990f | ||
|
|
06875fb9ab | ||
|
|
f6b0cc59ed | ||
|
|
e3aacdbf05 | ||
|
|
45dc81b4c4 | ||
|
|
0324fd9a1e | ||
|
|
ca9f9b3447 | ||
|
|
624247d378 | ||
|
|
5f8dbdeb6d | ||
|
|
2bdb844557 | ||
|
|
422f336d70 | ||
|
|
563ef0d8ef | ||
|
|
3a85c4f64b | ||
|
|
4056f5b9d3 | ||
|
|
442a7d18a5 | ||
|
|
79be4b20d7 | ||
|
|
b2f3b56c31 | ||
|
|
072f932206 | ||
|
|
d5a3a4fe7e | ||
|
|
a49b7938e0 | ||
|
|
1eef88eb44 | ||
|
|
eda1399330 | ||
|
|
8dbc4b5707 | ||
|
|
687a28d2c2 | ||
|
|
f733390bd1 | ||
|
|
ac6fa9643f | ||
|
|
f28053a09a | ||
|
|
49145ae272 | ||
|
|
af26870e83 | ||
|
|
007163a563 | ||
|
|
a9acdbe47a | ||
|
|
955df30c7f | ||
|
|
23c0397764 | ||
|
|
789f5f05c3 | ||
|
|
ea2c22c015 | ||
|
|
1c09b9c45d | ||
|
|
dd9626f7a4 | ||
|
|
35909afb0d | ||
|
|
8e67bbbc11 | ||
|
|
a5813e4e23 | ||
|
|
d439d43be6 | ||
|
|
11465f2b2a | ||
|
|
079f2dacd4 | ||
|
|
7c6bd4202d | ||
|
|
1740a9a8c4 | ||
|
|
0cadc3247e | ||
|
|
e23de2ee9f | ||
|
|
8fb52a3f37 | ||
|
|
3edac85b90 | ||
|
|
64c76e51ef | ||
|
|
02cac598a0 | ||
|
|
02a47b4003 | ||
|
|
4afe8c893b | ||
|
|
5afa094175 | ||
|
|
196705ba1f | ||
|
|
4c46a999f7 | ||
|
|
7bd31c0d95 | ||
|
|
dc2a1adf26 | ||
|
|
e89b50cdf2 | ||
|
|
d08e0a9574 | ||
|
|
22d37c4c1c | ||
|
|
546ccb7ac2 | ||
|
|
1ab03d4c9f | ||
|
|
a6fcb75aa8 | ||
|
|
907c5ab075 | ||
|
|
515f994ab8 | ||
|
|
25905c5d77 | ||
|
|
babf0f4ded | ||
|
|
41664b8e21 | ||
|
|
5c080a7831 | ||
|
|
5aa4fa0239 | ||
|
|
4f4e610635 | ||
|
|
39791be440 | ||
|
|
2814350f9f | ||
|
|
4a28b48275 | ||
|
|
97474a21de | ||
|
|
719106bf0f | ||
|
|
0a735a32ed | ||
|
|
bd26b9340d | ||
|
|
f45ae5ffad | ||
|
|
0520dde990 | ||
|
|
e53781ec6e | ||
|
|
1bc189e2fe | ||
|
|
91bcfa28ea | ||
|
|
64c1de32da | ||
|
|
56762b5494 | ||
|
|
77e21a0b63 | ||
|
|
d6fa5269c5 | ||
|
|
0198d58dc7 | ||
|
|
c30f0a79bd | ||
|
|
89ee83b906 | ||
|
|
0bef7b84f8 | ||
|
|
c3e90bc73e | ||
|
|
814b7f30ba | ||
|
|
8039c035a7 | ||
|
|
430b70711b | ||
|
|
82915eea4b | ||
|
|
995544396c | ||
|
|
4678f52293 | ||
|
|
26c5a5f9ba | ||
|
|
c6ccc0638d | ||
|
|
6ba8c6c3fc | ||
|
|
9087f4187c | ||
|
|
673c81c096 | ||
|
|
43bfa80753 | ||
|
|
3884ce14d7 | ||
|
|
4fafd4f6be | ||
|
|
0bec0e02b1 | ||
|
|
59c0367283 | ||
|
|
63f523dac6 | ||
|
|
4822975acb | ||
|
|
c389c9c2b7 | ||
|
|
76e70799aa | ||
|
|
2a94cc9233 | ||
|
|
ae9e862f19 | ||
|
|
12f4e187d6 | ||
|
|
51dd2a5d28 | ||
|
|
6981555804 | ||
|
|
3583759d3a | ||
|
|
c92a889b68 | ||
|
|
b9fb005c9c | ||
|
|
a06ea6de11 | ||
|
|
a868b477e1 | ||
|
|
c799e038de | ||
|
|
8468be2126 | ||
|
|
1ff9c3a40b | ||
|
|
9b201f6b0d | ||
|
|
afda6f9f66 | ||
|
|
5cc0b8854d | ||
|
|
f88951c56d | ||
|
|
2aab7f71fd | ||
|
|
6376980213 | ||
|
|
1bb08d011d | ||
|
|
966c55e69d | ||
|
|
6b14004a6f | ||
|
|
7a4f7bbb84 | ||
|
|
155e2f8c40 | ||
|
|
6a1968beff | ||
|
|
f4557233f1 | ||
|
|
a597b81f5a | ||
|
|
a587ae65d1 | ||
|
|
6522b5fef0 | ||
|
|
7f78f0c580 | ||
|
|
127a8053d8 | ||
|
|
6c0acee645 | ||
|
|
60c52eb13f | ||
|
|
8bac8d68f4 | ||
|
|
087a5d2c42 | ||
|
|
481511b6c2 | ||
|
|
21d98294bd | ||
|
|
ebbb54758b | ||
|
|
c07c115ee3 | ||
|
|
8c02320795 | ||
|
|
932164458a | ||
|
|
de79bf1b5c | ||
|
|
5944103aef | ||
|
|
ab4226e066 | ||
|
|
a66121db0d | ||
|
|
eacfdea37f | ||
|
|
68b1f4e413 | ||
|
|
947035a7b7 | ||
|
|
e54134cda9 | ||
|
|
1609c3e98a | ||
|
|
ed9aa76547 | ||
|
|
b8529030e6 | ||
|
|
1412a07899 | ||
|
|
f79ad67ea7 | ||
|
|
dd8018a4d5 | ||
|
|
350784eb70 | ||
|
|
f0fc63e5b7 | ||
|
|
51375d4510 | ||
|
|
2c0ea34694 | ||
|
|
867edf8516 | ||
|
|
dcd1a88250 | ||
|
|
8f95dd323d | ||
|
|
336b778398 | ||
|
|
572c7f5e59 | ||
|
|
6b12b7935f | ||
|
|
ade2fbacec | ||
|
|
a59368f3e7 | ||
|
|
d021d87656 | ||
|
|
5d0d353c74 | ||
|
|
e00d680fc9 | ||
|
|
59b7285fdf | ||
|
|
988bdc2c8d | ||
|
|
1a67b33860 | ||
|
|
d43bffc9d9 | ||
|
|
f8079f4f9d | ||
|
|
47e7f997d5 | ||
|
|
8c0cf9fe9b | ||
|
|
fa8bd83ba3 | ||
|
|
697fb999b4 | ||
|
|
aeb943fc9e | ||
|
|
434af009cb | ||
|
|
cc010cb653 | ||
|
|
e450e959a6 | ||
|
|
10f3421021 | ||
|
|
8eba60d617 | ||
|
|
e3d658ea10 | ||
|
|
ef1c051e10 | ||
|
|
bc566718b4 | ||
|
|
22719f21fc | ||
|
|
c51daa922c | ||
|
|
632d8804be | ||
|
|
a4b7194490 | ||
|
|
ea80c6d639 | ||
|
|
a01e4b2efe | ||
|
|
801bdfa224 | ||
|
|
410d100dc6 | ||
|
|
7078750a3f | ||
|
|
360c92f6b0 | ||
|
|
2377fef3a8 | ||
|
|
684afa871e | ||
|
|
dd2f884504 | ||
|
|
9dd05bb727 | ||
|
|
e96a0fbfbb | ||
|
|
f9618dd0ab | ||
|
|
db0656967b | ||
|
|
53ec751cf1 | ||
|
|
45cc161cc7 | ||
|
|
1ccd2d1856 | ||
|
|
d9d37edc2f | ||
|
|
ae405871fb | ||
|
|
f4700f07ce | ||
|
|
d2d19a615d | ||
|
|
c36cc506b6 | ||
|
|
7180693f89 | ||
|
|
aa08356823 | ||
|
|
197ff7365d | ||
|
|
a0c6a6ce59 | ||
|
|
934ecb821d | ||
|
|
f0cf949336 | ||
|
|
ecd245e8dc | ||
|
|
f65f000d38 | ||
|
|
3b60f205f7 | ||
|
|
d6c93cfcfe | ||
|
|
cbd71f9d24 | ||
|
|
45d5119a5a | ||
|
|
773cb7f45f | ||
|
|
d74e3a9b92 | ||
|
|
fe1fba7ac6 | ||
|
|
4e20ef61c8 | ||
|
|
a750b32d14 | ||
|
|
69006c48c6 | ||
|
|
b12d03dfe3 | ||
|
|
ddbf93fb24 | ||
|
|
65c55b789c | ||
|
|
d83530bee3 | ||
|
|
e6c02f5c52 | ||
|
|
122d76d061 | ||
|
|
fb1442dbcb | ||
|
|
0b8141f092 | ||
|
|
137c32262b | ||
|
|
7c726738b1 | ||
|
|
2570f584b9 | ||
|
|
4c1f568fab | ||
|
|
27bd71253e | ||
|
|
9a9a82016f | ||
|
|
aa03cef61f | ||
|
|
c14e30b6f5 | ||
|
|
b5d43cdc3c | ||
|
|
1edd8a577b | ||
|
|
358e0958bb | ||
|
|
fa5fba796b | ||
|
|
ce215228f3 | ||
|
|
28e43395ab | ||
|
|
e09231c05a | ||
|
|
f29de0f3dd | ||
|
|
ba540338e2 | ||
|
|
2442fee341 | ||
|
|
bbadd3e755 | ||
|
|
2fdce2f938 | ||
|
|
f1fad2d16b | ||
|
|
8a5700b44e | ||
|
|
e046455a05 | ||
|
|
ddbc27486c | ||
|
|
2041007b38 | ||
|
|
7b7e17819e | ||
|
|
f855cd60e1 | ||
|
|
883ed9549d | ||
|
|
d1858f747b | ||
|
|
aa7d1b6410 | ||
|
|
bc3a98ddb2 | ||
|
|
5b01f375e0 | ||
|
|
dd2755909d | ||
|
|
b052ab9ef0 | ||
|
|
9c768d60a1 | ||
|
|
d1d0ab85ff | ||
|
|
e1eee2e078 | ||
|
|
5c38f90cd6 | ||
|
|
45d49b9de8 | ||
|
|
4ccb8ab26d | ||
|
|
ab162583e4 | ||
|
|
e25b47aa1c | ||
|
|
63a98819a6 | ||
|
|
27d3d80d30 | ||
|
|
478381a994 | ||
|
|
51a15a960f | ||
|
|
92967eed23 | ||
|
|
57338303e8 | ||
|
|
e735ce10f0 | ||
|
|
d75b6d2f2b | ||
|
|
bd1470dad7 | ||
|
|
15f97681ef | ||
|
|
7075ce910a | ||
|
|
5ba816dd38 | ||
|
|
a515cc3860 | ||
|
|
73344cbf26 | ||
|
|
cf27328d13 | ||
|
|
869f1e4791 | ||
|
|
e2d65a690e | ||
|
|
3141f06472 | ||
|
|
b88cf5a07b | ||
|
|
a344ad9867 | ||
|
|
76e327d2fa | ||
|
|
0ae0ef195a | ||
|
|
b1f74a1280 | ||
|
|
30431fbfb8 | ||
|
|
fb4c055fbf | ||
|
|
3ea51fe1a2 | ||
|
|
afd36764c2 | ||
|
|
b694809394 | ||
|
|
66296265ba | ||
|
|
952495ce04 | ||
|
|
29eb377267 | ||
|
|
47345e1dcb | ||
|
|
36fc6de760 | ||
|
|
6c0aca8c63 | ||
|
|
bd93689109 | ||
|
|
4e5d4853d6 | ||
|
|
bb2361a986 | ||
|
|
7c8d4815f0 | ||
|
|
0f05589cd6 | ||
|
|
21db60a14e | ||
|
|
091c28ca8b | ||
|
|
9af353dd32 | ||
|
|
981ff00ca3 | ||
|
|
ec0197df3d | ||
|
|
2111107ff4 | ||
|
|
2b08c5e0c9 | ||
|
|
cc8a6c4ab5 | ||
|
|
437e17cf37 | ||
|
|
22191d7d0c | ||
|
|
ba890c2d2e | ||
|
|
9a6cdd9cee | ||
|
|
32324f3e66 | ||
|
|
ffe297b239 | ||
|
|
7fe5983f7c | ||
|
|
d5f14bb5f8 | ||
|
|
f3049ed451 | ||
|
|
8485494ea7 | ||
|
|
7a75813a84 | ||
|
|
35830e3d50 | ||
|
|
46fd4dac56 | ||
|
|
ebd8635f84 | ||
|
|
efbf43b472 | ||
|
|
8a6d8e2ed1 | ||
|
|
bff99799ab | ||
|
|
1434b2a50d | ||
|
|
c3fdbfb643 | ||
|
|
a9ebac264f | ||
|
|
60a591ab6b | ||
|
|
ab3a6b50d4 | ||
|
|
b193b39701 | ||
|
|
806d67a72f | ||
|
|
9c465cd998 | ||
|
|
024a71b618 | ||
|
|
f144816256 | ||
|
|
f0eeea8625 | ||
|
|
72819b6130 | ||
|
|
23e4f32e11 | ||
|
|
243d1548dc | ||
|
|
c3bc56f306 | ||
|
|
288c607069 | ||
|
|
55c307d0e5 | ||
|
|
69febfcea5 | ||
|
|
9934755566 | ||
|
|
a7561eaa9b | ||
|
|
689661169a | ||
|
|
eac40abc3e | ||
|
|
372e4e0949 | ||
|
|
e42f7f1393 | ||
|
|
3860d4a56b | ||
|
|
3b75b69970 | ||
|
|
a4f0eab855 | ||
|
|
f54ea27d97 | ||
|
|
db48fe1b40 | ||
|
|
d0a0e902a7 | ||
|
|
95a6412d5c | ||
|
|
5faecbf4f3 | ||
|
|
5af1719384 | ||
|
|
6a66370ffe | ||
|
|
c0874220d2 | ||
|
|
9c67b1b494 | ||
|
|
22656d5b82 | ||
|
|
d55963caba | ||
|
|
413cebe40f | ||
|
|
140ffae01a | ||
|
|
68251777fb | ||
|
|
188b20a4f1 | ||
|
|
5fba1db11c | ||
|
|
21b1a722fc | ||
|
|
715c50685b | ||
|
|
dd0ba17351 | ||
|
|
576dd4cdd4 | ||
|
|
a2a0380401 | ||
|
|
f1a85f45bd | ||
|
|
200cf48df4 | ||
|
|
14b5993dc3 | ||
|
|
585ba93588 | ||
|
|
e30a692a6e | ||
|
|
edc563e0e4 | ||
|
|
969ca59948 | ||
|
|
53abd22176 | ||
|
|
f449b37bda | ||
|
|
c97f4082dd | ||
|
|
5e6761c61b | ||
|
|
b2c87b4f80 | ||
|
|
58fcb074ff | ||
|
|
dbff65a4d1 | ||
|
|
a7ac589692 | ||
|
|
3d4570cd1f | ||
|
|
b6bc35ed3e | ||
|
|
5d4d0c07ad | ||
|
|
15cb97c56e | ||
|
|
f902b32755 | ||
|
|
fcfc7cd6fc | ||
|
|
c3718d22d6 | ||
|
|
2829acd6f5 | ||
|
|
c35ae8ffc9 | ||
|
|
f7159e9338 | ||
|
|
4074fb7750 | ||
|
|
444169d84b | ||
|
|
5d5f97a776 | ||
|
|
a8c5d3bc24 | ||
|
|
dd2a18d60e | ||
|
|
a3f9860181 | ||
|
|
1fed000855 | ||
|
|
61dfefde94 | ||
|
|
454fbcbc6e | ||
|
|
8112e90ded | ||
|
|
a4c0ad3d73 | ||
|
|
30f2afacb7 | ||
|
|
2a27c1d14e | ||
|
|
cccf4ec428 | ||
|
|
38c76393b1 | ||
|
|
ce9b10dc2d | ||
|
|
13e89dc219 | ||
|
|
16af3a9acc | ||
|
|
c690b2c9e9 | ||
|
|
43ab629a26 | ||
|
|
b83a14e16f | ||
|
|
a966bbff6f | ||
|
|
141a5c3dee | ||
|
|
994bb07bc4 | ||
|
|
24f658d8fe | ||
|
|
49d77a2f90 | ||
|
|
876cf35954 | ||
|
|
46c0448854 | ||
|
|
d78c7ed9be | ||
|
|
51d0ccf654 | ||
|
|
9c8252b59f | ||
|
|
488a78cc52 | ||
|
|
0e6d088372 | ||
|
|
d4d1a4f8e2 | ||
|
|
34801bfd1e | ||
|
|
948b4c4d51 | ||
|
|
85efe92d30 | ||
|
|
b01636e05d | ||
|
|
c0a7838429 | ||
|
|
eda4112501 | ||
|
|
dbb9025e26 | ||
|
|
beee0bc8c2 | ||
|
|
1bd6fd512b | ||
|
|
ab8421b2f2 | ||
|
|
1be56dd072 | ||
|
|
c023f81f1a | ||
|
|
47f64d40de | ||
|
|
d0b8233c9a | ||
|
|
39534d11dd | ||
|
|
ca2f5f927c | ||
|
|
2ab040591c | ||
|
|
8b26759731 | ||
|
|
0e43287386 | ||
|
|
7221ceb7b4 | ||
|
|
66416ff4cc | ||
|
|
0d89d1e6c8 | ||
|
|
81765ee971 | ||
|
|
b72273b2a9 | ||
|
|
e697a2d6cf | ||
|
|
94d07eed53 | ||
|
|
64ce3872b4 | ||
|
|
508444526a | ||
|
|
faa6de3b75 | ||
|
|
77d2ae5249 | ||
|
|
e2f94a9e0e | ||
|
|
ba55e4d9bd | ||
|
|
8e9ff939f3 | ||
|
|
bd3198f6f0 | ||
|
|
3319feeb73 | ||
|
|
47bcd4478c | ||
|
|
065b8628d2 | ||
|
|
87e2f1cad7 | ||
|
|
373b07f271 | ||
|
|
58f598fc88 | ||
|
|
8f44c294d7 | ||
|
|
f65079ad6d | ||
|
|
edce56cd20 | ||
|
|
cd437c3809 | ||
|
|
007cbef086 | ||
|
|
a03cc9ce64 | ||
|
|
3275aa4c12 | ||
|
|
a0f880fbba | ||
|
|
833f087fdf | ||
|
|
9a2a28e0aa | ||
|
|
bf5fc42f07 | ||
|
|
fb495fd2fc | ||
|
|
90ab7af069 | ||
|
|
0914e4c48d | ||
|
|
3436055c7f | ||
|
|
20aa797e96 | ||
|
|
5ebc2634ae | ||
|
|
94464a40b8 | ||
|
|
1194abf125 | ||
|
|
ceba698678 | ||
|
|
b1e9480f5a | ||
|
|
eaa38c858c | ||
|
|
4504045bc6 | ||
|
|
a9ea69b9a1 | ||
|
|
9a8d089c73 | ||
|
|
0d56cfbded | ||
|
|
9896875180 | ||
|
|
a1c04ce39f | ||
|
|
da541e000a | ||
|
|
e490162e4f | ||
|
|
a0b7d39f83 | ||
|
|
c464e049bf | ||
|
|
daad9b5d5f | ||
|
|
2682722cb1 | ||
|
|
8d5718178f | ||
|
|
1d438f098f | ||
|
|
1d305db29e | ||
|
|
c2a549c114 | ||
|
|
f43e298ac7 | ||
|
|
c25b769578 | ||
|
|
0cf1f1983d | ||
|
|
39ec568ab1 | ||
|
|
5b94ebae34 | ||
|
|
a857b5fc43 | ||
|
|
eb8791ec47 | ||
|
|
ff6da43007 | ||
|
|
d42fdf8a4a | ||
|
|
adab25ad44 | ||
|
|
90b057938b | ||
|
|
fc5c72e164 | ||
|
|
bd5c03812f | ||
|
|
6b0b7ea823 | ||
|
|
dd24ed5fe0 | ||
|
|
f64942b51d | ||
|
|
375db9996f | ||
|
|
20dfc063ff | ||
|
|
70c341e268 | ||
|
|
dc59c79bd3 | ||
|
|
422cd26b92 | ||
|
|
cec892ce88 | ||
|
|
d5374b9f51 | ||
|
|
51e2d965cf | ||
|
|
a6c8f2212a | ||
|
|
b3aac40246 | ||
|
|
fb138b77ff | ||
|
|
273284da39 | ||
|
|
7102229937 | ||
|
|
be80ba3b3b | ||
|
|
4410cb6dc6 | ||
|
|
df8df2bffa | ||
|
|
ae4c921300 | ||
|
|
3d1aa6698d | ||
|
|
613b115eb4 | ||
|
|
e19b690bd5 | ||
|
|
888be8e8a8 | ||
|
|
5785896007 | ||
|
|
8d522de7e7 | ||
|
|
81ae4c8d4d | ||
|
|
8cd3b8fdef | ||
|
|
c1aa341a7a | ||
|
|
f9c192c47a | ||
|
|
cdc6da844e | ||
|
|
fd35f23af7 | ||
|
|
c04851f64e | ||
|
|
3a63c3ad43 | ||
|
|
431f1c97cf | ||
|
|
1b68a3d5a9 | ||
|
|
c797808a40 | ||
|
|
d810ccba84 | ||
|
|
2fea5d9af2 | ||
|
|
1d9a3bf23a | ||
|
|
3d8c764eb0 | ||
|
|
eb317f0d46 | ||
|
|
27de1aea11 | ||
|
|
92f7e761ee | ||
|
|
b2f1786eff | ||
|
|
f8369e7c63 | ||
|
|
f095a74f2a | ||
|
|
4e3fccb009 | ||
|
|
a2995ed3c5 | ||
|
|
5edff9235b | ||
|
|
31e134c1e0 | ||
|
|
47e22b788f | ||
|
|
798628fdf8 | ||
|
|
ca9825d262 | ||
|
|
1a36ec65ee | ||
|
|
d07a20e6f8 | ||
|
|
783b317281 | ||
|
|
4bc525f250 | ||
|
|
11cfc7ea09 | ||
|
|
a806f2672d | ||
|
|
2fee88e54b | ||
|
|
7e1a2a6e4f | ||
|
|
d5b311760e | ||
|
|
dffe6f8b91 | ||
|
|
b4bca4670b | ||
|
|
150c43f41f | ||
|
|
9fc11df229 | ||
|
|
56a7a960c3 | ||
|
|
cd44cc6396 | ||
|
|
4af714f1dd | ||
|
|
836719587c | ||
|
|
2d6fab6e14 | ||
|
|
0ae58a3346 | ||
|
|
f32e958984 | ||
|
|
0703d927ca | ||
|
|
62b5deb77d | ||
|
|
82e718b3d1 | ||
|
|
41409c9b94 | ||
|
|
57c759773a | ||
|
|
9d6402a4f7 | ||
|
|
a29609df21 | ||
|
|
04ea8293a8 | ||
|
|
bde54aba3b | ||
|
|
687e1be3e5 | ||
|
|
a44d9b7ca8 | ||
|
|
febf571d84 | ||
|
|
818ece9f10 | ||
|
|
ec10c9c70c | ||
|
|
8852d50971 | ||
|
|
908f6763be | ||
|
|
03e20842fb | ||
|
|
084913ac91 | ||
|
|
d9801e2d57 | ||
|
|
29fe913fd8 | ||
|
|
5b68f9623e | ||
|
|
2a6662472d | ||
|
|
5cf6777340 | ||
|
|
17863c85b6 | ||
|
|
237d0f9d9a | ||
|
|
b98e27e464 | ||
|
|
d01d9edb78 | ||
|
|
0a86683392 | ||
|
|
b2b4febd31 | ||
|
|
ad67e6eaee | ||
|
|
ed5ce48f65 | ||
|
|
2e351bfc78 | ||
|
|
f324b97e8b | ||
|
|
46544e1cbe | ||
|
|
ffab6c0e12 | ||
|
|
10e736386b | ||
|
|
a1ecebf5bf | ||
|
|
996597dcb1 | ||
|
|
e09ad373b3 | ||
|
|
ddf7d34982 | ||
|
|
db9a4e4402 | ||
|
|
39a75a6792 | ||
|
|
d78484ff38 | ||
|
|
8900ac9a1f | ||
|
|
7df2e8af97 | ||
|
|
2ed723dfc2 | ||
|
|
087177274d | ||
|
|
59459ebbd6 | ||
|
|
2d981cd737 | ||
|
|
4c4e6fd6f9 | ||
|
|
c52f2fc069 | ||
|
|
eb3e2566e9 | ||
|
|
c186573775 | ||
|
|
3d9d8d6efc | ||
|
|
1ed82fc7d5 | ||
|
|
162228aff3 | ||
|
|
dd051f4c6e | ||
|
|
e59645b347 | ||
|
|
cbdc0bd99b | ||
|
|
b4fc36701a | ||
|
|
f2f00e3017 | ||
|
|
c706fbc6e7 | ||
|
|
88fb8458c1 | ||
|
|
982f298fc4 | ||
|
|
4a9a05718e | ||
|
|
b99a851af3 | ||
|
|
f452d6f5b7 | ||
|
|
b98b94de91 | ||
|
|
b18aee9dba | ||
|
|
bfe7bcf1b4 | ||
|
|
55bb732bb0 | ||
|
|
465fea8a16 | ||
|
|
149758ccab | ||
|
|
16095544cb | ||
|
|
37265f25d8 | ||
|
|
c61eb3f039 | ||
|
|
39862034e1 | ||
|
|
f938b29040 | ||
|
|
984b92815c | ||
|
|
82c4b0007c | ||
|
|
f4a3f699e8 | ||
|
|
9c4055a046 | ||
|
|
088493dc4f | ||
|
|
479ab1fb7b | ||
|
|
749cde6e72 | ||
|
|
7317fad754 | ||
|
|
83a29328c7 | ||
|
|
788fb145af | ||
|
|
b1b1a9b5de | ||
|
|
941a36a385 | ||
|
|
3ef3c23a29 | ||
|
|
39e630cece | ||
|
|
b2a62c2dd7 | ||
|
|
26dd3a2ca8 | ||
|
|
c328d6f6c6 | ||
|
|
44c79d71d7 | ||
|
|
ecd90d605a | ||
|
|
b6bd4b9da0 | ||
|
|
6ae11f862c | ||
|
|
c224141355 | ||
|
|
28c35633d3 | ||
|
|
6e36e33b22 | ||
|
|
093cca9d21 | ||
|
|
410c19dd78 | ||
|
|
4a7be89be6 | ||
|
|
51305e0a21 | ||
|
|
fda3398440 | ||
|
|
340ff0107c | ||
|
|
8374a58dc1 | ||
|
|
3690863a27 | ||
|
|
078d003cfe | ||
|
|
b6ab795878 | ||
|
|
7e81dede2f | ||
|
|
3482257b15 | ||
|
|
9f3ab8d3dd | ||
|
|
8f2ee555ec | ||
|
|
db53de2233 | ||
|
|
3596faed2f | ||
|
|
9e13d134d3 | ||
|
|
7f229005a6 | ||
|
|
e3a887f36c | ||
|
|
bca8e64574 | ||
|
|
3873d7099c | ||
|
|
48b176f49a | ||
|
|
8b8b387f2a | ||
|
|
f459d9b953 | ||
|
|
b276fbab90 | ||
|
|
e73f076324 | ||
|
|
131f8f7f45 | ||
|
|
c3b73964d5 | ||
|
|
790fc7c04b | ||
|
|
cd33314d0b | ||
|
|
4ba50267f1 | ||
|
|
d46e603366 | ||
|
|
f8878d73c3 | ||
|
|
9c0dac044c | ||
|
|
2f8e330b73 | ||
|
|
e6e55aa827 | ||
|
|
07bff8cb37 | ||
|
|
d857144653 | ||
|
|
17fdd840bb | ||
|
|
da6711c93c | ||
|
|
36b307eb49 | ||
|
|
2d8ec2fd78 | ||
|
|
11ba96103c | ||
|
|
843d2a224d | ||
|
|
0faf01c194 | ||
|
|
e868cf6270 | ||
|
|
255b3d0da7 | ||
|
|
5fad8d0680 | ||
|
|
d3dcdcb92e | ||
|
|
44ae5edc56 | ||
|
|
f0542923d7 | ||
|
|
29d0c07164 | ||
|
|
152abb086a | ||
|
|
d5c36ddc89 | ||
|
|
226a4ea2f3 | ||
|
|
ac0eafe6ab | ||
|
|
87bc9a5431 | ||
|
|
ef62892f60 | ||
|
|
7ae24488d9 | ||
|
|
6482670fdf | ||
|
|
317cf6d00f | ||
|
|
a5eeac6e5a | ||
|
|
e2cf9255ac | ||
|
|
25941cdbdd | ||
|
|
1764633bc5 | ||
|
|
f6eb90bd2d | ||
|
|
5f46c820e6 | ||
|
|
c20b279362 | ||
|
|
24ceb8801e | ||
|
|
8d5ca66db7 | ||
|
|
f0d250ff15 | ||
|
|
074cafbab1 | ||
|
|
79cd52833c | ||
|
|
6b75286885 | ||
|
|
b884ae039c | ||
|
|
3ecfdd027e | ||
|
|
55ca9927b0 | ||
|
|
b67377c41e | ||
|
|
15f24eb26b | ||
|
|
0283bb0e91 | ||
|
|
d39c0995b6 | ||
|
|
db4c088ce9 | ||
|
|
a4898e24b7 | ||
|
|
086db0d52f | ||
|
|
7b3523fb24 | ||
|
|
74ca91d611 | ||
|
|
e94d4b28b0 | ||
|
|
a85aa2da52 | ||
|
|
dded8504e6 | ||
|
|
a2bad425f6 | ||
|
|
a4ec8ec05d | ||
|
|
1b4bf7918b | ||
|
|
1f48e44cc6 | ||
|
|
83613f02a0 | ||
|
|
9d8743e765 | ||
|
|
84b9b11ef5 | ||
|
|
2327a0012e | ||
|
|
4cdd796a3d | ||
|
|
e819265e7e | ||
|
|
070a96c506 | ||
|
|
e1be54823c | ||
|
|
d7dd9393ff | ||
|
|
64c36a1562 | ||
|
|
13a54565ba | ||
|
|
12eb17cc41 | ||
|
|
9715dfa126 | ||
|
|
a6e3689e97 | ||
|
|
2e5cf81231 | ||
|
|
4eeca12d6a | ||
|
|
ad577d22d0 | ||
|
|
5e68094e87 | ||
|
|
10c26fe642 | ||
|
|
49ecd252ed | ||
|
|
2ee2a5dc46 | ||
|
|
430fdf4fcf | ||
|
|
abca81ea38 | ||
|
|
a0a76f738b | ||
|
|
7d440c2430 | ||
|
|
94274fd092 | ||
|
|
266edd80f3 | ||
|
|
d1b1be32ca | ||
|
|
fbdd923d43 | ||
|
|
2c30414f88 | ||
|
|
d8e469a33a | ||
|
|
a6b89b3ea3 | ||
|
|
0f80901bce | ||
|
|
8fc45e5590 | ||
|
|
c829304e31 | ||
|
|
d3f94ff2fb | ||
|
|
85d9a9dc27 | ||
|
|
04db6d3838 | ||
|
|
e5a28ac64e | ||
|
|
2397c6c0ea | ||
|
|
c3e6c3d1da | ||
|
|
22da75cb72 | ||
|
|
22a8ca37b6 | ||
|
|
692afba3d9 | ||
|
|
9c621d5816 | ||
|
|
feedbcf581 | ||
|
|
a57f3be58d | ||
|
|
897dffc426 | ||
|
|
6f0b61e6d8 | ||
|
|
674ee9ac9e | ||
|
|
5eab013cf6 | ||
|
|
079ef8d800 | ||
|
|
1a9be279c6 | ||
|
|
f5d2eba0c4 | ||
|
|
e7d19c9084 | ||
|
|
638bf38b25 | ||
|
|
c4dc49ac5e | ||
|
|
926600e29d | ||
|
|
5e58f1e273 | ||
|
|
c79ad65d37 | ||
|
|
95a97ad776 | ||
|
|
6c28cedf23 | ||
|
|
a3599b53bb | ||
|
|
438c501fae | ||
|
|
25cbd55841 | ||
|
|
5ef53f251d | ||
|
|
92819b6c9e | ||
|
|
d22674f362 | ||
|
|
0fc83e9255 | ||
|
|
f171c5d59e | ||
|
|
78b8299130 | ||
|
|
2c7fe0c92d | ||
|
|
6ff30f2a0e | ||
|
|
7707c5e558 | ||
|
|
9b7a920e0d | ||
|
|
2e51380be5 | ||
|
|
445f508ea5 | ||
|
|
b82c89c582 | ||
|
|
85a47a8049 | ||
|
|
f8e9798038 | ||
|
|
581d6747ad | ||
|
|
00a1aa7628 | ||
|
|
79a9048db5 | ||
|
|
2bfba2e399 | ||
|
|
484419e526 | ||
|
|
8c18830c97 | ||
|
|
653d370a85 | ||
|
|
316e91cfcf | ||
|
|
f31632c8c8 | ||
|
|
bb52c13f9a | ||
|
|
738d43fd83 | ||
|
|
1c6c8588d9 | ||
|
|
7a97cb2e02 | ||
|
|
5e0d2992c9 | ||
|
|
210859a5ef | ||
|
|
25f6d229dd | ||
|
|
60405abf58 | ||
|
|
8070b11c27 | ||
|
|
7d76ce77c9 | ||
|
|
3d48cbc111 | ||
|
|
36f34da227 | ||
|
|
d06e07542e | ||
|
|
a0c8646923 | ||
|
|
6c924de209 | ||
|
|
500503c069 | ||
|
|
5dd8cd66dd | ||
|
|
41e84e55f1 | ||
|
|
7f8888d7dd | ||
|
|
216928f904 | ||
|
|
345bab3a99 | ||
|
|
064a7a113c | ||
|
|
115d5c7db1 | ||
|
|
8a86ecc38d | ||
|
|
430a2d71e3 | ||
|
|
187c0d2a52 | ||
|
|
8fbe77afb2 | ||
|
|
e43e92f2b0 | ||
|
|
cc6c0ee7df | ||
|
|
3cd0665166 | ||
|
|
a42e696695 | ||
|
|
83886fbcf1 | ||
|
|
f0c5046ccf | ||
|
|
9db2a65b31 | ||
|
|
59c5619b44 | ||
|
|
b39016df7c | ||
|
|
c22fe6320d | ||
|
|
b99ccdf612 | ||
|
|
2d338ffbfb | ||
|
|
739cb9306a | ||
|
|
954fc29613 | ||
|
|
630f71b349 | ||
|
|
2b3f274aae | ||
|
|
e834e46ef6 | ||
|
|
27f10cd10e | ||
|
|
f4b92ee690 | ||
|
|
1c4d3d5f13 | ||
|
|
7bb7a092a4 | ||
|
|
0ed623caf9 | ||
|
|
19cd40cfdd | ||
|
|
7617a1ef8e | ||
|
|
a370afe94b | ||
|
|
ff5a1ac7cb | ||
|
|
893c7e3ab2 | ||
|
|
17698bfeae | ||
|
|
8b90e99658 | ||
|
|
fa72b89b3a | ||
|
|
fd3c88cb67 | ||
|
|
8b44ca913f | ||
|
|
7fe79a703e | ||
|
|
80c36a02a9 | ||
|
|
4bdfe9b9b8 | ||
|
|
767e8a0db4 | ||
|
|
d8a2ffa835 | ||
|
|
d38bec39b6 | ||
|
|
33a9ca060d | ||
|
|
30fedf418c | ||
|
|
5bdacb377c | ||
|
|
ee16892481 | ||
|
|
e2909f6165 | ||
|
|
205d25e341 | ||
|
|
f49ced2d92 | ||
|
|
b86dcce381 | ||
|
|
c4be58f074 | ||
|
|
b3f0bfa4fb | ||
|
|
37daf3a192 | ||
|
|
7ada4af31b | ||
|
|
67db483b0b | ||
|
|
357e118ace | ||
|
|
f2cdbe26b6 | ||
|
|
3569489ce7 | ||
|
|
6c3fa224e0 | ||
|
|
9066003240 | ||
|
|
f0007d0a13 | ||
|
|
ff6db1d00a | ||
|
|
27403a08d2 | ||
|
|
6d70d2aada | ||
|
|
0e551383ba | ||
|
|
b5b86ab8b8 | ||
|
|
61d0159e8a | ||
|
|
c41859816b | ||
|
|
5a99e55309 | ||
|
|
1b6e6692c0 | ||
|
|
116ba72f37 | ||
|
|
3fe9caf0e6 | ||
|
|
a403c3b596 | ||
|
|
2a44b0bb5b | ||
|
|
130a23dd4f | ||
|
|
db0d6e8bbc | ||
|
|
1cc532d600 | ||
|
|
8f5fa0cf9a | ||
|
|
89c6904d69 | ||
|
|
14663ca204 | ||
|
|
64d2b35ace | ||
|
|
ab5e09db93 | ||
|
|
932a015e49 | ||
|
|
d6b18cd426 | ||
|
|
84540fb087 | ||
|
|
5b8c983ab3 | ||
|
|
13a11e78f0 | ||
|
|
fb8cf26c51 | ||
|
|
41db725e15 | ||
|
|
f25d2ba183 | ||
|
|
66531635bc | ||
|
|
4c5cf85091 | ||
|
|
6db4deafee | ||
|
|
2c312c1a5b | ||
|
|
bcc2bf123e | ||
|
|
50fedab19e | ||
|
|
d0ccd3e9c2 | ||
|
|
4b2d8a8d5a | ||
|
|
c12364a7c7 | ||
|
|
560400e786 | ||
|
|
f7a4d89467 |
10
.git-blame-ignore-revs
Normal file
@@ -0,0 +1,10 @@
|
||||
# yapf bulk change
|
||||
72a8d311bce64b1536c08e754d22bb91efb66460
|
||||
# isort bulk change
|
||||
e6369e0c3c240715a0a2daede6c3b225ed63cf60
|
||||
# pre-commit bulk change
|
||||
33521558ed7007c24b24127f1448c2c23ecbfb35
|
||||
# flake8 bulk change
|
||||
627185079f65c9cc471194b7927c833682e4a7a3
|
||||
# yapf style update
|
||||
27c90fa736d8a7a1ef6acda4345d3599862e185c
|
||||
39
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Information**
|
||||
<!-- Make sure that your issue is not one of the known issues in the Solaar documentation at https://pwr-solaar.github.io/Solaar/ -->
|
||||
<!-- Do not bother opening an issue for a version older than 1.1.0. Update to the latest version and see if your issue persists. -->
|
||||
- Solaar version (`solaar --version` or `git describe --tags` if cloned from this repository):
|
||||
- Distribution:
|
||||
- Kernel version (ex. `uname -srmo`): `KERNEL VERSION HERE`
|
||||
- Output of `solaar show`:
|
||||
|
||||
<details>
|
||||
|
||||
```
|
||||
OUTPUT HERE
|
||||
```
|
||||
</details>
|
||||
|
||||
**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.
|
||||
35
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Information**
|
||||
<!-- Please update to Solaar from this repository before asking for a new feature. -->
|
||||
- Solaar version (`solaar --version` and `git describe --tags`):
|
||||
- Distribution:
|
||||
- Kernel version (ex. `uname -srmo`):
|
||||
- Output of `solaar show` for the target device (if applicable):
|
||||
|
||||
<details>
|
||||
|
||||
```
|
||||
OUTPUT HERE
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
16
.github/workflows/checks.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: checks
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
|
||||
- name: Run pre-commit
|
||||
uses: pre-commit/action@v2.0.0
|
||||
17
.gitignore
vendored
@@ -1,4 +1,19 @@
|
||||
*.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/
|
||||
|
||||
/po/*.po~
|
||||
|
||||
26
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v3.1.0
|
||||
hooks:
|
||||
- id: check-ast
|
||||
- id: check-builtin-literals
|
||||
- id: check-merge-conflict
|
||||
- id: check-yaml
|
||||
- id: check-toml
|
||||
- id: debug-statements
|
||||
- id: double-quote-string-fixer
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/pre-commit/mirrors-yapf
|
||||
rev: v0.30.0
|
||||
hooks:
|
||||
- id: yapf
|
||||
- repo: https://github.com/pre-commit/mirrors-isort
|
||||
rev: v4.3.21
|
||||
hooks:
|
||||
- id: isort
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.8.3
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies: ['flake8-bugbear']
|
||||
41
COPYING
@@ -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
@@ -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/>.
|
||||
415
ChangeLog.md
Normal file
@@ -0,0 +1,415 @@
|
||||
# 1.1.2
|
||||
|
||||
* Update documentation on supported devices and translations
|
||||
* Include evdev as a dependency
|
||||
* Try to use uinput for fake input if XTest extension not available
|
||||
* Add Nano receiver C542 for M190 mice
|
||||
* Broaden range of HID++ Bluetooth devices
|
||||
* Add setting to divert gestures
|
||||
* Rule editor can edit all rule components
|
||||
* Configuation via solaar config takes effect in Solaar UI if it is running
|
||||
* Add setting to disable Onboard Profiles and decouple from Polling Rate setting
|
||||
* Add setting for PERSISTENT_REMAPPABLE_ACTION, common keyboard and mouse cases only
|
||||
* Split Test rule condition into Test and TestBytes and support in rule editor
|
||||
* Fix bug in speed-change setting
|
||||
* Support Backlight3 feature
|
||||
* Ensure that settings are pushed in resume
|
||||
* Update German, Polish, and zh_CN translations
|
||||
* Determine device number for direct-connected devices from protocol
|
||||
* fix bug in add and delete button actions in rule editor
|
||||
* dispose of no-op notifications quickly
|
||||
* add rule condition for checking device settings
|
||||
* use local file for conversion from key names to keysyms
|
||||
* get keyboard group and use to get correct keycodes (X11 only)
|
||||
* improve how rules work under Wayland
|
||||
* add settings for M-Key LEDs and MR-Key LED
|
||||
* fix bug in unpacking M and MR key notification
|
||||
* add G815 keyboard and MX518 mouse
|
||||
* add new special keys for recent keyboards
|
||||
* track M and MR keys for use in rules
|
||||
* make sure that device is online when searching for devices in solaar show
|
||||
* don't check for device kind in dpi sliding setting
|
||||
* fix problem with devices that report 0 DPI
|
||||
* handle missing divert-setting in action RW for settings
|
||||
* add id property (unitId or serial) and don't use ? for unknown serial
|
||||
* fix contains for NamedInts and eliminate use of has_element
|
||||
* check for xtest and disable modifier checking if not available
|
||||
* improve determination of gesture information
|
||||
* add Set rules to rule GUI
|
||||
* add gesture params to Set rules
|
||||
* hide system tray when there are no devices to control
|
||||
* add G733 headset, G9 mouse, G502 Hero mouse
|
||||
* Use greyscale solaar icon in tray when using symbolic icons
|
||||
* Fix bugs in solaar config
|
||||
* Use classes for settings to hep with modularity
|
||||
* Accept '~' and Toggle for toggling boolean settings in cli and rules
|
||||
* handle errors when writing to devices
|
||||
* refactor config_panel.py to use classes for widgets
|
||||
* add rules action to set Solaar settings
|
||||
* decrease amount of logging at each debug level
|
||||
* don't stretch toggles in settings
|
||||
* use key structure for key remapping setting
|
||||
* optimize ReprogrammableKey implementation
|
||||
* keep track of settings that are absent from device
|
||||
* add G512 keyboard and G402 mouse
|
||||
* reformat descriptors.py
|
||||
* use feature numbers for reprogrammable key versions
|
||||
* don't use new_from_icon_set in menu as it is deprecated
|
||||
|
||||
# 1.1.1
|
||||
|
||||
* Keep left pane in Solaar main window the same size
|
||||
* Fix crash when checking a process condition when X11 not running
|
||||
* Add version number to output of solaar show
|
||||
* Fix crash when pinging a device with unknown protocol
|
||||
* Display battery percentage estimates from battery voltage
|
||||
* Add minimal support for Logitech PRO X Wireless Gaming Headset
|
||||
* Push settings when device requests software reconfiguration
|
||||
* Fix read for key/button diversion setting
|
||||
* Add modalias information to Solaar metainfo
|
||||
* Don't do on-screen notifications when devices are powered on
|
||||
* Add setting to switch crown between smooth and ratchet scrolling
|
||||
* Add write_prefix_bytes argument to Boolean validator
|
||||
* Update Russian and Spanish translations
|
||||
* New shell script tools to help determine capabilities of receivers
|
||||
* Add special keys for MX Keys for Business and MX Keys Mini
|
||||
* Improve tray menu ordering
|
||||
* Add --tray-icon-size option to get around bugs in some tray implementations
|
||||
|
||||
# 1.1.0
|
||||
|
||||
* Fix bug when adding receiver to tray menu
|
||||
* Add Catalan translation.
|
||||
* Add toggle command to solaar config to toggle boolean settings
|
||||
* Don't select windows with no PID when looking for focus window
|
||||
* Catch errors when applying settings so that other settings are not affected
|
||||
* Add support for Bolt receivers and devices, including pairing
|
||||
* Revise method for creating system tray menu
|
||||
* Remove obsolete code (mostly Python 2 compatibility code)
|
||||
* Add support for PRO X Wireless Mouse, G914 TKL keyboard
|
||||
* Ignore more notifications that come to a device listener
|
||||
* Handle more device connection protocols
|
||||
* Update usage and rules documentation
|
||||
* Change emojis to text in documentation
|
||||
* Pare down device documentation so as not to require frequent updates
|
||||
* Add information about M500S mouse
|
||||
* Reimplement MOUSE GESTURE and DPI SLIDING settings
|
||||
* Add setting for DPI CHANGE button to switch sensitivity
|
||||
* Use file name instead of icon name for tray to avoid XFCE bug
|
||||
* Update documentation on implemented features and mouse gestures
|
||||
* Update Polish, Japanese, and Spanish translations
|
||||
* Make Quit and About strings more translatable
|
||||
|
||||
# 1.0.7
|
||||
|
||||
* Don't use time_ns so as not to require Python 3.7
|
||||
* Correctly determine setting box in change_click method
|
||||
* Handle fake Nano connection notifications
|
||||
* Lock on actual handle, not just on handle number
|
||||
* Mark Nano receiver C52F as not unpairing
|
||||
* Upgrade pairing/unpairing documentation
|
||||
* Don't signal status change when battery changes from None to None.
|
||||
* Add Japanese translation
|
||||
* Use first word of name for code name if no other code name available.
|
||||
* Better determination of when to add SW ID.
|
||||
* Check for more HID++ feature request failing.
|
||||
* Fix bug with new_fn_inversion setting.
|
||||
* Use correct device number for directly connected devices
|
||||
* Add debug message when candidate device found
|
||||
* Update Polish, Taiwanese, and Brazilian Portuguese translations
|
||||
* Add MouseProcess a rule condition like Process but for the window under the mouse
|
||||
* Add parameters for binary settings to support prefixes
|
||||
* Add locks to serialize requests to devices
|
||||
* Fix bug when reprog key requests returns None
|
||||
* Fix bug for empty process name and class
|
||||
* Rules can now trigger on both pressing and releasing a diverted key
|
||||
* Upgrade mouse gestures to allow sequences of movements
|
||||
* Fix gkeys diversion faked read
|
||||
* Add support for Logitech g pro x superlight receiver
|
||||
* Convert HID++ 2.0 device kinds to enhanced HID++ 1.0 device kinds
|
||||
* Update about window, bug report templates, and supported kernels.
|
||||
|
||||
# 1.0.6
|
||||
|
||||
* Update sliding DPI to look for suitable keys
|
||||
* Add mouse gestures that can trigger rules
|
||||
* Complain if receivers do not support connection notification
|
||||
* In polling rate setting, only modify onboard profiles when actually writing polling rate
|
||||
* Add ability to ignore settings.
|
||||
* Use symbols for receiver sub-registers
|
||||
* Add support for wired G700
|
||||
* Do not set attention icon
|
||||
* Replace deprecated GTK stock menu icons
|
||||
* Better handling of icons in tray and tray menus
|
||||
* Receiver c52e does not unpair
|
||||
* Match active WM_CLASS as well as active process name in rules
|
||||
* Correctly set icon theme value when regular battery icons are not available
|
||||
* Handle exception when device is not available when device is being added
|
||||
* Perform initial activation of devices in listener threads
|
||||
* Keep track of serial numbers in the configuration file
|
||||
* Don't update settings for non-active devices
|
||||
* Set the current host name if not stored on the device
|
||||
* Add setting for SMART SHIFT ENHANCED feature
|
||||
* Don't unnecessarily use long messages for HID++ 1.0 commands
|
||||
* Correctly select choices in solaar config and use 1-origin addressing
|
||||
* Add quirk for G915 TKL keyboard because its host mode interferes with its Fn keys
|
||||
* Show command outputs both saved and on-device settings
|
||||
* Update documentation
|
||||
* Fix bug in hidconsole
|
||||
* Update French translation
|
||||
|
||||
# 1.0.5
|
||||
|
||||
* Update documentation on devices forgetting settings.
|
||||
* Improve help messages
|
||||
* Fix bug in finding receiver to pair
|
||||
* Solaar config command can set keyed settings.
|
||||
* Add setting for polling rate
|
||||
* Use long HID++ messages for all 2.0 requests
|
||||
* Update German, Italian, and Polish translations
|
||||
* Solaar config command no longer selects paired but unconnected devices
|
||||
* Show HID++ 1.0 remaining pairings value in solaar show for devices that support it
|
||||
* Add option to not use battery icons in system tray.
|
||||
* Update Polish and Dutch translation.
|
||||
* Add Czech translation.
|
||||
* Remove information on SUSE package as it is very old.
|
||||
* Turn GKEY notifications into Gn key keypresses that can trigger rules.
|
||||
* Push device settings to devices after suspend when device is immediately active.
|
||||
* Reduce unnecessary saving of configuration file.
|
||||
* Better handling of disconnected devices.
|
||||
* Implement GUI to edit rules.
|
||||
* Implement rule-base processing of HID++ feature notifications (depends on X11).
|
||||
* Add settings for diversion of crown and remappable keys.
|
||||
* Access widgets by name instead of by index.
|
||||
* Implement UNIFIED_BATTERY feature and use in battery reports.
|
||||
* Add a clickable lock icon that determines where each setting can be changed.
|
||||
|
||||
# 1.0.4
|
||||
|
||||
* Update pt_BR translation
|
||||
* Support USB and BT connected devices that are not in descriptors.py
|
||||
* Use FRIENDLY NAME for codename if needed and available.
|
||||
* Extract manufacturer and product ID from Udev HID information.
|
||||
* Add Bluetooth and USB product IDs to device descriptors records.
|
||||
* Support Bluetooth-connected devices.
|
||||
* Add model ID and unit ID to device identification.
|
||||
* Support changing DPI by pressing DPI Switch button and sliding horizontally
|
||||
* Add device-specific notification handlers.
|
||||
* Add MX Vertical USB information.
|
||||
* Udev rule adds seat permissions for all Logitech devices.
|
||||
* Support USB-connected devices in GUI.
|
||||
* Make probe and config work for USB-connected devices.
|
||||
* Improve strings and display for settings.
|
||||
* Correctly handle non-unifying connection notifications.
|
||||
* Update GUI strings for several settings.
|
||||
* Better support for EX100 and devices that connect to it.
|
||||
* Partial support for feature GESTURE_2.
|
||||
* Simplify interface for settings.
|
||||
* Use DJ connection notifications to set device active status
|
||||
* Udev rule sets seat write permissions for hidraw nodes for device as well as receivers.
|
||||
* Handle USB devices that use HID++ protocol in CLI.
|
||||
* Use device hidraw nodes where possible.
|
||||
* Handle receivers with serial numbers that don't provide number of pairings.
|
||||
* Ignore exceptions when setting locale.
|
||||
* Correctly discover settings that share a name.
|
||||
* Don't show pop-up notifications at startup.
|
||||
* Keep battery voltage updated in GUI.
|
||||
* Add Portuguese translation.
|
||||
* Update several translations.
|
||||
* Add Lightspeed receivers c545 and c541.
|
||||
* Reimplement REPROG_CONTROLS data structure.
|
||||
|
||||
# 1.0.3
|
||||
|
||||
* Clean up documentation files.
|
||||
* Update documentation on installation.
|
||||
* Update Swedish and French translations.
|
||||
* Add Norwegian Nynorsk and Danish translations.
|
||||
* Fix bug handling DJ pairing notifications.
|
||||
* Add Norwegian Bokmål translation.
|
||||
* Remove deprecated solaar-cli application.
|
||||
* Don't install udev or autostart files from python (or pip).
|
||||
* Solaar needs Python 3.6+ and probably needs kernel 5.2+
|
||||
* Handle exceptions on dynamic settings when device is not connected.
|
||||
* Fix infinite loop on some low-level write errors
|
||||
* Add support for EX100 keyboard/mouse and receiver (046d:c517)
|
||||
* Add two settings for THUMB_WHEEL feature - inversion and reporting via HID++
|
||||
* Update German translation
|
||||
* Use REPORT RATE feature when available to determine polling rate.
|
||||
* Improve config command speed when not printing all settings
|
||||
* Improve config command handling and checking of arguments
|
||||
* Add setting for CHANGE_HOST feature
|
||||
* Add argument to settings for values that are not to persist
|
||||
* Add argument to settings to not wait for reply when writing a value to device
|
||||
* Add argument to not wait for reply from request to device
|
||||
* Add settings for MULTIPLATFORM and DUALPLATFORM features
|
||||
* Remove Logitech documents from documentation directory
|
||||
* Change config command to not read all settings when only printing or showing one
|
||||
* Display hosts info in 'solaar show' if device supports it
|
||||
* Remove non-working smooth-scroll from M510 v1
|
||||
* Add yapf and flake8 code style checks
|
||||
* Fix feature k375s Fn inversion
|
||||
* Update controls (keys and buttons) and tasks (actions)
|
||||
* Improved way to specify feature settings.
|
||||
* Don't abort on device notifications with unexpected device numbers, just warn.
|
||||
* Keep track of non-features so as not to ask device multiple times.
|
||||
* Implement KEYBOARD DISABLE KEYS feature.
|
||||
* Don't create notifications for DJ device activity reports.
|
||||
* Update a few special keys and actions.
|
||||
* Add keyed choice settings in configuration panel.
|
||||
* Support remappable keys from reprogrammable keys v4 feature.
|
||||
* Add setting class for keyed choice.
|
||||
* Only check for features once per device.
|
||||
* Use settings interface to show feature values in `solaar show` if no special code for feature.
|
||||
* Remove maximum window size.
|
||||
* Process battery voltage notifications.
|
||||
* Display battery voltage information in main window if regular battery information not available.
|
||||
* Show next battery level where available.
|
||||
* Update list of implemented features and provide information on how to implement features.
|
||||
* Add c53d as a Lightspeed receiver.
|
||||
|
||||
# 1.0.2
|
||||
|
||||
* Add usage document
|
||||
* Don't produce error dialog for inaccessible receivers with access control lists.
|
||||
* Add option --battery-icons=symbolic to use symbolic icons if available.
|
||||
* Update French translation
|
||||
* Update installation documentation
|
||||
* Remove packaging directory tree as it is not maintained
|
||||
* Pip installs udev rule and solaar autostart when doing install without --user flag
|
||||
* Use Solaar icon instead of a missing battery icon
|
||||
* Use only standard icons for battery levels. Symbolic icons do not change to white in dark themes because of problems external to Solaar.
|
||||
* Better reporting of battery levels when charging for some devices.
|
||||
* Add information on K600 TV, M350 WIPD 4080, and MX Keys
|
||||
* Remove assertion requiring receivers to still be in window when they are updated.
|
||||
* Augment long description of Solaar showing up in repositories.
|
||||
* Update installation directions.
|
||||
* Install udev rule as well as autostart file when doing system install.
|
||||
* Add support for Ayatana AppIndicator.
|
||||
* Use setuptools icon directory on system installs when not using pip.
|
||||
* Add receiver C517 and several older devices.
|
||||
* Improved translations for polish.
|
||||
* Bypass bug in appindicator when solaar is file in current directory.
|
||||
* Don't check that device kind matches feature kind.
|
||||
* Better determination of icons for battery levels.
|
||||
* Use Ayatana AppIndicator if available.
|
||||
* Improve error reporting when required system packages are not install.
|
||||
* Better tooltip description
|
||||
* Add release script to help when creating releases
|
||||
* Look up tray icon filenames to get around a bug in libappindicator.
|
||||
* Make the default behavior be to show the main window at startup.
|
||||
* Support c537 nano receiver
|
||||
* Add logind signals for suspend/resume.
|
||||
* Remove solaar-gnome3 package
|
||||
* Ignore features for devices that don't follow feature specification
|
||||
* Add probe command to command-line interface to dump receiver registers
|
||||
* Don't terminate on malformed or unknown messages
|
||||
* Create fewer internal notifications for messages from devices
|
||||
* Add a button to the main window to terminate (quit) Solaar
|
||||
* Set up nano receivers as receivers with no unpairing and with re-pairing
|
||||
* Set up c534 as receiver with max 2 pairings, no unpairing, re-pairing
|
||||
* Better support receivers that do not unpair or when pairing replace existing pairings
|
||||
* Add information about receiver pairing to receiver data structure
|
||||
* Better support devices that only allow a limited number of total re-pairings
|
||||
* Add --window option to control main window visibility and tray usage
|
||||
* Ignore receiver if USB id is not retrieved
|
||||
* Fix bug with double deleting when devices are disconnected
|
||||
* Determine some receiver information from data structure for USB ids
|
||||
* Treat battery level of 0 as unknown
|
||||
* Fix bug on devices with no serial number
|
||||
* Drop support for python2, and use python3 throughout
|
||||
* Fix bug in remembering features discovered from device reports
|
||||
* Show icons in main window device list
|
||||
* Count offline devices when determining whether pairing is possible
|
||||
* Update French, Dutch, German, and Croatian translations
|
||||
* Better icons for battery levels
|
||||
* Support DPI, Backlight 2, Battery Voltage features
|
||||
* Support M585, M590, M330, MX Master 2s and 3, new M310, new K800, craft keyboard
|
||||
* Documentation improvements
|
||||
* Clean up directory structure and remove unused files
|
||||
|
||||
# 1.0.1
|
||||
|
||||
* Updated the repo url.
|
||||
* Fixed typo which was crashing the application.
|
||||
* Improved the HID write routine which was causing issues on some devices.
|
||||
* Fix non-unifying receivers in Linux 5.2.
|
||||
* Add new Lightspeed receiver (used in the G305)
|
||||
|
||||
# 1.0.0
|
||||
|
||||
* Too many to track...
|
||||
|
||||
# 0.9.3
|
||||
|
||||
* Merged solaar-cli functionality into main solaar.
|
||||
* Scrolling over the systray icon switches between multiple peripherals.
|
||||
* Swedish translation courtesy of Daniel Zippert and Emelie Snecker
|
||||
* French translation courtesy of Papoteur, David Geiger and Damien Lallement.
|
||||
* Fixed some untranslated strings.
|
||||
|
||||
# 0.9.2
|
||||
|
||||
* Added support for hand detection on the K800.
|
||||
* Added support for V550 and V450 Nano.
|
||||
* Fixed side-scrolling with the M705 Marathon.
|
||||
* Fixed identification of the T650 Touchpad.
|
||||
* Added internationalization support and romanian translation.
|
||||
* Polish translation courtesy of Adrian Piotrowicz.
|
||||
|
||||
# 0.9.1
|
||||
|
||||
* When devices report a battery alert, only show the alert once.
|
||||
* Make sure devices in the window tree are sorted by registration index.
|
||||
* Added an autostart .desktop file.
|
||||
* Replaced single-instance code with GtkApplication.
|
||||
* Fixed identification of the M505 mouse.
|
||||
* Fixed an occasional windowing layout bug with the C52F Nano Receiver.
|
||||
|
||||
# 0.9.0
|
||||
|
||||
* New single-window UI.
|
||||
* Performance MX leds show the current battery charge.
|
||||
* Support the VX Nano mouse.
|
||||
* Faster and more accurate detection of devices.
|
||||
* If upower is accessible through DBus, handle suspend/resume.
|
||||
* Replaced Solaar icons with SVGs.
|
||||
* Running solaar-cli in parallel with solaar is now less likely to cause issues.
|
||||
* Bugfixes to saving and applying device settings.
|
||||
* Properly handle ^C when running in console.
|
||||
|
||||
# 0.8.9
|
||||
|
||||
* Improved support for gnome-shell/Unity.
|
||||
* Persist devices settings between runs.
|
||||
* Fixed reading of MK700 keyboard battery status.
|
||||
* Use battery icons from the current theme instead of custom ones.
|
||||
* Debian/Ubuntu packages now depend on an icon theme, to make sure
|
||||
no missing icons appear in the application window.
|
||||
* Fixed missing icons under Kubuntu.
|
||||
* Many more bug-fixes and reliability improvements.
|
||||
|
||||
# 0.8.8
|
||||
|
||||
* Partial support for some Nano receivers.
|
||||
* Improved support for some devices: M510, K800, Performance MX.
|
||||
* Improved battery support for some HID++ 1.0 devices.
|
||||
* Properly handle device loss on computer sleep/wake.
|
||||
* Better handling of receiver adding and removal at runtime.
|
||||
* Removed a few more unhelpful notifications.
|
||||
* Incipient support for multiple connected receivers.
|
||||
* More Python 3 fixes.
|
||||
|
||||
# 0.8.7
|
||||
|
||||
* Don't show the "device disconnected" notification, it can be annoying and
|
||||
not very useful.
|
||||
* More robust detection of systray icon visibility.
|
||||
|
||||
# 0.8.6
|
||||
|
||||
* Ensure the Gtk application is single-instance.
|
||||
* Fix identifying available dpi values.
|
||||
* Fixed locating application icons when installed in a custom prefix.
|
||||
* Fixed some icon names for the oxygen theme.
|
||||
* Python 3 fixes.
|
||||
3
MANIFEST.in
Normal file
@@ -0,0 +1,3 @@
|
||||
include COPYRIGHT COPYING README.md ChangeLog.md
|
||||
recursive-include rules.d *
|
||||
recursive-include share/locale *
|
||||
60
README
@@ -1,60 +0,0 @@
|
||||
Solaar
|
||||
------
|
||||
|
||||
|
||||
This application connects to a Logitech Unifying Receiver
|
||||
(http://www.logitech.com/en-us/66/6079) and listens for events from devices
|
||||
attached to it.
|
||||
|
||||
Currently the K750 solar keyboard is also queried for its solar charge status.
|
||||
Support for other devices could be added in the future, but the K750 keyboard is
|
||||
the only device I have and can test on.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
- Python (2.7 or 3.2). Either version should work well.
|
||||
- Gtk 3; Gtk 2 should partially work with some problems.
|
||||
- Python GI (GObject Introspection), for Gtk bindings.
|
||||
- pyudev for enumerating udev devices.
|
||||
- Optional libnotify GI bindings, for desktop notifications.
|
||||
|
||||
The necessary packages for Debian/Ubuntu are `python-pyudev`/`python3-pyudev`,
|
||||
`python-gi`/`python3-gi`, `gir1.2-gtk-3.0`, and optionally `gir1.2-notify-0.7`.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Normally USB devices are not accessible for r/w by regular users, so you will
|
||||
need to install a udev rule to allow access to the Logitech Unifying Receiver.
|
||||
|
||||
In rules.d/ you'll find a udev rule file, to be copied in /etc/udev/rules.d/ (as
|
||||
root).
|
||||
|
||||
In its current form it makes the UR 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.
|
||||
|
||||
After you copy the file to /etc/udev/rules.d (and possibly modify it for your
|
||||
system), run 'udevadm control --reload-rules' as root for it to apply. Then
|
||||
physically remove the Unifying Receiver, wait 30 seconds and re-insert it.
|
||||
|
||||
|
||||
Thanks
|
||||
------
|
||||
|
||||
This project began as a third-hand clone of Noah K. Tilton's logitech-solar-k750
|
||||
project on GitHub (no longer available). It was developed further thanks to the
|
||||
diggings in Logitech's HID protocol done, among others, by Julien Danjou
|
||||
(http://julien.danjou.info/blog/2012/logitech-k750-linux-support) and
|
||||
Lars-Dominik Braun (http://6xq.net/git/lars/lshidpp.git).
|
||||
|
||||
|
||||
Cheers,
|
||||
-pwr
|
||||
16
RELEASE.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# 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.md, 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 github token with `public_repo` access
|
||||
in `~/.github-token`
|
||||
77
Release_Notes.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Notes on Major Changes in Releases
|
||||
|
||||
## Version 1.1.2
|
||||
|
||||
* Rules partly work under Wayland. There is no access to the current process in Wayland. Simulated input uses uinput if XTest extension not available, requiring read and write permissions on /dev/uinput.
|
||||
|
||||
* There is a setting to divert gestures so that they can trigger rules.
|
||||
|
||||
* There is a setting to disable Onboard Profiles, which can interfere with the Polling Rate and M-Key LEDs settings. The Polling Rate setting no longer disables onboard profiles.
|
||||
|
||||
* There is a setting for the Persistent Remappable Keys feature.
|
||||
|
||||
* There is a new rule condition that tests device settings.
|
||||
|
||||
* There are new settings to set M-Key LEDs and MR-Key LED.
|
||||
|
||||
* There is a new kind of Solaar rule action to change settings for devices.
|
||||
|
||||
## Version 1.1.1
|
||||
|
||||
* There is a new setting to switch keyboard crowns between smooth and ratchet scrolling.
|
||||
|
||||
## Version 1.1.0
|
||||
|
||||
* Solaar now supports Bolt receivers and devices that connect to them, including authentication of devices when pairing.
|
||||
|
||||
* A setting has been added for the DPI CHANGE button to switch movement sensitivity.
|
||||
|
||||
## Version 1.0.7
|
||||
|
||||
* Solaar rules can now trigger on both pressing and releasing a diverted key.
|
||||
|
||||
* The new rule condition MouseProcess is like the Process condition except for the process of the window under the mouse.
|
||||
|
||||
* Mouse gestures have been upgraded. A mouse gesture is now a sequence of movements separated by no movement periods while the mouse gesture button is held down. The MouseGesture rule condition matches mouse gesture sequences. The old mouse-up, etc., tests are converted to MouseGesture conditions.
|
||||
|
||||
## Version 1.0.6
|
||||
|
||||
* The sliding DPI setting now looks for suitable keys to use to trigger its effects.
|
||||
|
||||
* If a mouse has a suitable button it can generate mouse gestures, which trigger rule processing. Mouse gestures need to be turned on and the button diverted to produce mouse gestures.
|
||||
|
||||
* Settings can now be ignored by clicking on the icon at the right-hand edge of a setting until the dialog error icon (usually a red icon) appears. Solaar will not try to restore the value for an ignored setting.
|
||||
|
||||
* Icon handling in the tray and the tray menu has been updated to work better with some system tray implementations.
|
||||
|
||||
* The process rule condition also matches against the current X11 WM_CLASS.
|
||||
|
||||
* The SMART SHIFT ENHANCED feature is supported.
|
||||
|
||||
## Version 1.0.5
|
||||
|
||||
* Solaar has rules that can perform actions such as pressing keys or scrolling when certain HID++ feature notifications happen. Users can change these rules either by editing ~/.config/solaar/rules.yaml or via a GUI. Rules depend on X11 and so are only available under X11. This is an experimental feature for Solaar and may undergo changes in the future.
|
||||
|
||||
* Each setting has a clickable lock icon that determines whether the setting can be changed.
|
||||
|
||||
## Version 1.0.4
|
||||
|
||||
* Devices that connect directly via Bluetooth or USB are now supported. These devices show up in the GUI as separate lines, not under a receiver. A device that is directly connected and also paired to a receiver will show up twice, but the entry under the receiver will not be active. With this change identifying devices becomes more difficult so occasionally check your Solaar configuration file (at ~/.config/solaar/config.json) to see that there is only one entry for each of your devices.
|
||||
|
||||
* There are new settings for gestures, thumb wheels, adjusting the wheel ratchet behavior, and changing DPI using a DPI Switch button.
|
||||
|
||||
* Solaar's Udev rule now adds seat permissions for all Logitech devices. Users who install Solaar themselves will have to install the new Udev rule and activate the rule. One way to do this is to restart the user's computer.
|
||||
|
||||
## Version 1.0.3
|
||||
|
||||
* The separate deprecated solaar-cli command has been removed.
|
||||
|
||||
* Devices can be switched between hosts using the Change Host setting. The device will try to connect to the other host. Some devices will detect that there is no active host on the other connections and reconnect back.
|
||||
|
||||
## Version 1.0.2
|
||||
|
||||
* The separate unneeded solaar-gnome3 command has been removed. The packaging directories have been removed.
|
||||
|
||||
* Non-unifying receivers are modelled better. Many of them cannot unpair but instead new pairings replace existing pairings.
|
||||
|
||||
* Battery icon selection has been simplified.
|
||||
@@ -1,82 +0,0 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
from logging import getLogger as _Logger
|
||||
_l = _Logger('pairing')
|
||||
|
||||
from logitech.unifying_receiver import base as _base
|
||||
|
||||
state = None
|
||||
|
||||
class State(object):
|
||||
TICK = 400
|
||||
PAIR_TIMEOUT = 60 * 1000 / TICK
|
||||
|
||||
def __init__(self, listener):
|
||||
self.listener = listener
|
||||
self.reset()
|
||||
|
||||
def device(self, number):
|
||||
return self.listener.devices.get(number)
|
||||
|
||||
def reset(self):
|
||||
self.success = None
|
||||
self.detected_device = None
|
||||
self._countdown = self.PAIR_TIMEOUT
|
||||
|
||||
def countdown(self, assistant):
|
||||
if self._countdown < 0 or not self.listener:
|
||||
return False
|
||||
|
||||
if self._countdown == self.PAIR_TIMEOUT:
|
||||
self.start_scan()
|
||||
self._countdown -= 1
|
||||
return True
|
||||
|
||||
self._countdown -= 1
|
||||
if self._countdown > 0 and self.success is None:
|
||||
return True
|
||||
|
||||
self.stop_scan()
|
||||
assistant.scan_complete(assistant, self.detected_device)
|
||||
return False
|
||||
|
||||
def start_scan(self):
|
||||
self.reset()
|
||||
self.listener.events_filter = self.filter_events
|
||||
reply = _base.request(self.listener.handle, 0xFF, b'\x80\xB2', b'\x01')
|
||||
_l.debug("start scan reply %s", repr(reply))
|
||||
|
||||
def stop_scan(self):
|
||||
if self._countdown >= 0:
|
||||
self._countdown = -1
|
||||
reply = _base.request(self.listener.handle, 0xFF, b'\x80\xB2', b'\x02')
|
||||
_l.debug("stop scan reply %s", repr(reply))
|
||||
self.listener.events_filter = None
|
||||
|
||||
def filter_events(self, event):
|
||||
if event.devnumber == 0xFF:
|
||||
if event.code == 0x10:
|
||||
if event.data == b'\x4A\x01\x00\x00\x00':
|
||||
_l.debug("receiver listening for device wakeup")
|
||||
return True
|
||||
if event.data == b'\x4A\x00\x01\x00\x00':
|
||||
_l.debug("receiver gave up")
|
||||
self.success = False
|
||||
return True
|
||||
return False
|
||||
|
||||
if event.devnumber in self.listener.receiver.devices:
|
||||
return False
|
||||
|
||||
_l.debug("event for new device? %s", event)
|
||||
if event.code == 0x10 and event.data[0:2] == b'\x41\x04':
|
||||
self.detected_device = self.listener.make_device(event)
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
def unpair(self, device):
|
||||
_l.debug("unpair %s", device)
|
||||
self.listener.unpair_device(device)
|
||||
340
app/receiver.py
@@ -1,340 +0,0 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
from logging import getLogger as _Logger
|
||||
from struct import pack as _pack
|
||||
from time import sleep as _sleep
|
||||
|
||||
from logitech.unifying_receiver import base as _base
|
||||
from logitech.unifying_receiver import api as _api
|
||||
from logitech.unifying_receiver.listener import EventsListener as _EventsListener
|
||||
from logitech.unifying_receiver.common import FallbackDict as _FallbackDict
|
||||
from logitech import devices as _devices
|
||||
from logitech.devices.constants import (STATUS, STATUS_NAME, PROPS)
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
class _FeaturesArray(object):
|
||||
__slots__ = ('device', 'features', 'supported')
|
||||
|
||||
def __init__(self, device):
|
||||
self.device = device
|
||||
self.features = None
|
||||
self.supported = True
|
||||
|
||||
def _check(self):
|
||||
if self.supported:
|
||||
if self.features is not None:
|
||||
return True
|
||||
|
||||
if self.device.status >= STATUS.CONNECTED:
|
||||
handle = self.device.handle
|
||||
try:
|
||||
index = _api.get_feature_index(handle, self.device.number, _api.FEATURE.FEATURE_SET)
|
||||
except _api._FeatureNotSupported:
|
||||
self.supported = False
|
||||
else:
|
||||
count = None if index is None else _base.request(handle, self.device.number, _pack('!BB', index, 0x00))
|
||||
if count is None:
|
||||
self.supported = False
|
||||
else:
|
||||
count = ord(count[:1])
|
||||
self.features = [None] * (1 + count)
|
||||
self.features[0] = _api.FEATURE.ROOT
|
||||
self.features[index] = _api.FEATURE.FEATURE_SET
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
__bool__ = __nonzero__ = _check
|
||||
|
||||
def __getitem__(self, index):
|
||||
if not self._check():
|
||||
return None
|
||||
|
||||
if index < 0 or index >= len(self.features):
|
||||
raise IndexError
|
||||
if self.features[index] is None:
|
||||
fs_index = self.features.index(_api.FEATURE.FEATURE_SET)
|
||||
feature = _base.request(self.device.handle, self.device.number, _pack('!BB', fs_index, 0x10), _pack('!B', index))
|
||||
if feature is not None:
|
||||
self.features[index] = feature[:2]
|
||||
|
||||
return self.features[index]
|
||||
|
||||
def __contains__(self, value):
|
||||
if self._check():
|
||||
if value in self.features:
|
||||
return True
|
||||
|
||||
for index in range(0, len(self.features)):
|
||||
f = self.features[index] or self.__getitem__(index)
|
||||
assert f is not None
|
||||
if f == value:
|
||||
return True
|
||||
if f > value:
|
||||
break
|
||||
|
||||
return False
|
||||
|
||||
def index(self, value):
|
||||
if self._check():
|
||||
if self.features is not None and value in self.features:
|
||||
return self.features.index(value)
|
||||
raise ValueError("%s not in list" % repr(value))
|
||||
|
||||
def __iter__(self):
|
||||
if self._check():
|
||||
yield _api.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 DeviceInfo(_api.PairedDevice):
|
||||
"""A device attached to the receiver.
|
||||
"""
|
||||
def __init__(self, listener, number, status=STATUS.UNKNOWN):
|
||||
super(DeviceInfo, self).__init__(listener.handle, number)
|
||||
self._features = _FeaturesArray(self)
|
||||
|
||||
self.LOG = _Logger("Device[%d]" % number)
|
||||
self._listener = listener
|
||||
|
||||
self._status = status
|
||||
self.props = {}
|
||||
|
||||
# read them now, otherwise it it temporarily hang the UI
|
||||
# if status >= STATUS.CONNECTED:
|
||||
# n, k, s, f = self.name, self.kind, self.serial, self.firmware
|
||||
|
||||
@property
|
||||
def receiver(self):
|
||||
return self._listener.receiver
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
return self._status
|
||||
|
||||
@status.setter
|
||||
def status(self, new_status):
|
||||
if new_status != self._status and not (new_status == STATUS.CONNECTED and self._status > new_status):
|
||||
self.LOG.debug("status %d => %d", self._status, new_status)
|
||||
urgent = new_status < STATUS.CONNECTED or self._status < STATUS.CONNECTED
|
||||
self._status = new_status
|
||||
self._listener.status_changed(self, urgent)
|
||||
|
||||
if new_status < STATUS.CONNECTED:
|
||||
self.props.clear()
|
||||
|
||||
@property
|
||||
def status_text(self):
|
||||
if self._status < STATUS.CONNECTED:
|
||||
return STATUS_NAME[self._status]
|
||||
|
||||
t = []
|
||||
if self.props.get(PROPS.BATTERY_LEVEL):
|
||||
t.append('Battery: %d%%' % self.props[PROPS.BATTERY_LEVEL])
|
||||
if self.props.get(PROPS.BATTERY_STATUS):
|
||||
t.append(self.props[PROPS.BATTERY_STATUS])
|
||||
if self.props.get(PROPS.LIGHT_LEVEL):
|
||||
t.append('Light: %d lux' % self.props[PROPS.LIGHT_LEVEL])
|
||||
return ', '.join(t) if t else STATUS_NAME[STATUS.CONNECTED]
|
||||
|
||||
def process_event(self, code, data):
|
||||
if code == 0x10 and data[:1] == b'\x8F':
|
||||
self.status = STATUS.UNAVAILABLE
|
||||
return True
|
||||
|
||||
if code == 0x11:
|
||||
status = _devices.process_event(self, data)
|
||||
if status:
|
||||
if type(status) == int:
|
||||
self.status = status
|
||||
return True
|
||||
|
||||
if type(status) == tuple:
|
||||
p = dict(self.props)
|
||||
self.props.update(status[1])
|
||||
if self.status == status[0]:
|
||||
if p != self.props:
|
||||
self._listener.status_changed(self)
|
||||
else:
|
||||
self.status = status[0]
|
||||
return True
|
||||
|
||||
self.LOG.warn("don't know how to handle processed event status %s", status)
|
||||
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return '<DeviceInfo(%d,%s,%d)>' % (self.number, self._name or '?', self._status)
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
_RECEIVER_STATUS_NAME = _FallbackDict(
|
||||
lambda x:
|
||||
'1 device found' if x == STATUS.CONNECTED + 1 else
|
||||
'%d devices found' if x > STATUS.CONNECTED else
|
||||
'?',
|
||||
{
|
||||
STATUS.UNKNOWN: 'Initializing...',
|
||||
STATUS.UNAVAILABLE: 'Receiver not found.',
|
||||
STATUS.BOOTING: 'Scanning...',
|
||||
STATUS.CONNECTED: 'No devices found.',
|
||||
}
|
||||
)
|
||||
|
||||
class ReceiverListener(_EventsListener):
|
||||
"""Keeps the status of a Unifying Receiver.
|
||||
"""
|
||||
|
||||
def __init__(self, receiver, status_changed_callback=None):
|
||||
super(ReceiverListener, self).__init__(receiver.handle, self._events_handler)
|
||||
self.receiver = receiver
|
||||
|
||||
self.LOG = _Logger("ReceiverListener(%s)" % receiver.path)
|
||||
|
||||
self.events_filter = None
|
||||
self.events_handler = None
|
||||
|
||||
self.status_changed_callback = status_changed_callback
|
||||
|
||||
receiver.kind = receiver.name
|
||||
receiver.devices = {}
|
||||
receiver.status = STATUS.BOOTING
|
||||
receiver.status_text = _RECEIVER_STATUS_NAME[STATUS.BOOTING]
|
||||
|
||||
if _base.request(receiver.handle, 0xFF, b'\x80\x00', b'\x00\x01'):
|
||||
self.LOG.info("initialized")
|
||||
else:
|
||||
self.LOG.warn("initialization failed")
|
||||
|
||||
if _base.request(receiver.handle, 0xFF, b'\x80\x02', b'\x02'):
|
||||
self.LOG.info("triggered device events")
|
||||
else:
|
||||
self.LOG.warn("failed to trigger device events")
|
||||
|
||||
def change_status(self, new_status):
|
||||
if new_status != self.receiver.status:
|
||||
self.LOG.debug("status %d => %d", self.receiver.status, new_status)
|
||||
self.receiver.status = new_status
|
||||
self.receiver.status_text = _RECEIVER_STATUS_NAME[new_status]
|
||||
self.status_changed(None, True)
|
||||
|
||||
def status_changed(self, device=None, urgent=False):
|
||||
if self.status_changed_callback:
|
||||
self.status_changed_callback(self.receiver, device, urgent)
|
||||
|
||||
def _device_status_from(self, event):
|
||||
state_code = ord(event.data[2:3]) & 0xC0
|
||||
state = STATUS.UNAVAILABLE if state_code == 0x40 else \
|
||||
STATUS.CONNECTED if state_code == 0x80 else \
|
||||
STATUS.CONNECTED if state_code == 0x00 else \
|
||||
None
|
||||
if state is None:
|
||||
self.LOG.warn("don't know how to handle state code 0x%02X: %s", state_code, event)
|
||||
return state
|
||||
|
||||
def _events_handler(self, event):
|
||||
if self.events_filter and self.events_filter(event):
|
||||
return
|
||||
|
||||
if event.code == 0x10 and event.data[0:2] == b'\x41\x04':
|
||||
|
||||
if event.devnumber in self.receiver.devices:
|
||||
status = self._device_status_from(event)
|
||||
if status is not None:
|
||||
self.receiver.devices[event.devnumber].status = status
|
||||
else:
|
||||
dev = self.make_device(event)
|
||||
if dev is None:
|
||||
self.LOG.warn("failed to make new device from %s", event)
|
||||
else:
|
||||
self.receiver.devices[event.devnumber] = dev
|
||||
self.change_status(STATUS.CONNECTED + len(self.receiver.devices))
|
||||
return
|
||||
|
||||
if event.devnumber == 0xFF:
|
||||
if event.code == 0xFF and event.data is None:
|
||||
# receiver disconnected
|
||||
self.LOG.warn("disconnected")
|
||||
self.receiver.devices = {}
|
||||
self.change_status(STATUS.UNAVAILABLE)
|
||||
return
|
||||
elif event.devnumber in self.receiver.devices:
|
||||
dev = self.receiver.devices[event.devnumber]
|
||||
if dev.process_event(event.code, event.data):
|
||||
return
|
||||
|
||||
if self.events_handler and self.events_handler(event):
|
||||
return
|
||||
|
||||
self.LOG.warn("don't know how to handle event %s", event)
|
||||
|
||||
def make_device(self, event):
|
||||
if event.devnumber < 1 or event.devnumber > self.receiver.max_devices:
|
||||
self.LOG.warn("got event for invalid device number %d: %s", event.devnumber, event)
|
||||
return None
|
||||
|
||||
status = self._device_status_from(event)
|
||||
if status is not None:
|
||||
dev = DeviceInfo(self, event.devnumber, status)
|
||||
self.LOG.info("new device %s", dev)
|
||||
self.status_changed(dev, True)
|
||||
return dev
|
||||
|
||||
self.LOG.error("failed to identify status of device %d from %s", event.devnumber, event)
|
||||
|
||||
def unpair_device(self, device):
|
||||
try:
|
||||
del self.receiver[device.number]
|
||||
except IndexError:
|
||||
self.LOG.error("failed to unpair device %s", device)
|
||||
return False
|
||||
|
||||
del self.receiver.devices[device.number]
|
||||
self.LOG.info("unpaired device %s", device)
|
||||
self.change_status(STATUS.CONNECTED + len(self.receiver.devices))
|
||||
device.status = STATUS.UNPAIRED
|
||||
return True
|
||||
|
||||
def __str__(self):
|
||||
return '<ReceiverListener(%s,%d)>' % (self.receiver.path, self.receiver.status)
|
||||
|
||||
@classmethod
|
||||
def open(self, status_changed_callback=None):
|
||||
receiver = _api.Receiver.open()
|
||||
if receiver:
|
||||
rl = ReceiverListener(receiver, status_changed_callback)
|
||||
rl.start()
|
||||
while not rl._active:
|
||||
_sleep(0.1)
|
||||
return rl
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
class _DUMMY_RECEIVER(object):
|
||||
__slots__ = ['name', 'max_devices', 'status', 'status_text', 'devices']
|
||||
name = kind = _api.Receiver.name
|
||||
max_devices = _api.Receiver.max_devices
|
||||
status = STATUS.UNAVAILABLE
|
||||
status_text = _RECEIVER_STATUS_NAME[STATUS.UNAVAILABLE]
|
||||
devices = {}
|
||||
__bool__ = __nonzero__ = lambda self: False
|
||||
DUMMY = _DUMMY_RECEIVER()
|
||||
127
app/solaar.py
@@ -1,127 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
NAME = 'Solaar'
|
||||
VERSION = '0.7.2'
|
||||
__author__ = "Daniel Pavel <daniel.pavel@gmail.com>"
|
||||
__version__ = VERSION
|
||||
__license__ = "GPL"
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
def _parse_arguments():
|
||||
import argparse
|
||||
arg_parser = argparse.ArgumentParser(prog=NAME.lower())
|
||||
arg_parser.add_argument('-v', '--verbose',
|
||||
action='count', default=0,
|
||||
help='increase the logger verbosity (may be repeated)')
|
||||
arg_parser.add_argument('-S', '--no-systray',
|
||||
action='store_false',
|
||||
dest='systray',
|
||||
help='don\'t embed the application window into the 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('-V', '--version',
|
||||
action='version',
|
||||
version='%(prog)s ' + __version__)
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
import logging
|
||||
log_level = logging.WARNING - 10 * args.verbose
|
||||
log_format='%(asctime)s %(levelname)8s [%(threadName)s] %(name)s: %(message)s'
|
||||
logging.basicConfig(level=max(log_level, logging.DEBUG), format=log_format)
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def _check_requirements():
|
||||
try:
|
||||
import pyudev
|
||||
except ImportError:
|
||||
return 'python-pyudev'
|
||||
|
||||
try:
|
||||
import gi.repository
|
||||
except ImportError:
|
||||
return 'python-gi'
|
||||
|
||||
try:
|
||||
from gi.repository import Gtk
|
||||
except ImportError:
|
||||
return 'gir1.2-gtk-3.0'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = _parse_arguments()
|
||||
|
||||
req_fail = _check_requirements()
|
||||
if req_fail:
|
||||
raise ImportError('missing required package: %s' % req_fail)
|
||||
|
||||
import ui
|
||||
|
||||
# check if the notifications are available and enabled
|
||||
args.notifications &= args.systray
|
||||
if ui.notify.available and ui.notify.init(NAME):
|
||||
ui.action.toggle_notifications.set_active(args.notifications)
|
||||
else:
|
||||
ui.action.toggle_notifications = None
|
||||
|
||||
from receiver 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
|
||||
window.present()
|
||||
|
||||
import pairing
|
||||
from gi.repository import Gtk, GObject
|
||||
|
||||
listener = None
|
||||
notify_missing = True
|
||||
|
||||
def status_changed(receiver, device=None, urgent=False):
|
||||
ui.update(receiver, icon, window, device)
|
||||
if ui.notify.available and urgent:
|
||||
GObject.idle_add(ui.notify.show, device or receiver)
|
||||
|
||||
global listener
|
||||
if not listener:
|
||||
GObject.timeout_add(5000, check_for_listener)
|
||||
listener = None
|
||||
|
||||
from receiver import ReceiverListener
|
||||
def check_for_listener(retry=True):
|
||||
global listener, notify_missing
|
||||
|
||||
if listener is None:
|
||||
try:
|
||||
listener = ReceiverListener.open(status_changed)
|
||||
except OSError:
|
||||
ui.show_permissions_warning(window)
|
||||
|
||||
if listener is None:
|
||||
pairing.state = None
|
||||
if notify_missing:
|
||||
status_changed(DUMMY, None, True)
|
||||
notify_missing = False
|
||||
return retry
|
||||
|
||||
# print ("opened receiver", listener, listener.receiver)
|
||||
notify_missing = True
|
||||
pairing.state = pairing.State(listener)
|
||||
status_changed(listener.receiver, None, True)
|
||||
|
||||
GObject.timeout_add(100, check_for_listener, False)
|
||||
Gtk.main()
|
||||
|
||||
if listener is not None:
|
||||
listener.stop()
|
||||
|
||||
ui.notify.uninit()
|
||||
@@ -1,70 +0,0 @@
|
||||
# pass
|
||||
|
||||
from . import (notify, status_icon, main_window, pair_window, action)
|
||||
|
||||
from gi.repository import (GObject, Gtk)
|
||||
GObject.threads_init()
|
||||
|
||||
|
||||
from solaar import NAME as _NAME
|
||||
_APP_ICONS = (_NAME + '-fail', _NAME + '-init', _NAME)
|
||||
def appicon(receiver_status):
|
||||
return (_APP_ICONS[0] if receiver_status < 0 else
|
||||
_APP_ICONS[1] if receiver_status < 1 else
|
||||
_APP_ICONS[2])
|
||||
|
||||
|
||||
_ICON_THEME = Gtk.IconTheme.get_default()
|
||||
|
||||
def get_icon(name, fallback):
|
||||
return name if name and _ICON_THEME.has_icon(name) else fallback
|
||||
|
||||
def icon_file(name):
|
||||
if name and _ICON_THEME.has_icon(name):
|
||||
return _ICON_THEME.lookup_icon(name, 0, 0).get_filename()
|
||||
return None
|
||||
|
||||
|
||||
def show_permissions_warning(window):
|
||||
text = ('Found a possible Unifying Receiver device,\n'
|
||||
'but did not have permission to open it.')
|
||||
|
||||
m = Gtk.MessageDialog(window, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, text)
|
||||
m.set_title('Permissions error')
|
||||
m.run()
|
||||
m.destroy()
|
||||
|
||||
|
||||
def find_children(container, *child_names):
|
||||
assert container is not None
|
||||
|
||||
def _iterate_children(widget, names, result, count):
|
||||
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:
|
||||
count = _iterate_children(w, names, result, count)
|
||||
if count == 0:
|
||||
break
|
||||
|
||||
return count
|
||||
|
||||
names = list(child_names)
|
||||
count = len(names)
|
||||
result = [None] * count
|
||||
_iterate_children(container, names, result, count)
|
||||
return tuple(result) if count > 1 else result[0]
|
||||
|
||||
|
||||
def update(receiver, icon, window, reason):
|
||||
assert receiver is not None
|
||||
assert reason is not None
|
||||
if window:
|
||||
GObject.idle_add(main_window.update, window, receiver, reason)
|
||||
if icon:
|
||||
GObject.idle_add(status_icon.update, icon, receiver)
|
||||
@@ -1,91 +0,0 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
# from sys import version as PYTTHON_VERSION
|
||||
from gi.repository import Gtk
|
||||
|
||||
import ui.notify
|
||||
import ui.pair_window
|
||||
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_license_type(Gtk.License.GPL_2_0)
|
||||
about.set_authors(('Daniel Pavel http://github.com/pwr', ))
|
||||
about.set_website('http://github.com/pwr/Solaar/wiki')
|
||||
about.set_website_label('Solaar Wiki')
|
||||
# about.set_comments('Using Python %s\n' % PYTTHON_VERSION.split(' ')[0])
|
||||
about.run()
|
||||
about.destroy()
|
||||
about = _action('help-about', 'About ' + _NAME, _show_about_window)
|
||||
|
||||
quit = _action('exit', 'Quit', Gtk.main_quit)
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
import pairing
|
||||
|
||||
def _pair_device(action, frame):
|
||||
window = frame.get_toplevel()
|
||||
|
||||
pair_dialog = ui.pair_window.create( action, pairing.state)
|
||||
pair_dialog.set_transient_for(window)
|
||||
pair_dialog.set_modal(True)
|
||||
|
||||
window.present()
|
||||
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.YES_NO,
|
||||
"Unpair device\n%s ?" % device.name)
|
||||
choice = qdialog.run()
|
||||
qdialog.destroy()
|
||||
if choice == Gtk.ResponseType.YES:
|
||||
pairing.state.unpair(device)
|
||||
|
||||
def unpair(frame):
|
||||
return _action('remove', 'Unpair', _unpair_device, frame)
|
||||
@@ -1,304 +0,0 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
from gi.repository import (Gtk, Gdk)
|
||||
|
||||
import ui
|
||||
from logitech.devices.constants import (STATUS, PROPS)
|
||||
|
||||
|
||||
_SMALL_DEVICE_ICON_SIZE = Gtk.IconSize.BUTTON
|
||||
_DEVICE_ICON_SIZE = Gtk.IconSize.DIALOG
|
||||
_STATUS_ICON_SIZE = Gtk.IconSize.LARGE_TOOLBAR
|
||||
_PLACEHOLDER = '~'
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
def _info_text(dev):
|
||||
fw_text = '\n'.join(['%-12s\t<tt>%s%s%s</tt>' %
|
||||
(f.kind, f.name, ' ' if f.name else '', f.version) for f in dev.firmware])
|
||||
return ('<small>'
|
||||
'Serial \t\t<tt>%s</tt>\n'
|
||||
'HID protocol\t<tt>%1.1f</tt>\n'
|
||||
'%s'
|
||||
'</small>' % (dev.serial, dev.protocol, fw_text))
|
||||
|
||||
def _toggle_info(action, label_widget, box_widget, frame):
|
||||
if action.get_active():
|
||||
box_widget.set_visible(True)
|
||||
if not label_widget.get_text():
|
||||
label_widget.set_markup(_info_text(frame._device))
|
||||
else:
|
||||
box_widget.set_visible(False)
|
||||
|
||||
|
||||
def _make_receiver_box(name):
|
||||
frame = Gtk.Frame()
|
||||
frame._device = None
|
||||
frame.set_name(name)
|
||||
|
||||
icon_name = ui.get_icon(name, 'preferences-desktop-peripherals')
|
||||
icon = Gtk.Image.new_from_icon_name(icon_name, _SMALL_DEVICE_ICON_SIZE)
|
||||
|
||||
label = Gtk.Label('Scanning...')
|
||||
label.set_name('label')
|
||||
label.set_alignment(0, 0.5)
|
||||
|
||||
toolbar = Gtk.Toolbar()
|
||||
toolbar.set_name('toolbar')
|
||||
toolbar.set_style(Gtk.ToolbarStyle.ICONS)
|
||||
toolbar.set_icon_size(Gtk.IconSize.MENU)
|
||||
toolbar.set_show_arrow(False)
|
||||
|
||||
hbox = Gtk.HBox(homogeneous=False, spacing=8)
|
||||
hbox.pack_start(icon, False, False, 0)
|
||||
hbox.pack_start(label, True, True, 0)
|
||||
hbox.pack_end(toolbar, False, False, 0)
|
||||
|
||||
info_label = Gtk.Label()
|
||||
info_label.set_name('info-label')
|
||||
info_label.set_alignment(0, 0.5)
|
||||
info_label.set_padding(8, 2)
|
||||
info_label.set_selectable(True)
|
||||
|
||||
info_box = Gtk.Frame()
|
||||
info_box.add(info_label)
|
||||
info_box.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
|
||||
|
||||
toggle_info_action = ui.action._toggle_action('info', 'Receiver info', _toggle_info, info_label, info_box, frame)
|
||||
toolbar.insert(toggle_info_action.create_tool_item(), 0)
|
||||
toolbar.insert(ui.action.pair(frame).create_tool_item(), -1)
|
||||
|
||||
vbox = Gtk.VBox(homogeneous=False, spacing=2)
|
||||
vbox.set_border_width(4)
|
||||
vbox.pack_start(hbox, True, True, 0)
|
||||
vbox.pack_start(info_box, True, True, 0)
|
||||
|
||||
frame.add(vbox)
|
||||
frame.show_all()
|
||||
info_box.set_visible(False)
|
||||
return frame
|
||||
|
||||
|
||||
def _make_device_box(index):
|
||||
frame = Gtk.Frame()
|
||||
frame._device = None
|
||||
frame.set_name(_PLACEHOLDER)
|
||||
|
||||
icon_name = 'preferences-desktop-peripherals'
|
||||
icon = Gtk.Image.new_from_icon_name(icon_name, _DEVICE_ICON_SIZE)
|
||||
icon.set_name('icon')
|
||||
icon.set_alignment(0.5, 0)
|
||||
|
||||
label = Gtk.Label('Initializing...')
|
||||
label.set_name('label')
|
||||
label.set_alignment(0, 0.5)
|
||||
label.set_padding(4, 4)
|
||||
|
||||
battery_icon = Gtk.Image.new_from_icon_name('battery_unknown', _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)
|
||||
|
||||
toolbar = Gtk.Toolbar()
|
||||
toolbar.set_name('toolbar')
|
||||
toolbar.set_style(Gtk.ToolbarStyle.ICONS)
|
||||
toolbar.set_icon_size(Gtk.IconSize.MENU)
|
||||
toolbar.set_show_arrow(False)
|
||||
|
||||
status_box = Gtk.HBox(homogeneous=False, spacing=0)
|
||||
status_box.set_name('status')
|
||||
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)
|
||||
|
||||
info_label = Gtk.Label()
|
||||
info_label.set_name('info-label')
|
||||
info_label.set_alignment(0, 0.5)
|
||||
info_label.set_padding(8, 2)
|
||||
info_label.set_selectable(True)
|
||||
|
||||
info_box = Gtk.Frame()
|
||||
info_box.add(info_label)
|
||||
|
||||
toggle_info_action = ui.action._toggle_action('info', 'Device info', _toggle_info, info_label, info_box, frame)
|
||||
toolbar.insert(toggle_info_action.create_tool_item(), 0)
|
||||
toolbar.insert(ui.action.unpair(frame).create_tool_item(), -1)
|
||||
|
||||
vbox = Gtk.VBox(homogeneous=False, spacing=4)
|
||||
vbox.pack_start(label, True, True, 0)
|
||||
vbox.pack_start(status_box, True, True, 0)
|
||||
vbox.pack_start(info_box, True, True, 0)
|
||||
|
||||
box = Gtk.HBox(homogeneous=False, spacing=4)
|
||||
box.set_border_width(4)
|
||||
box.pack_start(icon, False, False, 0)
|
||||
box.pack_start(vbox, True, True, 0)
|
||||
box.show_all()
|
||||
|
||||
frame.add(box)
|
||||
info_box.set_visible(False)
|
||||
return frame
|
||||
|
||||
|
||||
def toggle(window, trigger):
|
||||
if window.get_visible():
|
||||
position = window.get_position()
|
||||
window.hide()
|
||||
window.move(*position)
|
||||
else:
|
||||
if trigger and type(trigger) == Gtk.StatusIcon:
|
||||
x, y = window.get_position()
|
||||
if x == 0 and y == 0:
|
||||
x, y, _ = Gtk.StatusIcon.position_menu(Gtk.Menu(), trigger)
|
||||
window.move(x, y)
|
||||
window.present()
|
||||
return True
|
||||
|
||||
|
||||
def create(title, name, max_devices, systray=False):
|
||||
window = Gtk.Window()
|
||||
window.set_title(title)
|
||||
window.set_icon_name(ui.appicon(0))
|
||||
window.set_role('status-window')
|
||||
|
||||
vbox = Gtk.VBox(homogeneous=False, spacing=4)
|
||||
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)
|
||||
|
||||
window.toggle_visible = lambda i: toggle(window, i)
|
||||
|
||||
if systray:
|
||||
window.set_keep_above(True)
|
||||
window.connect('delete-event', toggle)
|
||||
else:
|
||||
window.connect('delete-event', Gtk.main_quit)
|
||||
|
||||
return window
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
def _update_receiver_box(frame, receiver):
|
||||
label, toolbar, info_label = ui.find_children(frame, 'label', 'toolbar', 'info-label')
|
||||
|
||||
label.set_text(receiver.status_text or '')
|
||||
if receiver.status < STATUS.CONNECTED:
|
||||
toolbar.set_sensitive(False)
|
||||
toolbar.get_children()[0].set_active(False)
|
||||
info_label.set_text('')
|
||||
frame._device = None
|
||||
else:
|
||||
toolbar.set_sensitive(True)
|
||||
frame._device = receiver
|
||||
|
||||
|
||||
def _update_device_box(frame, dev):
|
||||
frame._device = dev
|
||||
|
||||
icon, label, info_label = ui.find_children(frame, 'icon', 'label', 'info-label')
|
||||
|
||||
if frame.get_name() != dev.name:
|
||||
frame.set_name(dev.name)
|
||||
icon_name = ui.get_icon(dev.name, dev.kind)
|
||||
icon.set_from_icon_name(icon_name, _DEVICE_ICON_SIZE)
|
||||
label.set_markup('<b>' + dev.name + '</b>')
|
||||
|
||||
status = ui.find_children(frame, 'status')
|
||||
status_icons = status.get_children()
|
||||
toolbar = status_icons[-1]
|
||||
if dev.status < STATUS.CONNECTED:
|
||||
icon.set_sensitive(False)
|
||||
label.set_sensitive(False)
|
||||
status.set_sensitive(False)
|
||||
for c in status_icons[1:-1]:
|
||||
c.set_visible(False)
|
||||
toolbar.get_children()[0].set_active(False)
|
||||
else:
|
||||
icon.set_sensitive(True)
|
||||
label.set_sensitive(True)
|
||||
status.set_sensitive(True)
|
||||
|
||||
battery_icon, battery_label = status_icons[0:2]
|
||||
battery_level = dev.props.get(PROPS.BATTERY_LEVEL)
|
||||
if battery_level is None:
|
||||
battery_icon.set_from_icon_name('battery_unknown', _STATUS_ICON_SIZE)
|
||||
battery_icon.set_sensitive(False)
|
||||
battery_label.set_visible(False)
|
||||
else:
|
||||
icon_name = 'battery_%03d' % (20 * ((battery_level + 10) // 20))
|
||||
battery_icon.set_from_icon_name(icon_name, _STATUS_ICON_SIZE)
|
||||
battery_icon.set_sensitive(True)
|
||||
battery_label.set_text('%d%%' % battery_level)
|
||||
battery_label.set_visible(True)
|
||||
|
||||
battery_status = dev.props.get(PROPS.BATTERY_STATUS)
|
||||
battery_icon.set_tooltip_text(battery_status or '')
|
||||
|
||||
light_icon, light_label = status_icons[2:4]
|
||||
light_level = dev.props.get(PROPS.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)
|
||||
|
||||
for b in toolbar.get_children()[:-1]:
|
||||
b.set_sensitive(True)
|
||||
|
||||
frame.set_visible(True)
|
||||
|
||||
|
||||
def update(window, receiver, device=None):
|
||||
# print ("update", receiver, receiver.status, device)
|
||||
window.set_icon_name(ui.appicon(receiver.status))
|
||||
|
||||
vbox = window.get_child()
|
||||
frames = list(vbox.get_children())
|
||||
|
||||
if device is None:
|
||||
_update_receiver_box(frames[0], receiver)
|
||||
if receiver.status < STATUS.CONNECTED:
|
||||
for frame in frames[1:]:
|
||||
frame.set_visible(False)
|
||||
frame.set_name(_PLACEHOLDER)
|
||||
frame._device = None
|
||||
else:
|
||||
frame = frames[device.number]
|
||||
if device.status == STATUS.UNPAIRED:
|
||||
frame.set_visible(False)
|
||||
frame.set_name(_PLACEHOLDER)
|
||||
frame._device = None
|
||||
else:
|
||||
_update_device_box(frame, device)
|
||||
@@ -1,75 +0,0 @@
|
||||
#
|
||||
# Optional desktop notifications.
|
||||
#
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
try:
|
||||
from gi.repository import Notify
|
||||
|
||||
import ui
|
||||
from logitech.devices.constants import STATUS
|
||||
|
||||
# necessary because the notifications daemon does not know about our XDG_DATA_DIRS
|
||||
_icons = {}
|
||||
|
||||
def _icon(title):
|
||||
if title not in _icons:
|
||||
_icons[title] = ui.icon_file(title)
|
||||
|
||||
return _icons.get(title)
|
||||
|
||||
# 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):
|
||||
"""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()
|
||||
|
||||
n.update(summary, dev.status_text, _icon(summary) or dev.kind)
|
||||
urgency = Notify.Urgency.LOW if dev.status > STATUS.CONNECTED 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:
|
||||
logging.warn("desktop notifications disabled")
|
||||
available = False
|
||||
init = lambda app_title: False
|
||||
uninit = lambda: None
|
||||
show = lambda dev: None
|
||||
@@ -1,125 +0,0 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
# import logging
|
||||
from gi.repository import (Gtk, GObject)
|
||||
|
||||
import ui
|
||||
|
||||
|
||||
def _create_page(assistant, text, kind):
|
||||
p = Gtk.VBox(False, 12)
|
||||
p.set_border_width(8)
|
||||
|
||||
if text:
|
||||
label = Gtk.Label(text)
|
||||
label.set_alignment(0, 0)
|
||||
p.pack_start(label, False, True, 0)
|
||||
|
||||
assistant.append_page(p)
|
||||
assistant.set_page_type(p, kind)
|
||||
|
||||
p.show_all()
|
||||
return p
|
||||
|
||||
|
||||
def _device_confirmed(entry, _2, trigger, assistant, page):
|
||||
assistant.commit()
|
||||
assistant.set_page_complete(page, True)
|
||||
return True
|
||||
|
||||
|
||||
def _finish(assistant):
|
||||
# logging.debug("finish %s", assistant)
|
||||
assistant.destroy()
|
||||
|
||||
def _cancel(assistant, state):
|
||||
# logging.debug("cancel %s", assistant)
|
||||
state.stop_scan()
|
||||
_finish(assistant)
|
||||
|
||||
def _prepare(assistant, page, state):
|
||||
index = assistant.get_current_page()
|
||||
# logging.debug("prepare %s %d %s", assistant, index, page)
|
||||
|
||||
if index == 0:
|
||||
state.reset()
|
||||
GObject.timeout_add(state.TICK, state.countdown, assistant)
|
||||
spinner = page.get_children()[-1]
|
||||
spinner.start()
|
||||
return
|
||||
|
||||
assistant.remove_page(0)
|
||||
state.stop_scan()
|
||||
|
||||
|
||||
def _scan_complete_ui(assistant, device):
|
||||
if device is None:
|
||||
page = _create_page(assistant,
|
||||
'No new device detected.\n'
|
||||
'\n'
|
||||
'Make sure your device is within range of the receiver,\nand it has a decent battery charge.\n',
|
||||
Gtk.AssistantPageType.CONFIRM)
|
||||
else:
|
||||
page = _create_page(assistant,
|
||||
None,
|
||||
Gtk.AssistantPageType.CONFIRM)
|
||||
|
||||
hbox = Gtk.HBox(False, 16)
|
||||
device_icon = Gtk.Image()
|
||||
device_icon.set_from_icon_name(ui.get_icon(device.name, device.kind), Gtk.IconSize.DIALOG)
|
||||
hbox.pack_start(device_icon, False, False, 0)
|
||||
device_label = Gtk.Label(device.kind + '\n' + device.name)
|
||||
hbox.pack_start(device_label, False, False, 0)
|
||||
halign = Gtk.Alignment.new(0.5, 0.5, 0, 1)
|
||||
halign.add(hbox)
|
||||
page.pack_start(halign, False, True, 0)
|
||||
|
||||
hbox = Gtk.HBox(False, 16)
|
||||
hbox.pack_start(Gtk.Entry(), False, False, 0)
|
||||
hbox.pack_start(Gtk.ToggleButton('Test'), False, False, 0)
|
||||
halign = Gtk.Alignment.new(0.5, 0.5, 0, 1)
|
||||
halign.add(hbox)
|
||||
page.pack_start(halign, False, False, 0)
|
||||
|
||||
entry_info = Gtk.Label('Use the controls above to confirm\n'
|
||||
'this is the device you want to pair.')
|
||||
entry_info.set_sensitive(False)
|
||||
page.pack_start(entry_info, False, False, 0)
|
||||
|
||||
page.show_all()
|
||||
assistant.set_page_complete(page, True)
|
||||
|
||||
assistant.next_page()
|
||||
|
||||
def _scan_complete(assistant, device):
|
||||
GObject.idle_add(_scan_complete_ui, assistant, device)
|
||||
|
||||
|
||||
def create(action, state):
|
||||
assistant = Gtk.Assistant()
|
||||
assistant.set_title(action.get_label())
|
||||
assistant.set_icon_name(action.get_icon_name())
|
||||
|
||||
assistant.set_size_request(440, 240)
|
||||
assistant.set_resizable(False)
|
||||
assistant.set_role('pair-device')
|
||||
|
||||
page_intro = _create_page(assistant,
|
||||
'Turn on the device you want to pair.\n'
|
||||
'\n'
|
||||
'If the device is already turned on,\nturn if off and on again.',
|
||||
Gtk.AssistantPageType.INTRO)
|
||||
spinner = Gtk.Spinner()
|
||||
spinner.set_visible(True)
|
||||
page_intro.pack_end(spinner, True, True, 16)
|
||||
|
||||
assistant.scan_complete = _scan_complete
|
||||
|
||||
assistant.connect('prepare', _prepare, state)
|
||||
assistant.connect('cancel', _cancel, state)
|
||||
assistant.connect('close', _finish)
|
||||
assistant.connect('apply', _finish)
|
||||
|
||||
return assistant
|
||||
@@ -1,55 +0,0 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
from gi.repository import Gtk
|
||||
import ui
|
||||
|
||||
|
||||
def create(window, menu_actions=None):
|
||||
icon = Gtk.StatusIcon()
|
||||
icon.set_title(window.get_title())
|
||||
icon.set_name(window.get_title())
|
||||
icon.set_from_icon_name(ui.appicon(0))
|
||||
|
||||
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)
|
||||
|
||||
return icon
|
||||
|
||||
|
||||
def update(icon, receiver):
|
||||
icon.set_from_icon_name(ui.appicon(receiver.status))
|
||||
|
||||
if receiver.devices:
|
||||
lines = []
|
||||
if receiver.status < 1:
|
||||
lines += (receiver.status_text, '')
|
||||
|
||||
devlist = [receiver.devices[d] for d in range(1, 1 + receiver.max_devices) if d in receiver.devices]
|
||||
for dev in devlist:
|
||||
name = '<b>' + dev.name + '</b>'
|
||||
if dev.status < 1:
|
||||
lines.append(name + ' (' + dev.status_text + ')')
|
||||
else:
|
||||
lines.append(name)
|
||||
if dev.status > 1:
|
||||
lines.append(' ' + dev.status_text)
|
||||
lines.append('')
|
||||
|
||||
text = '\n'.join(lines).rstrip('\n')
|
||||
icon.set_tooltip_markup(text)
|
||||
else:
|
||||
icon.set_tooltip_text(receiver.status_text)
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
Z=`readlink -f "$0"`
|
||||
LIB=`readlink -f $(dirname "$Z")/../lib`
|
||||
#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LIB/native/`arch`
|
||||
export PYTHONPATH=$LIB
|
||||
|
||||
PYTHON=`which python python2 python3 | head -n 1`
|
||||
exec $PYTHON -OOu -m hidapi.hidconsole "$@"
|
||||
9
bin/scan
@@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
Z=`readlink -f "$0"`
|
||||
LIB=`readlink -f $(dirname "$Z")/../lib`
|
||||
#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LIB/native/`arch`
|
||||
export PYTHONPATH=$LIB
|
||||
|
||||
PYTHON=`which python python2 python3 | head -n 1`
|
||||
exec $PYTHON -OOu -m logitech.scanner "$@"
|
||||
62
bin/solaar
@@ -1,13 +1,55 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env python3
|
||||
# -*- python-mode -*-
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
Z=`readlink -f "$0"`
|
||||
APP=`readlink -f $(dirname "$Z")/../app`
|
||||
LIB=`readlink -f $(dirname "$Z")/../lib`
|
||||
SHARE=`readlink -f $(dirname "$Z")/../share`
|
||||
## 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 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LIB/native/`arch`
|
||||
export PYTHONPATH=$APP:$LIB
|
||||
export XDG_DATA_DIRS=$SHARE:$XDG_DATA_DIRS
|
||||
|
||||
PYTHON=`which python python2 python3 | head -n 1`
|
||||
exec $PYTHON -OOu -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:
|
||||
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()
|
||||
|
||||
6
docs/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# ignore documentation-specific files
|
||||
|
||||
.jekyll-metadata
|
||||
Gemfile
|
||||
Gemfile.lock
|
||||
_site/
|
||||
BIN
docs/20121210110342697.pdf
Normal file
4
docs/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Documentation Readme
|
||||
|
||||
This project's documentation is hosted using GitHub pages, which serves static pages using Jekyll.
|
||||
[Please refer to the official documentation for instructions for how to build the site locally.](https://help.github.com/articles/setting-up-your-github-pages-site-locally-with-jekyll/)
|
||||
BIN
docs/Solaar-main-window-back-divert.png
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
docs/Solaar-main-window-button-actions.png
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
docs/Solaar-main-window-keyboard.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
docs/Solaar-main-window-mouse.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
docs/Solaar-main-window-multiple.png
Normal file
|
After Width: | Height: | Size: 135 KiB |
BIN
docs/Solaar-main-window-offline.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
docs/Solaar-main-window-receiver.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
docs/Solaar-menu.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
docs/Solaar-rule-editor.png
Normal file
|
After Width: | Height: | Size: 141 KiB |
10
docs/_config.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
title: Solaar
|
||||
description: Linux Device Manager for Logitech Unifying Receivers and Devices.
|
||||
tagline: Linux Device Manager for Logitech Unifying Receivers and Devices.
|
||||
owner: pwr-Solaar
|
||||
owner_url: https://github.com/pwr-Solaar
|
||||
repository: pwr-Solaar/Solaar
|
||||
version: 1.1.2
|
||||
show_downloads: false
|
||||
encoding: utf-8
|
||||
theme: jekyll-theme-slate
|
||||
53
docs/_layouts/default.html
Normal 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
@@ -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
|
After Width: | Height: | Size: 1.7 KiB |
100
docs/assets/solaar.svg
Normal 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 |
219
docs/capabilities.md
Normal file
@@ -0,0 +1,219 @@
|
||||
---
|
||||
title: Solaar Capabilities
|
||||
layout: page
|
||||
---
|
||||
|
||||
# Solaar Capabilities
|
||||
|
||||
[**Solaar**][solaar] reports on and controls [Logitech][logitech] devices
|
||||
(keyboards, mice, and trackballs) that connect to your computer via a
|
||||
Logitech USB receiver (a very small piece of hardware that plugs into one of
|
||||
your USB ports).
|
||||
Solaar is designed to detect all connected devices,
|
||||
and at the very least display some basic information about them.
|
||||
At this moment, all [Unifying][unifying] receivers are supported (e.g., devices
|
||||
with USB ID `046d:c52b` or `046d:c532`) as are several Lightspeed Receivers
|
||||
and many Nano receivers.
|
||||
|
||||
Solaar also reports on and controls some Logitech devices that directly connect
|
||||
to your computer using a USB cable or via Bluetooth.
|
||||
Not all such devices supported in Solaar as information needs to be added to Solaar
|
||||
for each device type that directly connects.
|
||||
|
||||
|
||||
## HID++
|
||||
|
||||
The devices that Solaar handles use Logitech's HID++ protocol.
|
||||
|
||||
HID++ is a Logitech-proprietary protocol that extends the standard HID
|
||||
protocol for interfacing with receivers, keyboards, mice, and so on. It allows
|
||||
Logitech receivers to communicate with multiple devices and modify some
|
||||
features of the device. As the HID++ protocol is
|
||||
proprietary, many aspects of it are unknown. Some information about HID++
|
||||
has been obtained from Logitech but even that is subject to change and
|
||||
extension.
|
||||
|
||||
There are several versions of HID++ and many Logitech
|
||||
receivers and devices that utilize it. Different receivers and devices
|
||||
implement different portions of HID++ so even if two devices appear to be
|
||||
the same in both physical appearance and behavior they may work
|
||||
differently underneath. (For example, there are versions of the
|
||||
M510 mouse that use different versions of the HID++ protocol.)
|
||||
Contrariwise, two different devices may appear different physically but
|
||||
actually look the same to software. (For example, some M185 mice look the
|
||||
same to software as some M310 mice.)
|
||||
|
||||
The software identity of a receiver can be determined by its USB product ID
|
||||
(reported by Solaar and also viewable in Linux using `lsusb`). The software
|
||||
identity of a device that connects to a receiver can be determined by
|
||||
its wireless PID as reported by Solaar. The software identity of devices that
|
||||
connect via a USB cable or via bluetooth can be determined by their USB or
|
||||
Bluetooth product ID.
|
||||
|
||||
|
||||
# Pairing and Unpairing
|
||||
|
||||
Solaar is able to pair and unpair devices with
|
||||
receivers as supported by the device and receiver.
|
||||
|
||||
For Unifying 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.
|
||||
|
||||
Bolt receivers add an authentication phase to pairing,
|
||||
where the user has type a passcode or click some buttons to authenticate the device.
|
||||
|
||||
Only some connections between receivers and devices are possible. 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.
|
||||
|
||||
|
||||
## Device Settings
|
||||
|
||||
Solaar can display quite a few changeable settings of receivers and devices.
|
||||
For a list of HID++ features and their support see [the features page](features).
|
||||
|
||||
Solaar does not do much beyond using the HID++ protocol to change the
|
||||
behavior of receivers and devices via changing their settings.
|
||||
In particular, Solaar cannot change how
|
||||
the operating system turns the keycodes that a keyboard produces into
|
||||
characters that are sent to programs. That is the province of HID device
|
||||
drivers and other software (such as X11).
|
||||
|
||||
Settings can only be changed in the Solaar GUI when they are unlocked.
|
||||
To unlock a setting click on the icon at the right-hand edge of the setting
|
||||
until an unlocked lock appears (with tooltop "Changes allowed").
|
||||
|
||||
Solaar keeps track of most of the changeable settings of a device.
|
||||
Devices forget most changed settings when the device is turned off
|
||||
or goes into a power-saving mode.
|
||||
The exceptions include the setting to change the host the device is connected to
|
||||
and the setting to persistently change what a key or button does.
|
||||
When Solaar starts, it restores on-line devices to their previously-known state
|
||||
for the unexceptionable settings and while running it restores
|
||||
devices to their previously-known state when the device itself comes on line.
|
||||
Setting information is stored in the file `~/.config/solaar/config.json`.
|
||||
|
||||
Updating of a setting can be turned off in the Solaar GUI by clicking on the icon
|
||||
at the right-hand edge of the setting until a red icon appears (with tooltip
|
||||
"Ignore this setting" ).
|
||||
|
||||
Solaar keeps track of settings independently on each computer.
|
||||
As a result if a device is switched between different computers
|
||||
Solaar may apply different settings for it on the different computers
|
||||
|
||||
Querying a device for its current state can require quite a few HID++
|
||||
interactions. These interactions can temporarily slow down the device, so
|
||||
Solaar tries to internally cache information about devices while it is
|
||||
running. If the device
|
||||
state is changed by some other means, even sometimes by another invocation
|
||||
of Solaar, this cached information may become incorrect. Currently there is
|
||||
no way to force an update of the cached information besides restarting Solaar.
|
||||
|
||||
Logitech receivers and devices have firmware in them. Some firmware
|
||||
can be updated using Logitech software in Windows. For example, there are
|
||||
security issues with some Logitech receivers and devices and Logitech has
|
||||
firmware updates to alleviate these problems. Some Logitech firmware can
|
||||
also be updated in Linux using `fwupdmgr`.
|
||||
WARNING: Updating firmware can cause a piece of hardware to become
|
||||
permanently non-functional if something goes wrong with the update or the
|
||||
update installs the wrong firmware.
|
||||
|
||||
## Other Solaar Capabilities
|
||||
|
||||
Solaar has a few capabilities that go beyond simply changing device settings.
|
||||
|
||||
### Rule-based Processing of HID++ Notifications
|
||||
|
||||
Solaar can process HID++ Notifications from devices to, for example,
|
||||
change the speed of some thumb wheels. These notifications are only sent
|
||||
for actions that are set in Solaar to their HID++ setting (also known as diverted).
|
||||
For more information on this capability of Solaar see
|
||||
[the rules page](https://pwr-solaar.github.io/Solaar/rules). As much of rule processing
|
||||
depends on X11, this capability is only when running under X11.
|
||||
|
||||
Users can edit rules using a GUI by clicking on the `Edit Rule` button in the Solaar main window.
|
||||
|
||||
Solaar rules is an experimental feature. Significant changes might be made in response to problems.
|
||||
|
||||
|
||||
### Sliding DPI
|
||||
|
||||
A few mice (such as the MX Vertical) have a button that is supposed to be used to change
|
||||
the sensitivity (DPI) of the mouse by pressing the button and moving the mouse left and right.
|
||||
Other mice (such as the MX Master 3) don't have a button specific for this purpose
|
||||
but have buttons that can be used for it.
|
||||
|
||||
The DPI Sliding Adjustment setting assigns a button for this purpose.
|
||||
Pressing the button, if the button is diverted, causes the mouse pointer to stop moving.
|
||||
When the button is released a new Sensitivity (DPI) value is applied to the mouse,
|
||||
depending on how far right or left the mouse is moved. If the mouse is moved only a little bit
|
||||
the previous value that was set is applied to the mouse.
|
||||
Notifications from Solaar are displayed while the mouse button is done
|
||||
showing the setting that will be applied.
|
||||
|
||||
### Mouse Gestures
|
||||
|
||||
Some mice (such as the MX Master 3) have a button that is supposed to be used to
|
||||
create up/down/left/right mouse gestures. Other mice (such as the MX Vertical) don't
|
||||
have a button specific for this purpose but have buttons that can be used for it.
|
||||
|
||||
The Mouse Gestures setting assigns a button for this purpose.
|
||||
Pressing the button, if the button is diverted, causes the mouse pointer to stop moving.
|
||||
When the button is released a MOUSE_GESTURE notification with the total mouse movement
|
||||
while the button was pressed is sent to the Solaar rule system.
|
||||
|
||||
MOUSE_GESTURE notifications trigger mouse gesture conditions in Solaar rules.
|
||||
For more information on mouse gesture rules conditions see
|
||||
[the rules page](https://pwr-solaar.github.io/Solaar/rules).
|
||||
|
||||
Mouse gestures is an experimental feature.
|
||||
Significant changes might be made to it in the future.
|
||||
|
||||
|
||||
## System Tray
|
||||
|
||||
Solaar's GUI normally uses an icon in the system tray.
|
||||
This allows users to close Solaar and reopen from the tray.
|
||||
This aspect of Solaar depends on having an active system tray which may
|
||||
require some special setup when using Gnome, particularly under Wayland.
|
||||
|
||||
If you are running gnome, you most likely need the
|
||||
`gnome-shell-extension-appindicator` package installed.
|
||||
In Fedora, this can be done by running
|
||||
```
|
||||
sudo dnf install gnome-shell-extension-appindicator
|
||||
```
|
||||
The likely command in Ubuntu and related distributions is
|
||||
```
|
||||
sudo apt install gnome-shell-extension-appindicator
|
||||
```
|
||||
You may have to log out and log in again before the system tray shows up.
|
||||
|
||||
|
||||
## Battery Icons
|
||||
|
||||
For many devices, Solaar shows the approximate battery level via icons that
|
||||
show up in both the main window and the system tray. In previous versions
|
||||
several heuristics 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 external bugs,
|
||||
these symbolic icons may be nearly invisible in dark themes.
|
||||
|
||||
[solaar]: https://github.com/pwr-Solaar/Solaar
|
||||
[logitech]: https://www.logitech.com
|
||||
[unifying]: https://en.wikipedia.org/wiki/Logitech_Unifying_receiver
|
||||
8
docs/debian.md
Normal 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`
|
||||
239
docs/devices.md
Normal file
@@ -0,0 +1,239 @@
|
||||
---
|
||||
title: Supported Devices
|
||||
layout: page
|
||||
---
|
||||
|
||||
# Supported receivers and devices
|
||||
|
||||
Solaar only supports Logitech receivers and devices that use the Logitech proprietary HID++ protocol.
|
||||
|
||||
Solaar supports most Logitech Nano, Unifying, and Bolt receivers.
|
||||
Solaar supports some Lightspeed receivers.
|
||||
See the receiver table below for the list of currently supported receivers.
|
||||
|
||||
Solaar supports most recent and many older Logitech devices
|
||||
(keyboards, mice, trackballs, and touchpads)
|
||||
that can connect to supported receivers.
|
||||
Solaar supports many recent Logitech devices that can connect via a USB cable,
|
||||
but some such Logitech devices are not suited for use in Solaar because they do not use the HID++ protocol.
|
||||
One example is the MX518 Gaming Mouse.
|
||||
Solaar supports most recent Logitech devices that can connect via Bluetooth.
|
||||
|
||||
The device tables below provide a list of some of the devices that Solaar supports,
|
||||
giving their product name, WPID product number, and HID++ protocol information..
|
||||
The tables concentrate on older devices that have explicit support information in Solaar.
|
||||
|
||||
The best way to determine whether Solaar supports a device is to run Solaar while the device is connected.
|
||||
If the device is supported, it will show up in the Solaar main window.
|
||||
If it is not, and there is no issue about the device in the Solaar GitHub repository,
|
||||
open an enhancement issue requesting that it be supported.
|
||||
|
||||
## Adding new receivers and devices
|
||||
|
||||
Adding a new receiver requires knowing whether the receiver is a regular
|
||||
Unifying receiver, a Nano receiver, a Bolt receiver, or a Lightspeed receiver. Add a line to
|
||||
`../lib/logitech_receiver/base_usb.py` defining the receiver as one of these.
|
||||
If the receiver has an unusual number of pairing slots, then this also needs
|
||||
to be specified. Then add the receiver to the tuple of receivers (ALL).
|
||||
|
||||
Most new devices do not need to be known to Solaar to work.
|
||||
The _D function in `../lib/logitech_receiver/descriptors.py` makes a device known to Solaar.
|
||||
The usual arguments to the _D function are the device's long name, its short name
|
||||
(codename), and its HID++ protocol version.
|
||||
Devices that use HID++ 1.0 need a tuple of known registers (registers) and settings (settings).
|
||||
Settings can be provided for Devices that use HID++ 2.0 or later,
|
||||
but Solaar can determine these from the device.
|
||||
If the device can connect to a receiver, provide its wireless product ID (wpid),
|
||||
If the device can connect via Bluetooth, provide its Bluetooth product ID (btid).
|
||||
If the device can connect via a USB cable, provide its USB product ID (usbid),
|
||||
and the interface it uses to send and receiver HID++ messages (interface - default 2).
|
||||
The use of a non-default USB interface is the main reason for requiring information about
|
||||
modern devices to be added to Solaar.
|
||||
|
||||
|
||||
### Supported Receivers
|
||||
|
||||
| USB ID | Kind | Max Paired Devices |
|
||||
------------|------------|--------------------|
|
||||
| 046d:c517 | 27MHz | 4 |
|
||||
| 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 |
|
||||
| 046d:c534 | Nano | 2 |
|
||||
| 046d:c537 | Nano | 2 |
|
||||
| 046d:c539 | Lightspeed | 1 |
|
||||
| 046d:c53a | Lightspeed | 1 |
|
||||
| 046d:c53d | Lightspeed | 1 |
|
||||
| 046d:c53f | Lightspeed | 1 |
|
||||
| 046d:c541 | Lightspeed | 1 |
|
||||
| 046d:c542 | Nano | 1 |
|
||||
| 046d:c545 | Lightspeed | 1 |
|
||||
| 046d:c547 | Lightspeed | 1 |
|
||||
| 046d:c548 | Bolt | 6 |
|
||||
| 17ef:6042 | Nano | 1 |
|
||||
|
||||
Some Nano receivers are only partly supported
|
||||
as they do not fully implement the full HID++ 1.0 protocol.
|
||||
Some Nano receivers are not supported at all as they do not implement the HID++ protocol.
|
||||
Receivers with USB ID 046d:c542 fall into this category.
|
||||
|
||||
The receiver with USB ID 046d:c517 is an old 27 MHz receiver, supporting only
|
||||
subset of HID++ 1.0 protocol. Only hardware pairing is supported.
|
||||
|
||||
|
||||
### Keyboards (Unifying)
|
||||
|
||||
| Device | WPID | HID++ |
|
||||
|------------------|------|-------|
|
||||
| K230 | 400D | 2.0 |
|
||||
| K270 | 4003 | 2.0 |
|
||||
| K340 | 2007 | 1.0 |
|
||||
| K350 | 200A | 1.0 |
|
||||
| K360 | 4004 | 2.0 |
|
||||
| K375s | 4071 | |
|
||||
| K400 Touch | 400E | 2.0 |
|
||||
| K400 Touch | 4024 | 2.0 |
|
||||
| K400 Plus | 404D | 2.0 |
|
||||
| K520 | 2011 | 1.0 |
|
||||
| K600 TV | 4078 | 2.0 |
|
||||
| K750 Solar | 4002 | 2.0 |
|
||||
| K780 | 405B | 2.0 |
|
||||
| K800 Illuminated | 2010 | 1.0 |
|
||||
| K800 (new ver) | 406E | 2.0 |
|
||||
| K830 Illuminated | 4032 | 2.0 |
|
||||
| MX Keys | 408A | 2.0 |
|
||||
| N545 | 2006 | |
|
||||
| TK820 | | 2.0 |
|
||||
| Craft | 4066 | 2.0 |
|
||||
|
||||
|
||||
### Keyboards (Lightspeed)
|
||||
|
||||
| Device | WPID | HID++ |
|
||||
|------------------|------|-------|
|
||||
| G915 TKL | 408E | 4.2 |
|
||||
|
||||
### Mice (Unifying)
|
||||
|
||||
| Device | WPID | HID++ |
|
||||
|------------------|------|-------|
|
||||
| M150 | 4022 | 2.0 |
|
||||
| M185 | 4055 | 2.0 |
|
||||
| M310 | 4031 | 2.0 |
|
||||
| M310 | 4055 | 2.0 |
|
||||
| M317 | | |
|
||||
| M325 | 400A | 2.0 |
|
||||
| M330 | | 2.0 |
|
||||
| M345 | 4017 | 2.0 |
|
||||
| M350 | 101C | 1.0 |
|
||||
| M350 | 4080 | 2.0 |
|
||||
| M505 | 101D | 1.0 |
|
||||
| M510 | 1025 | 1.0 |
|
||||
| M510 | 4051 | 2.0 |
|
||||
| M515 Couch | 4007 | 2.0 |
|
||||
| M525 | 4013 | 2.0 |
|
||||
| M560 | | 2.0 |
|
||||
| M585 | 406B | 2.0 |
|
||||
| M590 | 406B | 2.0 |
|
||||
| M600 Touch | 401A | 2.0 |
|
||||
| M705 Marathon | 101B | 1.0 |
|
||||
| M705 Marathon | 406D | 2.0 |
|
||||
| M720 Triathlon | 405E | 2.0 |
|
||||
| T400 Zone Touch | | 2.0 |
|
||||
| T620 Touch | | 2.0 |
|
||||
| Performance MX | 101A | 1.0 |
|
||||
| Anywhere MX | 1017 | 1.0 |
|
||||
| Anywhere MX 2 | 404A | 2.0 |
|
||||
| MX Master | 4041 | 2.0 |
|
||||
| MX Master 2S | 4069 | 2.0 |
|
||||
| Cube | | 2.0 |
|
||||
|
||||
### Mice (Nano)
|
||||
|
||||
| Device | WPID | HID++ |
|
||||
|------------------|------|-------|
|
||||
| G7 | 1002 | 1.0 |
|
||||
| G700 | 1023 | 1.0 |
|
||||
| G700s | 102A | 1.0 |
|
||||
| V450 Nano | 1011 | 1.0 |
|
||||
| V550 Nano | 1013 | 1.0 |
|
||||
| VX Nano | 100B | 1.0 |
|
||||
| VX Nano | 100F | 1.0 |
|
||||
| M175 | 4008 | |
|
||||
| M185 (old) | 4038 | 2.0 |
|
||||
| M185 (new) | 4054 | 2.0 |
|
||||
| M187 | 4019 | 2.0 |
|
||||
| M215 | 1020 | 1.0 |
|
||||
| M235 | 4055 | 2.0 |
|
||||
| M305 | 101F | 1.0 |
|
||||
| M310 | 1024 | 1.0 |
|
||||
| M315 | | |
|
||||
| M330 | | ?.? |
|
||||
| MX 1100 | 1014 | 1.0 |
|
||||
|
||||
* (old): M185 with P/N: 810-003496
|
||||
* (new): M185 with P/N: 810-005238 or 810-005232
|
||||
|
||||
### Mice (Mini)
|
||||
|
||||
| Device | WPID | HID++ |
|
||||
|-------------------|------|-------|
|
||||
| MX610 | 1001 | 1.0 |
|
||||
| MX610 left handed | 1004 | 1.0 |
|
||||
| MX620 | 100A | 1.0 |
|
||||
| MX620 | 1016 | 1.0 |
|
||||
| V400 | 1003 | 1.0 |
|
||||
| V450 | 1005 | 1.0 |
|
||||
| VX Revolution | 1006 | 1.0 |
|
||||
| VX Revolution | 100D | 1.0 |
|
||||
| MX Air | 1007 | 1.0 |
|
||||
| MX Air | 100E | 1.0 |
|
||||
| MX Revolution | 1008 | 1.0 |
|
||||
| MX Revolution | 100C | 1.0 |
|
||||
|
||||
|
||||
### Mice (Lightspeed)
|
||||
|
||||
| Device | WPID | HID++ |
|
||||
|------------------------------|------|-------|
|
||||
| PRO X Superlight Wireless | 4093 | 4.2 |
|
||||
|
||||
### Trackballs (Unifying)
|
||||
|
||||
| Device | WPID | HID++ |
|
||||
|-------------------|------|-------|
|
||||
| M570 Trackball | | 1.0 |
|
||||
| MX Ergo Trackball | | 2.0 |
|
||||
|
||||
### Touchpads (Unifying)
|
||||
|
||||
| Device | WPID | HID++ |
|
||||
|------------------|------|-------|
|
||||
| Wireless Touch | 4011 | 2.0 |
|
||||
| T650 Touchpad | 4101 | 2.0 |
|
||||
|
||||
### Mice and Keyboards sold as combos
|
||||
|
||||
| Device | WPID | HID++ |
|
||||
|------------------|------|-------|
|
||||
| MK220 | | 2.0 |
|
||||
| MK270 | 4023 | 2.0 |
|
||||
| MK320 | 200F | |
|
||||
| MK330 | | |
|
||||
| MK345 | 4023 | 2.0 |
|
||||
| MK520 | | M2/K1 |
|
||||
| MK550 | | |
|
||||
| MK700 | 2008 | 1.0 |
|
||||
| MK710 | | 1.0 |
|
||||
| EX100 keyboard | 0065 | 1.0 |
|
||||
| EX100 mouse | 003f | 1.0 |
|
||||
|
||||
* The EX100 is an old, preunifying receiver and device set, supporting only part of HID++ 1.0 features
|
||||
48
docs/devices/M510_HIDppV4.5.txt
Normal 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.
|
||||
51
docs/devices/anywhere-mx-2.txt
Normal 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.
|
||||
88
docs/devices/anywhere-mx.txt
Normal 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'
|
||||
113
docs/devices/craft.txt
Normal file
@@ -0,0 +1,113 @@
|
||||
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.
|
||||
120
docs/devices/ex100.txt
Normal file
@@ -0,0 +1,120 @@
|
||||
./scan-registers.sh ff /dev/hidraw4
|
||||
# Old notification flags: 000100
|
||||
>> ( 0.035) [10 FF 8100 000100] '\x10\xff\x81\x00\x00\x01\x00'
|
||||
<< ( 0.015) [10 FF 8101 000000] '\x10\xff\x81\x01\x00\x00\x00'
|
||||
>> ( 0.020) [10 FF 8101 000200] '\x10\xff\x81\x01\x00\x02\x00'
|
||||
<< ( 0.030) [10 FF 8102 000000] '\x10\xff\x81\x02\x00\x00\x00'
|
||||
>> ( 0.036) [10 FF 8102 000200] '\x10\xff\x81\x02\x00\x02\x00'
|
||||
--
|
||||
<< ( 0.142) [10 FF 8109 000000] '\x10\xff\x81\t\x00\x00\x00'
|
||||
>> ( 0.148) [10 FF 8109 010000] '\x10\xff\x81\t\x01\x00\x00'
|
||||
--
|
||||
<< ( 1.790) [10 FF 8170 000000] '\x10\xff\x81p\x00\x00\x00'
|
||||
>> ( 1.796) [10 FF 8170 012100] '\x10\xff\x81p\x01!\x00'
|
||||
<< ( 1.806) [10 FF 8171 000000] '\x10\xff\x81q\x00\x00\x00'
|
||||
>> ( 1.812) [10 FF 8171 011200] '\x10\xff\x81q\x01\x12\x00'
|
||||
--
|
||||
<< ( 1.838) [10 FF 8173 000000] '\x10\xff\x81s\x00\x00\x00'
|
||||
>> ( 1.844) [10 FF 8173 643F00] '\x10\xff\x81sd?\x00'
|
||||
--
|
||||
<< ( 2.046) [10 FF 8180 000000] '\x10\xff\x81\x80\x00\x00\x00'
|
||||
>> ( 2.052) [10 FF 8180 030000] '\x10\xff\x81\x80\x03\x00\x00'
|
||||
--
|
||||
<< ( 3.326) [10 FF 81D0 000000] '\x10\xff\x81\xd0\x00\x00\x00'
|
||||
>> ( 3.332) [10 FF 81D0 000000] '\x10\xff\x81\xd0\x00\x00\x00'
|
||||
|
||||
devices
|
||||
01 mouse
|
||||
Red button pressed
|
||||
>> ( 1676.106) [10 01 0810 000000] '\x10\x01\x08\x10\x00\x00\x00'
|
||||
>> ( 1676.114) [10 01 4600 000021] '\x10\x01F\x00\x00\x00!'
|
||||
>> ( 1676.122) [10 FF 4600 211100] '\x10\xffF\x00!\x11\x00'
|
||||
|
||||
Power lewel?
|
||||
?? Input: 10 01 81 07 00 00 00
|
||||
<< ( 1739.032) [10 01 8107 000000] '\x10\x01\x81\x07\x00\x00\x00'
|
||||
>> ( 1739.040) [10 01 8107 030000] '\x10\x01\x81\x07\x03\x00\x00'
|
||||
[10 01 8107 070000] '\x10\x01\x81\x07\x07\x00\x00'
|
||||
|
||||
power change
|
||||
>> ( 2441.563) [10 01 0703 000000] '\x10\x01\x07\x03\x00\x00\x00'
|
||||
>> ( 100.159) [10 01 0707 000000] '\x10\x01\x07\x07\x00\x00\x00'
|
||||
|
||||
enable power event
|
||||
<< ( 59.190) [10 01 8000 100000] '\x10\x01\x80\x00\x10\x00\x00'
|
||||
>> ( 59.193) [10 01 8000 000000] '\x10\x01\x80\x00\x00\x00\x00'
|
||||
|
||||
|
||||
03 keyboard
|
||||
|
||||
Power level?
|
||||
?? Input: 10 03 81 07 00 00 00
|
||||
<< ( 1777.961) [10 03 8107 000000] '\x10\x03\x81\x07\x00\x00\x00'
|
||||
>> ( 1777.967) [10 03 8107 070000] '\x10\x03\x81\x07\x07\x00\x00'
|
||||
|
||||
power on
|
||||
>> ( 1571.805) [10 03 0810 000000] '\x10\x03\x08\x10\x00\x00\x00'
|
||||
>> ( 1574.709) [10 03 0800 000000] '\x10\x03\x08\x00\x00\x00\x00'
|
||||
|
||||
red button pressed
|
||||
>> ( 1619.043) [10 03 0810 000000] '\x10\x03\x08\x10\x00\x00\x00'
|
||||
>> ( 1619.051) [10 03 4600 000011] '\x10\x03F\x00\x00\x00\x11'
|
||||
>> ( 1619.059) [10 FF 4600 221100] '\x10\xffF\x00"\x11\x00'
|
||||
>> ( 1621.747) [10 03 0800 000000] '\x10\x03\x08\x00\x00\x00\x00'
|
||||
|
||||
Fn pressed
|
||||
>> ( 1651.715) [10 03 032C 100000] '\x10\x03\x03,\x10\x00\x00'
|
||||
>> ( 1652.170) [10 03 0300 000000] '\x10\x03\x03\x00\x00\x00\x00'
|
||||
|
||||
|
||||
$ bin/solaar probe
|
||||
Nano Receiver
|
||||
Device path : /dev/hidraw3
|
||||
USB id : 046d:c517
|
||||
Serial : None
|
||||
Has 2 paired device(s) out of a maximum of 6.
|
||||
Notifications: wireless (0x000100)
|
||||
Register Dump
|
||||
Notification Register 0x00: 0x000100
|
||||
Connection State 0x02: 0x000200
|
||||
Device Activity 0xb3: None
|
||||
Pairing Register 0xb5 0x00: None
|
||||
Pairing Register 0xb5 0x10: None
|
||||
Pairing Register 0xb5 0x20: None
|
||||
Pairing Register 0xb5 0x30: None
|
||||
Pairing Name 0xb5 0x40: None
|
||||
Pairing Register 0xb5 0x01: None
|
||||
Pairing Register 0xb5 0x11: None
|
||||
Pairing Register 0xb5 0x21: None
|
||||
Pairing Register 0xb5 0x31: None
|
||||
Pairing Name 0xb5 0x41: None
|
||||
Pairing Register 0xb5 0x02: None
|
||||
Pairing Register 0xb5 0x12: None
|
||||
Pairing Register 0xb5 0x22: None
|
||||
Pairing Register 0xb5 0x32: None
|
||||
Pairing Name 0xb5 0x42: None
|
||||
Pairing Register 0xb5 0x03: None
|
||||
Pairing Register 0xb5 0x13: None
|
||||
Pairing Register 0xb5 0x23: None
|
||||
Pairing Register 0xb5 0x33: None
|
||||
Pairing Name 0xb5 0x43: None
|
||||
Pairing Register 0xb5 0x04: None
|
||||
Pairing Register 0xb5 0x14: None
|
||||
Pairing Register 0xb5 0x24: None
|
||||
Pairing Register 0xb5 0x34: None
|
||||
Pairing Name 0xb5 0x44: None
|
||||
Pairing Register 0xb5 0x05: None
|
||||
Pairing Register 0xb5 0x15: None
|
||||
Pairing Register 0xb5 0x25: None
|
||||
Pairing Register 0xb5 0x35: None
|
||||
Pairing Name 0xb5 0x45: None
|
||||
Firmware 0xf1 0x00: None
|
||||
Firmware 0xf1 0x01: None
|
||||
Firmware 0xf1 0x02: None
|
||||
Firmware 0xf1 0x03: None
|
||||
Firmware 0xf1 0x04: None
|
||||
|
||||
Battery status:
|
||||
1.9V critical
|
||||
2.3V low
|
||||
2.5V full
|
||||
42
docs/devices/k270-unifying.txt
Normal file
@@ -0,0 +1,42 @@
|
||||
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
48
docs/devices/m185_new.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
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.
|
||||
50
docs/devices/m185_old.txt
Normal file
@@ -0,0 +1,50 @@
|
||||
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
@@ -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
@@ -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
@@ -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,
|
||||
35
docs/devices/m510.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
# 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'
|
||||
|
||||
# ?
|
||||
<< ( 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'
|
||||
|
||||
# ?
|
||||
<< ( 41.121) [10 01 8128 000000] '\x10\x01\x81(\x00\x00\x00'
|
||||
>> ( 41.136) [10 01 8128 000200] '\x10\x01\x81(\x00\x02\x00'
|
||||
|
||||
# ?
|
||||
<< ( 215.788) [10 01 81D0 000000] '\x10\x01\x81\xd0\x00\x00\x00'
|
||||
>> ( 215.802) [10 01 81D0 000000] '\x10\x01\x81\xd0\x00\x00\x00'
|
||||
|
||||
# read-only, 01-04 firmware info
|
||||
<< ( 250.779) [10 01 81F1 000000] '\x10\x01\x81\xf1\x00\x00\x00'
|
||||
>> ( 250.794) [10 01 8F81 F10300] '\x10\x01\x8f\x81\xf1\x03\x00'
|
||||
|
||||
# ?
|
||||
<< ( 252.809) [10 01 81F3 000000] '\x10\x01\x81\xf3\x00\x00\x00'
|
||||
>> ( 252.824) [10 01 81F3 000000] '\x10\x01\x81\xf3\x00\x00\x00'
|
||||
|
||||
# ?
|
||||
<< ( 253.825) [10 01 81F4 000000] '\x10\x01\x81\xf4\x00\x00\x00'
|
||||
>> ( 253.838) [10 01 81F4 800000] '\x10\x01\x81\xf4\x80\x00\x00'
|
||||
34
docs/devices/m515.txt
Normal 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
@@ -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
@@ -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.
|
||||
24
docs/devices/m570.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
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.
|
||||
82
docs/devices/m585.txt
Normal file
@@ -0,0 +1,82 @@
|
||||
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.
|
||||
42
docs/devices/m705.txt
Normal file
@@ -0,0 +1,42 @@
|
||||
registers:
|
||||
|
||||
# writing 0x10 in this register will generate an event
|
||||
# 10 02 0Dxx yyzz00
|
||||
# where 0D happens to be the battery register number
|
||||
# xx is the battery charge
|
||||
# yy, zz ?
|
||||
<< ( 0.001) [10 02 8100 000000] '\x10\x02\x81\x00\x00\x00\x00'
|
||||
>> ( 1.132) [10 02 8100 100000] '\x10\x02\x81\x00\x10\x00\x00'
|
||||
|
||||
# smooth scroll - possible values
|
||||
# - 00 (off)
|
||||
# - 02 ?, apparently off as well, default value at power-on
|
||||
# - 0x40 (on)
|
||||
<< ( 2.005) [10 02 8101 000000] '\x10\x02\x81\x01\x00\x00\x00'
|
||||
>> ( 2.052) [10 02 8101 020000] '\x10\x02\x81\x01\x02\x00\x00'
|
||||
|
||||
# battery status: percentage full, ?, ?
|
||||
<< ( 14.835) [10 02 810D 000000] '\x10\x02\x81\r\x00\x00\x00'
|
||||
>> ( 14.847) [10 02 810D 644734] '\x10\x02\x81\rdG4'
|
||||
|
||||
# accepts mask 0xF1
|
||||
# setting 0x10 turns off the movement events (but buttons still work)
|
||||
<< ( 221.495) [10 02 81D0 000000] '\x10\x02\x81\xd0\x00\x00\x00'
|
||||
>> ( 221.509) [10 02 81D0 000000] '\x10\x02\x81\xd0\x00\x00\x00'
|
||||
|
||||
# appears to be read-only?
|
||||
<< ( 223.527) [10 02 81D2 000000] '\x10\x02\x81\xd2\x00\x00\x00'
|
||||
>> ( 223.540) [10 02 81D2 000003] '\x10\x02\x81\xd2\x00\x00\x03'
|
||||
|
||||
# appears to be read-only?
|
||||
<< ( 225.557) [10 02 81D4 000000] '\x10\x02\x81\xd4\x00\x00\x00'
|
||||
>> ( 225.571) [10 02 81D4 000004] '\x10\x02\x81\xd4\x00\x00\x04'
|
||||
|
||||
# read-only, 01-04 firmware info
|
||||
<< ( 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 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'
|
||||
81
docs/devices/mk220-new.txt
Normal file
@@ -0,0 +1,81 @@
|
||||
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.
|
||||
77
docs/devices/mk220.txt
Normal file
@@ -0,0 +1,77 @@
|
||||
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
@@ -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
|
||||
```
|
||||
85
docs/devices/mk270.txt
Normal file
@@ -0,0 +1,85 @@
|
||||
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.
|
||||
60
docs/devices/mk520.txt
Normal file
@@ -0,0 +1,60 @@
|
||||
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
@@ -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'
|
||||
84
docs/devices/mx-master-2s.txt
Normal 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.
|
||||
82
docs/devices/mx-master-3.txt
Normal file
@@ -0,0 +1,82 @@
|
||||
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.
|
||||
54
docs/devices/mx-master.txt
Normal 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.
|
||||
40
docs/devices/performance-mx.txt
Normal file
@@ -0,0 +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'
|
||||
|
||||
# ?
|
||||
<< ( 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'
|
||||
|
||||
# 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
@@ -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
@@ -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.
|
||||
205
docs/features.md
Normal file
@@ -0,0 +1,205 @@
|
||||
---
|
||||
title: List of HID++ 2.0 features
|
||||
layout: page
|
||||
---
|
||||
|
||||
# List of HID++ 2.0 features
|
||||
|
||||
## Feature status
|
||||
|
||||
See functions in `hidpp20.py` and `settings_templates.py`
|
||||
|
||||
Feature | ID | Status | Notes
|
||||
---------------------------------------|----------|:------------------:|------
|
||||
`ROOT` | `0x0000` | Supported | System
|
||||
`FEATURE_SET` | `0x0001` | Supported | System
|
||||
`FEATURE_INFO` | `0x0002` | Supported | System
|
||||
`DEVICE_FW_VERSION` | `0x0003` | Supported | `get_firmware`, `get_ids`, read only
|
||||
`DEVICE_UNIT_ID` | `0x0004` | Unsupported |
|
||||
`DEVICE_NAME` | `0x0005` | Supported | `get_kind`, `get_name`, read only
|
||||
`DEVICE_GROUPS` | `0x0006` | Unsupported |
|
||||
`DEVICE_FRIENDLY_NAME` | `0x0007` | Supported | `get_friendly_name`, read only
|
||||
`KEEP_ALIVE` | `0x0008` | Unsupported |
|
||||
`RESET` | `0x0020` | Unsupported | aka “Config Change”
|
||||
`CRYPTO_ID` | `0x0021` | Unsupported |
|
||||
`TARGET_SOFTWARE` | `0x0030` | Unsupported |
|
||||
`WIRELESS_SIGNAL_STRENGTH` | `0x0080` | Unsupported |
|
||||
`DFUCONTROL_LEGACY` | `0x00C0` | Unsupported |
|
||||
`DFUCONTROL_UNSIGNED` | `0x00C1` | Unsupported |
|
||||
`DFUCONTROL_SIGNED` | `0x00C2` | Unsupported |
|
||||
`DFU` | `0x00D0` | Unsupported |
|
||||
`BATTERY_STATUS` | `0x1000` | Supported | `get_battery`, read only
|
||||
`BATTERY_VOLTAGE` | `0x1001` | Supported | `get_voltage`, read only
|
||||
`UNIFIED_BATTERY` | `0x1004` | Supported | `get_battery`, read only
|
||||
`CHARGING_CONTROL` | `0x1010` | Unsupported |
|
||||
`LED_CONTROL` | `0x1300` | Unsupported |
|
||||
`GENERIC_TEST` | `0x1800` | Unsupported |
|
||||
`DEVICE_RESET` | `0x1802` | Unsupported |
|
||||
`OOBSTATE` | `0x1805` | Unsupported |
|
||||
`CONFIG_DEVICE_PROPS` | `0x1806` | Unsupported |
|
||||
`CHANGE_HOST` | `0x1814` | Supported | `ChangeHost`
|
||||
`HOSTS_INFO` | `0x1815` | Partial Support | `get_host_names`, partial listing only
|
||||
`BACKLIGHT` | `0x1981` | Unsupported |
|
||||
`BACKLIGHT2` | `0x1982` | Supported | `Backlight2`
|
||||
`BACKLIGHT3` | `0x1983` | Unsupported |
|
||||
`PRESENTER_CONTROL` | `0x1A00` | Unsupported |
|
||||
`SENSOR_3D` | `0x1A01` | Unsupported |
|
||||
`REPROG_CONTROLS` | `0x1B00` | Unsupported |
|
||||
`REPROG_CONTROLS_V2` | `0x1B01` | Listing Only | `get_keys`
|
||||
`REPROG_CONTROLS_V2_2` | `0x1B02` | Unsupported |
|
||||
`REPROG_CONTROLS_V3` | `0x1B03` | Unsupported |
|
||||
`REPROG_CONTROLS_V4` | `0x1B04` | Partial Support | `ReprogrammableKeys`, `DivertKeys`, `MouseGesture`, `get_keys`
|
||||
`REPORT_HID_USAGE` | `0x1BC0` | Unsupported |
|
||||
`PERSISTENT_REMAPPABLE_ACTION` | `0x1C00` | Supported | `PersistentRemappableAction`
|
||||
`WIRELESS_DEVICE_STATUS` | `0x1D4B` | Read only | status reporting from device
|
||||
`REMAINING_PAIRING` | `0x1DF0` | Unsupported |
|
||||
`FIRMWARE_PROPERTIES` | `0x1F1F` | Unsupported |
|
||||
`ADC_MEASUREMENT` | `0x1F20` | Unsupported |
|
||||
`LEFT_RIGHT_SWAP` | `0x2001` | Unsupported |
|
||||
`SWAP_BUTTON_CANCEL` | `0x2005` | Unsupported |
|
||||
`POINTER_AXIS_ORIENTATION` | `0x2006` | Unsupported |
|
||||
`VERTICAL_SCROLLING` | `0x2100` | Supported | `get_vertical_scrolling_info`, read only
|
||||
`SMART_SHIFT` | `0x2110` | Supported | `SmartShift`
|
||||
`SMART_SHIFT_ENHANCED` | `0x2111` | Supported | `SmartShiftEnhanced`
|
||||
`HI_RES_SCROLLING` | `0x2120` | Supported | `HiResScroll`, `get_hi_res_scrolling_info`
|
||||
`HIRES_WHEEL` | `0x2121` | Supported | `HiresSmoothInvert`, `HiresSmoothResolution`, `get_hires_wheel`
|
||||
`LOWRES_WHEEL` | `0x2130` | Supported | `LowresSmoothScroll`, `get_lowres_wheel_status`
|
||||
`THUMB_WHEEL` | `0x2150` | Supported | `ThumbMode`, `ThumbInvert`
|
||||
`MOUSE_POINTER` | `0x2200` | Supported | `get_mouse_pointer_info`, read only
|
||||
`ADJUSTABLE_DPI` | `0x2201` | Supported | `AdjustableDpi`, `DpiSliding`
|
||||
`POINTER_SPEED` | `0x2205` | Supported | `PointerSpeed`, `SpeedChange`, `get_pointer_speed_info`
|
||||
`ANGLE_SNAPPING` | `0x2230` | Unsupported |
|
||||
`SURFACE_TUNING` | `0x2240` | Unsupported |
|
||||
`HYBRID_TRACKING` | `0x2400` | Unsupported |
|
||||
`FN_INVERSION` | `0x40A0` | Supported | `FnSwap`
|
||||
`NEW_FN_INVERSION` | `0x40A2` | Supported | `NewFnSwap`, `get_new_fn_inversion
|
||||
`K375S_FN_INVERSION` | `0x40A3` | Supported | `K375sFnSwap`
|
||||
`ENCRYPTION` | `0x4100` | Unsupported |
|
||||
`LOCK_KEY_STATE` | `0x4220` | Unsupported |
|
||||
`SOLAR_DASHBOARD` | `0x4301` | Unsupported |
|
||||
`KEYBOARD_LAYOUT` | `0x4520` | Unsupported | read only
|
||||
`KEYBOARD_DISABLE_KEYS` | `0x4521` | Supported | `DisableKeyboardKeys`
|
||||
`KEYBOARD_DISABLE_BY_USAGE` | `0x4522` | Unsupported |
|
||||
`DUALPLATFORM` | `0x4530` | Supported | `Dualplatform`, untested
|
||||
`MULTIPLATFORM` | `0x4531` | Supported | `Multiplatform`
|
||||
`KEYBOARD_LAYOUT_2` | `0x4540` | Unsupported | read only
|
||||
`CROWN` | `0x4600` | Supported | `DivertCrown`, `CrownSmooth`
|
||||
`TOUCHPAD_FW_ITEMS` | `0x6010` | Unsupported |
|
||||
`TOUCHPAD_SW_ITEMS` | `0x6011` | Unsupported |
|
||||
`TOUCHPAD_WIN8_FW_ITEMS` | `0x6012` | Unsupported |
|
||||
`TAP_ENABLE` | `0x6020` | Unsupported |
|
||||
`TAP_ENABLE_EXTENDED` | `0x6021` | Unsupported |
|
||||
`CURSOR_BALLISTIC` | `0x6030` | Unsupported |
|
||||
`TOUCHPAD_RESOLUTION` | `0x6040` | Unsupported |
|
||||
`TOUCHPAD_RAW_XY` | `0x6100` | Unsupported |
|
||||
`TOUCHMOUSE_RAW_POINTS` | `0x6110` | Unsupported |
|
||||
`TOUCHMOUSE_6120` | `0x6120` | Unsupported |
|
||||
`GESTURE` | `0x6500` | Unsupported |
|
||||
`GESTURE_2` | `0x6501` | Partial Support | `Gesture2Gestures`, `Gesture2Params`
|
||||
`GKEY` | `0x8010` | Partial Support | `DivertGkeys`
|
||||
`MKEYS` | `0x8020` | Unsupported |
|
||||
`MR` | `0x8030` | Unsupported |
|
||||
`BRIGHTNESS_CONTROL` | `0x8040` | Unsupported |
|
||||
`REPORT_RATE` | `0x8060` | Supported | `ReportRate`
|
||||
`COLOR_LED_EFFECTS` | `0x8070` | Unsupported |
|
||||
`RGB_EFFECTS` | `0X8071` | Unsupported |
|
||||
`PER_KEY_LIGHTING` | `0x8080` | Unsupported |
|
||||
`PER_KEY_LIGHTING_V2` | `0x8081` | Unsupported |
|
||||
`MODE_STATUS` | `0x8090` | Unsupported |
|
||||
`ONBOARD_PROFILES` | `0x8100` | Unsupported |
|
||||
`MOUSE_BUTTON_SPY` | `0x8110` | Unsupported |
|
||||
`LATENCY_MONITORING` | `0x8111` | Unsupported |
|
||||
`GAMING_ATTACHMENTS` | `0x8120` | Unsupported |
|
||||
`FORCE_FEEDBACK` | `0x8123` | Unsupported |
|
||||
`SIDETONE` | `0x8300` | Unsupported |
|
||||
`EQUALIZER` | `0x8310` | Unsupported |
|
||||
`HEADSET_OUT` | `0x8320` | Unsupported |
|
||||
|
||||
A “read only” note means the feature is a read-only feature.
|
||||
|
||||
## Implementing a feature
|
||||
|
||||
Features are implemented as settable features in
|
||||
lib/logitech_receiver/settings_templates.py
|
||||
some features also have direct implementation in
|
||||
lib/logitech_receiver/hidpp20.py
|
||||
|
||||
In most cases it should suffice to only implement the settable feature
|
||||
interface for each setting in the feature. That will add one or more
|
||||
widgets in the Solaar main window to show and change the setting,
|
||||
will permit storing and restoring changed settings, and
|
||||
will output the feature settings in `solaar show`.
|
||||
|
||||
A setting implementation is a subclass of one of the built-in setting classes
|
||||
illustrated by the pointer speed setting implementation.
|
||||
|
||||
```python
|
||||
class PointerSpeed(_Setting):
|
||||
name = 'pointer_speed'
|
||||
label = _('Sensitivity (Pointer Speed)')
|
||||
description = _('Speed multiplier for mouse (256 is normal multiplier).')
|
||||
feature = _F.POINTER_SPEED
|
||||
validator_class = _RangeV
|
||||
min_value = 0x002e
|
||||
max_value = 0x01ff
|
||||
validator_options = {'byte_count': 2}
|
||||
```
|
||||
|
||||
A setting implementation needs a name, a label, and a description.
|
||||
The name is used in the persistent settings structure to store and restore changed settings and
|
||||
should be a valid Python identifier. (Some older settings have dashes.)
|
||||
The label is displayed in the Solaar main window and the description is used as a tooltip there.
|
||||
The label and description should be specified as translatable strings.
|
||||
A setting implementation for a feature (for modern devices that use the HID++ 2.0 protocol)
|
||||
needs a feature identifier.
|
||||
A setting implementation needs a reader/writer and a validator.
|
||||
|
||||
The reader/writer is resposible for actually writing settings to the device
|
||||
and reading them from the device, writing and reading the byte strings that
|
||||
represent the setting values on the device.
|
||||
For most feature settings the setting implementation can just inherit
|
||||
the standard feature reader/writer, `FeatureRW`.
|
||||
|
||||
Options for `FeatureRW` are supplied by the `rw_options` class variable,
|
||||
which is used to provide command numbers for reading and writing as well
|
||||
as other information needed to identify the parts of the command and reponse
|
||||
that hold the setting value and modify the reading and writing procedure.
|
||||
`PointerSpeed` uses the defaults; here is an example of specifying non-default commands
|
||||
for reading and writing:
|
||||
|
||||
```
|
||||
rw_options = {'read_fnid': 0x10, 'write_fnid': 0x20}
|
||||
```
|
||||
|
||||
Some old devices use registers instead and the setting needs to use the register reader/writer.
|
||||
Only implement a register interface for the setting if you are very brave and
|
||||
you have access to a device that has a register interface for the setting.
|
||||
Register interfaces cannot be auto-discovered and need to be stated in descriptors.py
|
||||
for each device with the register interface.
|
||||
|
||||
The validator instance is responsible for turning raw values read from the device into Python data
|
||||
and Python data into raw values to be written to the device and validating that the Python data is
|
||||
acceptable for the setting.
|
||||
There are several possible kinds of Python data for setting interfaces,
|
||||
ranging from simple toggles, to ranges, to fixed lists, to
|
||||
dynamic choices, to maps of dynamic choices.
|
||||
Pointer speed is a setting whose values are integers in a range so _RangeV validator is used.
|
||||
Arguments to validators are specified as class variables.
|
||||
The _RangeV validator requires the minimum and maximum for the value as separate class variables
|
||||
and the byte size of the value on the device as part of `validator_options`.
|
||||
Splitting the minimum and maximum makes it easier for code that works with
|
||||
settings to determine this information.
|
||||
Settings that are toggles or choices work similarly,
|
||||
but their validators have different arguments.
|
||||
Map settings have more complicated validators and more arguments.
|
||||
|
||||
Settings where the acceptable values are determined from the device
|
||||
subclass the validator and provide a build class method that queries the device
|
||||
and creates an instance of the validator.
|
||||
This method can also return `None`, indicating that even though the
|
||||
device implements the feature it does not usefully support the setting.
|
||||
|
||||
Settings need to be added to the `SETTINGS` list so that setting discovery can be done.
|
||||
|
||||
For more information on implementing feature settings
|
||||
see the comments in lib/logitech_receiver/settings_templates.py.
|
||||
2
docs/hidpp-documentation.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Documentation on HID++ can be found in the Google drive directory
|
||||
https://drive.google.com/drive/folders/0BxbRzx7vEV7eWmgwazJ3NUFfQ28
|
||||
66
docs/i18n.md
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
title: Translating Solaar
|
||||
layout: page
|
||||
---
|
||||
|
||||
# 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 favorite 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 <language>` again. This 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:
|
||||
|
||||
- Chinese (Simplified): [Rongrong][Rongronggg9]
|
||||
- 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]
|
||||
- Slovak: [Jose Riha][jose1711]
|
||||
- Svensk: [Daniel Zippert][zipperten], Emelie Snecker
|
||||
|
||||
[Rongronggg9]: https://github.com/Rongronggg9
|
||||
[papoteur]: http://github.com/papoteur
|
||||
[david-geiger]: http://github.com/david-geiger
|
||||
[damsweb]: http://github.com/damsweb
|
||||
[DJm00n]: https://github.com/DJm00n
|
||||
[jose1711]: https://github.com/jose1711
|
||||
[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/
|
||||
197
docs/index.md
Normal file
@@ -0,0 +1,197 @@
|
||||
---
|
||||
title: Solaar
|
||||
layout: default
|
||||
---
|
||||
|
||||
**Solaar** is a Linux manager for many Logitech keyboards, mice, and trackpads
|
||||
that connect wirelessly to a USB [Unifying][unifying], Bolt, Lightspeed, or Nano receiver,
|
||||
connect directly via a USB cable, or connect via Bluetooth.
|
||||
Solaar does not work with peripherals from other companies.
|
||||
|
||||
Documentation here is for the current version of Solaar.
|
||||
Some Linux distributions distribute old versions of Solaar.
|
||||
If you are using an old version and something described here does not work you should upgrade
|
||||
using one of the methods described below.
|
||||
|
||||
Solaar can be used as a GUI application or via its command-line interface.
|
||||
Both interfaces are able to list the connected devices and
|
||||
show information about each device, often including battery status.
|
||||
Solaar is able to pair and unpair devices with
|
||||
receivers as supported by the device and receiver.
|
||||
Solaar can also control some changeable settings of devices,
|
||||
such as scroll wheel direction and function key behavior.
|
||||
Solaar keeps track of most of these settings on a per-computer basis,
|
||||
because devices forget most settings when powered down,
|
||||
and the GUI application restores them whenever a device connects.
|
||||
For more information on how to use Solaar see
|
||||
[the usage page](https://pwr-solaar.github.io/Solaar/usage),
|
||||
and for more information on its capabilities see
|
||||
[the capabilities page](https://pwr-solaar.github.io/Solaar/capabilities).
|
||||
|
||||
|
||||
Solaar's GUI normally uses an icon in the system tray and starts with its main window visible.
|
||||
This aspect of Solaar depends on having an active system tray, which is not the default
|
||||
situation for recent versions of Gnome. For information on to set up a system tray under Gnome see
|
||||
[the capabilities page](https://pwr-solaar.github.io/Solaar/capabilities).
|
||||
|
||||
Solaar's GUI can be started in several ways
|
||||
|
||||
- `--window=show` (the default) starts with its main window visible,
|
||||
- `--window=hide` starts with its main window hidden,
|
||||
- `--window=only` does not use the system tray, and starts with main window visible.
|
||||
|
||||
For more information on Solaar's command-line interface use the help option,
|
||||
as in `solaar --help`.
|
||||
|
||||
Solaar does not process normal input from devices. It 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.1. 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 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 strangely 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 supported Unifying, Bolt, Lightspeed, or Nano
|
||||
receivers, and at the very least display some basic information about them.
|
||||
Solaar will detect some Logitech devices that connect via a USB cable or Bluetooth.
|
||||
|
||||
Solaar can pair and unpair a Logitech device showing the Unifying logo
|
||||
(Solaar's version of the [logo][logo])
|
||||
with any Unifying receiver,
|
||||
and pair and unpair a Logitech device showing the Bolt logo
|
||||
with any Bolt receiver,
|
||||
and
|
||||
can pair and unpair Lightspeed devices with Lightspeed receivers for the same model.
|
||||
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 or Bolt logo
|
||||
generally cannot be paired with Unifying or Bolt receivers.
|
||||
|
||||
Solaar does not handle connecting or disconnecting via Bluetooth,
|
||||
which is done using the usual Bluetooth mechanisms.
|
||||
|
||||
For a partial list of supported devices
|
||||
and their features, see [the devices page](https://pwr-solaar.github.io/Solaar/devices).
|
||||
|
||||
[logo]: https://pwr-solaar.github.io/Solaar/assets/solaar.svg
|
||||
|
||||
## Prebuilt packages
|
||||
|
||||
Up-to-date prebuilt packages are available for some Linux distros
|
||||
(e.g., Fedora 33+) in their standard repositories.
|
||||
If a recent version of Solaar is not
|
||||
available from the standard repositories for your distribution you can try
|
||||
one of these packages.
|
||||
|
||||
- Arch solaar package in the [community repository][arch]
|
||||
- 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 [Gentoo package][gentoo], courtesy of Carlos Silva and Tim Harder
|
||||
- a [Mageia package][mageia], courtesy of David Geiger
|
||||
|
||||
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/
|
||||
[gentoo]: https://packages.gentoo.org/packages/app-misc/solaar
|
||||
[mageia]: http://mageia.madb.org/package/show/release/cauldron/application/0/name/solaar
|
||||
[universe repository]: http://packages.ubuntu.com/search?keywords=solaar&searchon=names&suite=all§ion=all
|
||||
|
||||
## Manual installation
|
||||
|
||||
See [the installation page](https://pwr-solaar.github.io/Solaar/installation)
|
||||
for the step-by-step procedure for manual installation.
|
||||
|
||||
## Known Issues
|
||||
|
||||
- If some icons appear broken in the application, make sure you've properly
|
||||
configured the Gtk theme and icon theme in your control panel.
|
||||
|
||||
- Solaar normally uses icon names for its icons, which in some system tray implementatations
|
||||
results in missing or wrong-sized icons.
|
||||
The `--tray-icon-size` option forces Solaar to use icon files of appropriate size
|
||||
for tray icons instead, which produces better results in some system tray implementatations.
|
||||
To use icon files close to 32 pixels in size use `--tray-icon-size=32`.
|
||||
|
||||
- The icon in the system tray can show up as 'black on black' in dark
|
||||
themes or as non-symbolic when the theme uses symbolic icons. This is due to problems
|
||||
in some system tray implementations. Changing to a different theme may help.
|
||||
The `--battery-icons=symbolic` option can be used to force symbolic icons.
|
||||
|
||||
- Sometimes the system tray icon does not show up. The cause of this is unknown.
|
||||
Either wait a while and try again or try with the `--window=hide` option.
|
||||
|
||||
- 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.
|
||||
|
||||
- Some Linux drivers view or modify the setting Scroll Wheel Resolution to
|
||||
implement smooth scrolling. If Solaar changes this setting after the driver is
|
||||
set up scrolling can be either very fast or very slow. To fix this problem
|
||||
click on the icon at the right edge of the setting to set it to
|
||||
"Ignore this setting".
|
||||
The mouse has to be reset (e.g., by turning it off and on again) before this fix will take effect.
|
||||
|
||||
- Many gaming mice and keyboards have the ONBOARD PROFILES feature.
|
||||
This feature can override other features, including polling rate and key lighting.
|
||||
To make the Polling Rate and M-Key LEDs settings effective the Onboard Profiles setting has to be disabled.
|
||||
This may have other effects, such as turning off backlighting.
|
||||
|
||||
- Solaar will try to use uinput to simulate input from rules if Xtest is not available
|
||||
but this needs write permission on /dev/uinput.
|
||||
For more information see [the rules page](https://pwr-solaar.github.io/Solaar/rules).
|
||||
|
||||
|
||||
## Contributing to Solaar
|
||||
|
||||
Conributions to Solaaar are very welcome.
|
||||
|
||||
Solaar has complete or partial translations of its GUI strings into several languages.
|
||||
If you want to update a translation or add a new one see
|
||||
[the translation page](https://pwr-solaar.github.io/Solaar/i18n) for moe information.
|
||||
|
||||
If you find a bug and have a fix for it, please open a bug issue and also a GitHub pull request.
|
||||
Label your commits using the naming conventions in recent commits to Solaar.
|
||||
If you want to enhance Solaar open an enhancement issue to discuss your proposal.
|
||||
There are also usually several open issues for enhancements that have already been requested.
|
||||
|
||||
|
||||
## 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.
|
||||
113
docs/installation.md
Normal file
@@ -0,0 +1,113 @@
|
||||
---
|
||||
title: Manual Installation
|
||||
layout: page
|
||||
---
|
||||
|
||||
# Manual installation
|
||||
|
||||
## Downloading
|
||||
|
||||
Clone Solaar from GitHub by `git clone https://github.com/pwr-Solaar/Solaar.git`
|
||||
|
||||
## Requirements for 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 with kernel modules `hid-logitech-dj`
|
||||
and `hid-logitech-hidpp` loaded.
|
||||
Most of Solaar should work fine with any kernel more recent than 5.2,
|
||||
but newer kernels might be needed for some devices to be correctly recognized and handled.
|
||||
The `udev` package must be installed and its daemon running.
|
||||
|
||||
Solaar requires Python 3.6+ and requires several packages to be installed.
|
||||
If you are running the system version of Python you should have the
|
||||
`python3-pyudev`, `python3-psutil`, `python3-xlib`, `python3-evdev`,
|
||||
and `python3-yaml` or `python3-pyyaml` packages installed.
|
||||
To run the GUI Solaar also requires Gtk3 and its GObject introspection bindings.
|
||||
If you are running the system version of Python
|
||||
the Debian/Ubuntu packages you should have
|
||||
`python3-gi` and `gir1.2-gtk-3.0` installed.
|
||||
in Fedora you need `gtk3` and `python3-gobject`.
|
||||
You may have to install `gcc` and the Python development package (`python3-dev` or `python3-devel`,
|
||||
depending on your distribution).
|
||||
|
||||
If you are running a version of Python different from the system version,
|
||||
you may need to use pip to install projects that provide the above Python packages.
|
||||
|
||||
If desktop notifications bindings are also installed
|
||||
(`gir1.2-notify-0.7` for Debian/Ubuntu),
|
||||
you will also see 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 HID devices for receivers and devices.
|
||||
To be able to do this without running as root requires a udev rule
|
||||
that gives seated users write access to the HID devices for Logitech receiver and devices.
|
||||
|
||||
You can install this rule by copying, as root,
|
||||
`rules.d/42-logitech-unify-permissions.rules` from Solaar to
|
||||
`/etc/udev/rules.d`.
|
||||
You will probably also have to tell udev to reload its rule via
|
||||
`sudo udevadm control --reload-rules`.
|
||||
|
||||
For this rule to set up the correct permissions for your receivers and devices
|
||||
you will then need to either disconnect your receivers and
|
||||
any USB-connected or Bluetooth-connected devices and
|
||||
re-connect them or reboot your computer.
|
||||
|
||||
## Running from the Download Directories
|
||||
|
||||
To run Solaar from the download directories, first install the Solaar udev rule if necessary.
|
||||
Then cd to the solaar directory and run `bin/solaar` for the GUI
|
||||
or `bin/solaar <command> <arguments>` for the CLI.
|
||||
|
||||
Do not run Solaar as root, you may encounter problems with X11 integration and with the system tray.
|
||||
|
||||
## Installing Solaar Using Pip
|
||||
|
||||
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.)
|
||||
Once the udev rule has been installed you can then run Solaar as `~/.local/bin/solaar`.
|
||||
|
||||
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.)
|
||||
Then solaar can be run as /usr/local/bin/solaar.
|
||||
You will also have to install the udev rule.
|
||||
|
||||
[pip]: https://en.wikipedia.org/wiki/Pip_(package_manager)
|
||||
|
||||
## Solaar in other languages
|
||||
|
||||
If you want to have Solaar's user messages in some other language you need to run
|
||||
`tools/po-compile.sh` to create the translation files before running or installing Solaar
|
||||
and set the LANGUAGE environment variable appropriately when running Solaar.
|
||||
|
||||
## Running Solaar at Startup
|
||||
|
||||
Distributions can cause Solaar can be run automatically at user login by installing a desktop file at
|
||||
`/etc/xdg/autostart/solaar.desktop`. An example of this file content can be seen in the repository at
|
||||
[share/autostart/solaar.desktop](https://github.com/pwr-Solaar/Solaar/blob/master/share/autostart/solaar.desktop).
|
||||
|
||||
If you install Solaar yourself you may need to create or modify this file or install a startup file under your home directory.
|
||||
|
||||
## Installing from 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`.
|
||||
This will not install the Solaar udev rule, which you will need to copy from
|
||||
`~/.local/share/solaar/udev-rules.d/42-logitech-unify-permissions.rules`
|
||||
to `/etc/udev/rules.d` as root.
|
||||
240
docs/rules.md
Normal file
@@ -0,0 +1,240 @@
|
||||
---
|
||||
title: Rule Processing of HID++ Notifications
|
||||
layout: page
|
||||
---
|
||||
|
||||
Creating and editing most rules can be done in the Solaar GUI, by pressing the 'Rule Editor' button in the
|
||||
Solaar main window.
|
||||
|
||||
Rule processing is an experimental feature. Significant changes might be made in response to problems.
|
||||
|
||||
*Note that rule processing only fully works under X11.
|
||||
When running under Wayland with X11 libraries loaded some features will not be available.
|
||||
When running under Wayland without X11 libraries loaded even more features will not be available.
|
||||
Rule features known not to work under Wayland include process and mouse process conditions.
|
||||
Under Wayland using keyboard groups may result in incorrect symbols being input for simulated input.
|
||||
Under Wayland simulating inputs when modifier keys are pressed may result in incorrect symbols being input.
|
||||
Simulated input uses Xtest if available or uinput if the user has write access to /dev/uinput.
|
||||
To get access to /dev/uinput run `sudo setfacl -m u:${user}:rw /dev/uinput`*
|
||||
|
||||
Logitech devices that use HID++ version 2.0 or greater produce feature-based
|
||||
notifications that Solaar can process using a simple rule language. For
|
||||
example, using rules Solaar can emulate an `XF86_MonBrightnessDown` key tap
|
||||
in response to the pressing of the `Brightness Down` key on Craft keyboards,
|
||||
which normally does not produce any input at all when the keyboard is in
|
||||
Windows mode.
|
||||
|
||||
Solaar's rules only trigger on HID++ notifications so device actions that
|
||||
normally produce HID output have to be first be set (diverted) to
|
||||
produce HID++ notifications instead of their normal behavior.
|
||||
Currently Solaar can divert some mouse scroll wheels, some
|
||||
mouse thumb wheels, the crown of Craft keyboards, and some keys and buttons.
|
||||
If the scroll wheel, thumb wheel, crown, key, or button is
|
||||
not diverted by setting the appropriate setting then no HID++ notification is
|
||||
generated and rules will not be triggered by manipulating the wheel, crown, key, or button.
|
||||
Look for `HID++` or `Diversion` settings to see what
|
||||
diversion can be done with your devices.
|
||||
|
||||
Running Solaar with the `-ddd`
|
||||
option will show information about notifications, including their feature
|
||||
name, report number, and data.
|
||||
|
||||
Solaar can also create special notifications in response to mouse movements on some mice.
|
||||
Setting the `Mouse Gestures` setting to a key enables special processing of mouse movements
|
||||
while the key is depressed. Moving the mouse creates a mouse movement event.
|
||||
Stopping the mouse for a little while and moving it again creates another mouse movement event.
|
||||
Pressing a diverted key creates a key event.
|
||||
When the key is released the sequence of events is sent as a synthetic notification
|
||||
that can be matched with `Mouse Gesture` conditions.
|
||||
|
||||
In response to a feature-based HID++ notification Solaar runs a sequence of
|
||||
rules. A `Rule` is a sequence of components, which are either sub-rules,
|
||||
conditions, or actions. Conditions and actions are dictionaries with one
|
||||
entry whose key is the name of the condition or action and whose value is
|
||||
the argument of the action.
|
||||
|
||||
If the last thing that a rule does is execute an action, no more rules are
|
||||
processed for the notification.
|
||||
|
||||
Rules are evaluated by evaluating each of their components in order. The
|
||||
evaluation of a rule is terminated early if a condition component evaluates
|
||||
to false or the last evaluated sub-component of a component is an action. A
|
||||
rule is false if its last evaluated component evaluates to a false value.
|
||||
|
||||
`Not` conditions take a single component and are true if their component
|
||||
evaluates to a false value.
|
||||
`Or` conditions take a sequence of components and are evaluated by
|
||||
evaluating each of their components in order.
|
||||
An Or condition is terminated early if a component evaluates to true or the
|
||||
last evaluated sub-component of a component is an action.
|
||||
A Or condition is true if its last evaluated component evaluates to a true
|
||||
value. `And` conditions take a sequence of components are evaluted the same
|
||||
as rules.
|
||||
|
||||
`Feature` conditions are if true if the name of the feature of the current
|
||||
notification is their string argument.
|
||||
`Report` conditions are if true if the report number in the current
|
||||
notification is their integer argument.
|
||||
|
||||
`Key` conditions are true if the Logitech name of the last diverted key or button pressed is their
|
||||
string argument. Alternatively, if the argument is a list `[name, action]` where `action`
|
||||
is either `'pressed'` or `'released'`, the key down or key up events of `name` argument are
|
||||
matched, respectively. Logitech key and button names are shown in the `Key/Button Diversion`
|
||||
setting. Some keyboards have Gn, Mn, or MR keys, which are diverted using the 'Divert G Keys' setting.
|
||||
|
||||
`Modifiers` conditions take either a string or a sequence of strings, which
|
||||
can only be `Shift`, `Control`, `Alt`, and `Super`.
|
||||
Modifiers conditions are true if their argument is the current keyboard
|
||||
modifiers.
|
||||
|
||||
`Process` conditions are true if the process for focus input window
|
||||
or the window's Window manager class or instance name starts with their string argument.
|
||||
`MouseProcess` conditions are true if the process for the window under the mouse
|
||||
or the window's Window manager class or instance name starts with their string argument.
|
||||
|
||||
`Setting` conditions checks the value of a Solaar setting on a device.
|
||||
`Setting` conditions take three or four arguments, depending on the setting:
|
||||
the Serial number or Unit ID of a device, as shown in Solaar's detail pane,
|
||||
or null for the device that initiated rule processing;
|
||||
the internal name of a setting (which can be found from solaar config <device>);
|
||||
one or two arguments for the setting.
|
||||
For settings that use keys or buttons as an argument the Logtech name can be used
|
||||
as shown in the Solaar main window for these settings,
|
||||
or the numeric value for the key or button.
|
||||
For settings that use gestures as an argument the internal name of the gesture is used,
|
||||
which can be found in the GESTURE2_GESTURES_LABELS structure in lib/logitech_receiver/settings_templates.
|
||||
For settings that need one of a set of names as an argument the name can be used or its internal integer value,
|
||||
as used in the Solaar config file.
|
||||
|
||||
`Test` and `TestBytes` conditions are true if their test evaluates to true on the feature,
|
||||
report, and data of the current notification.
|
||||
`TestBytes` conditions can return a number instead of a boolean.
|
||||
|
||||
`TestBytes` conditions consist of a sequence of three or four integers and use the first
|
||||
two to select bytes of the notification data.
|
||||
Writing this kind of test condition is not trivial.
|
||||
Three-element `TestBytes` conditions are true if the selected bytes bit-wise anded
|
||||
with its third element is non-zero.
|
||||
The value of these test conditions is the result of the and.
|
||||
Four-element `TestBytes` conditions are true if the selected bytes form a signed
|
||||
integer between the third and fourth elements.
|
||||
The value of these conditions is the signed value of the selected bytes
|
||||
if that is non-zero otherwise True.
|
||||
|
||||
`Test` conditions are mnemonic shorthands for meaningful feature,
|
||||
report, and data combinations in notifications.
|
||||
A `crown_right` test is the rotation amount of a `CROWN` right rotation notification.
|
||||
A `crown_left` test is the rotation amount of a `CROWN` left rotation notification.
|
||||
A `crown_right_ratchet` test is the ratchet amount of a `CROWN` right ratchet rotation notification.
|
||||
A `crown_left_ratchet` test is the ratchet amount of a `CROWN` left ratchet rotation notification.
|
||||
A `crown_tap` test is true for a `CROWN` tap notification.
|
||||
A `crown_start_press` test is true for the start of a `CROWN` press notification.
|
||||
A `crown_stop_press` test is true for the end of a `CROWN` press notification.
|
||||
A `crown_pressed` test is true for a `CROWN` notification with the Crown pressed.
|
||||
A `thumb_wheel_up` test is the rotation amount of a `THUMB WHEEL` upward rotation notification.
|
||||
A `thumb_wheel_down` test is the rotation amount of a `THUMB WHEEL` downward rotation notification.
|
||||
`lowres_wheel_up`, `lowres_wheel_down`, `hires_wheel_up`, `hires_wheel_down` are the
|
||||
same but for `LOWRES WHEEL` and `HIRES WHEEL`.
|
||||
`True` and `False` tests return True and False, respectively.
|
||||
|
||||
`Mouse Gesture` conditions are true if the actions taken while the mouse's 'Gesture' button is held match the configured list when the 'Gesture' button is released.
|
||||
The available actions are `Mouse Up`, `Mouse Down`, `Mouse Left`, `Mouse Right`, `Mouse Up-left`, `Mouse Up-Right`, `Mouse Down-left`, `Mouse Down-right`, and buttons that are diverted.
|
||||
An example would be mapping `Mouse Up` -> `Mouse Up`. To perform this gesture, you would hold down the 'Gesture' button, move the mouse upwards, pause momentarily, move the mouse upwards, and release the 'Gesture' button.
|
||||
Another example would be mapping `Back Button` -> `Back Button`. With this one, you would hold down the 'Gesture' button, double-tap the 'Back' button, and then release the 'Gesture' button.
|
||||
Mouse movements and buttons can be mixed and chained together however you like.
|
||||
It's possible to create a `No-op` gesture by clicking 'Delete' on the initial Action when you first create the rule. This gesture will trigger when you simply click the 'Gesture' button.
|
||||
|
||||
`Setting` conditions check device settings of devices, provided the device is on-line.
|
||||
The first arguments to the condition are the Serial number or Unit ID of a device, as shown in Solaar's detail pane,
|
||||
or null for the device that initiated rule processing; and
|
||||
the internal name of a setting (which can be found from solaar config <device>).
|
||||
Most simple settings take one extra argument, the value to check the setting value against.
|
||||
Range setting can also take two arguments, which form an inclusive range to check against.
|
||||
Other settings take two arguments, a key indicating which sub-setting to check and the value to check it against.
|
||||
For settings that use gestures as an argument the internal name of the gesture is used,
|
||||
which can be found in the GESTURE2_GESTURES_LABELS structure in lib/logitech_receiver/settings_templates.
|
||||
For boolean settings '~' can be used to toggle the setting.
|
||||
|
||||
A `KeyPress` action takes a sequence of X11 key symbols and simulates a chorded keypress on the keyboard, such as "A", "Shift+A", or "Control+A".
|
||||
Any key symbols that correspond to modifier keys that are in the current keyboard modifiers are ignored.
|
||||
Use separate `KeyPress` actions for multiple characters.
|
||||
A `MouseScroll` action takes a sequence of two numbers and simulates a horizontal and vertical mouse scroll of these amounts.
|
||||
If the previous condition in the parent rule returns a number the scroll amounts are multiplied by this number.
|
||||
A `MouseClick` action takes a mouse button name (`left`, `middle` or `right`) and a positive number, and simulates that number of clicks of the specified button.
|
||||
An `Execute` action takes a program and arguments and executes it asynchronously.
|
||||
|
||||
A `Set` action changes a Solaar setting for a device, provided that the device is on-line.
|
||||
`Set` actions take three or four arguments, depending on the setting.
|
||||
The first two are the Serial number or Unit ID of a device, as shown in Solaar's detail pane,
|
||||
or null for the device that initiated rule processing; and
|
||||
the internal name of a setting (which can be found from solaar config <device>).
|
||||
Simple settings take one extra argument, the value to set the setting to.
|
||||
For boolean settings '~' can be used to toggle the setting.
|
||||
Other simple settings take two extra arguments, a key indicating which sub-setting to set and the value to set it to.
|
||||
For settings that use gestures as an argument the internal name of the gesture is used,
|
||||
which can be found in the GESTURE2_GESTURES_LABELS structure in lib/logitech_receiver/settings_templates.
|
||||
All settings are supported.
|
||||
|
||||
Solaar has several built-in rules, which are run after user-created rules and so can be overridden by user-created rules.
|
||||
One rule turns
|
||||
`Brightness Down` key press notifications into `XF86_MonBrightnessDown` key taps
|
||||
and `Brightness Up` key press notifications into `XF86_MonBrightnessUp` key taps.
|
||||
Another rule makes Craft crown ratchet movements move between tabs when the crown is pressed
|
||||
and up and down otherwise.
|
||||
A third rule turns Craft crown ratchet movements into `XF86_AudioNext` or `XF86_AudioPrev` key taps when the crown is pressed and `XF86_AudioRaiseVolume` or `XF86_AudioLowerVolume` otherwise.
|
||||
A fourth rule doubles the speed of `THUMB WHEEL` movements unless the `Control` modifier is on.
|
||||
All of these rules are only active if the key or feature is diverted, of course.
|
||||
|
||||
Solaar reads rules from a YAML configuration file (normally `~/.config/solaar/rules.yaml`).
|
||||
This file contains zero or more documents, each a rule.
|
||||
|
||||
Here is a file with six rules:
|
||||
|
||||
```
|
||||
%YAML 1.3
|
||||
---
|
||||
- Key: [M2, pressed]
|
||||
- Set: [198E3EB8, dpi, 3000]
|
||||
- Execute: [notify-send, Incresed mouse speed]
|
||||
...
|
||||
---
|
||||
- Key: [Host Switch Channel 2, pressed]
|
||||
- Set: [43DAF041, change-host, 1]
|
||||
- Set: [198E3EB8, change-host, 1]
|
||||
- Execute: [notify-send, Switched to host 2]
|
||||
...
|
||||
---
|
||||
- MouseGesture: [Mouse Up, Mouse Down]
|
||||
- Execute: [notify-send, Locking]
|
||||
- Execute: xflock4
|
||||
...
|
||||
- Feature: CROWN
|
||||
- Process: quodlibet
|
||||
- Rule: [ Test: crown_start_press, KeyPress: XF86_AudioMute ]
|
||||
- Rule: [ Test: crown_pressed, Test: crown_right_ratchet, KeyPress: XF86_AudioNext ]
|
||||
- Rule: [ Test: crown_pressed, Test: crown_left_ratchet, KeyPress: XF86_AudioPrev ]
|
||||
- Rule: [ Test: crown_right_ratchet, KeyPress: XF86_AudioRaiseVolume ]
|
||||
- Rule: [ Test: crown_left_ratchet, KeyPress: XF86_AudioLowerVolume ]
|
||||
...
|
||||
---
|
||||
- Feature: THUMB WHEEL
|
||||
- Rule: [ Modifiers: Control, Test: thumb_wheel_up, MouseScroll: [-2, 0] ]
|
||||
- Rule:
|
||||
- Modifiers: Control
|
||||
- Test: thumb_wheel_down
|
||||
- MouseScroll: [-2, 0]
|
||||
- Rule: [ Or: [ Test: thumb_wheel_up, Test: thumb_wheel_down ], MouseScroll: [-1, 0] ]
|
||||
...
|
||||
---
|
||||
- Feature: LOWRES WHEEL
|
||||
- Rule: [ Or: [ Test: lowres_wheel_up, Test: lowres_wheel_down ], MouseScroll: [0, 2] ]
|
||||
...
|
||||
```
|
||||
|
||||
Here is an example showing how to divert the Back Button on an MX Master 3 so that pressing
|
||||
the button will initiate rule processing and a rule that triggers on this notification and
|
||||
switches the mouse to host 3 after popping up a simple notification.
|
||||
|
||||

|
||||
|
||||

|
||||
176
docs/usage.md
Normal file
@@ -0,0 +1,176 @@
|
||||
---
|
||||
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 are no devices with battery information,
|
||||
then the icon is one of the Solaar icons.
|
||||
|
||||
Solaar also has a main window. When the main window is invisible,
|
||||
click on the icon in the system tray to bring up the menu, and then
|
||||
click on a receiver or device in the menu to see information about
|
||||
that receiver or device.
|
||||
|
||||
The following is an image of the Solaar menu and the icon (the battery
|
||||
symbol is in the system tray at the left of the image). The icon can
|
||||
also be other battery icons or versions of the Logitech Unifying icon.
|
||||
|
||||

|
||||
|
||||
Clicking on “Quit” in the Solaar menu terminates the program, and “About Solaar” pops up a window with further information.
|
||||
|
||||
## 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 the program, and “About Solaar” pops up a window with further information.
|
||||
The light bulb (or a similar icon) displays detailed information
|
||||
about the selected receiver or device (useful for debugging).
|
||||
|
||||
### Pairing and unpairing devices
|
||||
|
||||
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
|
||||
and the device is not already paired with another active receiver.
|
||||
For multi-host devices first select the host position that you want.
|
||||
Bolt devices and some Lightspeed devices pair by pressing a special pairing button.
|
||||
To pair with a Bolt receiver you have to type a passcode followed by enter
|
||||
or click the left and right buttons in the correct sequence followed by
|
||||
clicking both buttons simultaneously.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||
A receiver with the Unifying logo should be able to pair with any device
|
||||
with the Unifying logo
|
||||
and a receiver with the Bolt logo should be able to pair with any device
|
||||
with the Bolt logo.
|
||||
If there are no open pairing slots, however, you will
|
||||
not be able to pair a new device. In this case to pair a new device you
|
||||
first need to unpair a device.
|
||||
|
||||
Other receivers can only pair with certain kinds of devices.
|
||||
Most of these receivers do not allow unpairing - instead
|
||||
pairing a new device replaces an existing paired device of the same kind.
|
||||
Some receivers can only pair a limited number of times.
|
||||
|
||||
### Viewing and changing device settings
|
||||
|
||||
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 and change the settings of devices.
|
||||
Changing settings is performed by clicking on buttons,
|
||||
moving sliders, or selecting from alternatives.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Device setings now have a clickable icon that determines whether the
|
||||
setting can be changed and whether the setting is ignored.
|
||||
|
||||

|
||||
|
||||
If the selected device that is paired with a receiver is powered down or
|
||||
otherwise disconnected its settings cannot be changed
|
||||
but it still can be unpaired if its receiver allows unpairing.
|
||||
|
||||

|
||||
|
||||
If a device is paired with a receiver but directly connected via USB or Bluetooth
|
||||
the receiver pairing will show up as well as the direct connection.
|
||||
The device can only be manipulated using the direct connection.
|
||||
|
||||

|
||||
|
||||
#### Remapping key and button actions
|
||||
|
||||
For many devices Solaar can remap some of their keys or buttons to
|
||||
perform a different action. (This changes the information that the
|
||||
device sends when the key or button is activated.) Only some keys on some
|
||||
devices can be remapped and they can only be remapped to a limited
|
||||
number of actions. The remapping is done by selecting a key
|
||||
or button in the left-hand box on the “Action” setting line and then
|
||||
selecting the action to be performed in the right-hand box. The default
|
||||
action is always the shown first in the list. As with all settings,
|
||||
Solaar will remember past action settings and restore them on the device
|
||||
from then on.
|
||||
|
||||

|
||||
|
||||
The names of the keys, buttons, and actions are mostly taken from Logitech
|
||||
documentation and may not be completely obvious.
|
||||
|
||||
It is possible to end up with an unusable system, for example by having no
|
||||
way to do a mouse left click, so exercise caution when remapping keys or
|
||||
buttons that are needed to operate your system.
|
||||
|
||||
## Solaar command line interface
|
||||
|
||||
Solaar also has a command line interface that can do most of what can be
|
||||
done using the main window. For more information on the
|
||||
command line interface, run `solaar --help` to see the commands and
|
||||
then `solaar <command> --help` to see the arguments to any of the commands.
|
||||
|
||||
## Solaar settings
|
||||
|
||||
Solaar supports at least the following settings:
|
||||
|
||||
Setting | Description
|
||||
---------------------------------|------------
|
||||
Hand Detection | Turn on backlight when your hands hover over the keyboard
|
||||
Scroll Wheel Smooth Scrolling | Higher-speed vertical scrolling
|
||||
Side Scrolling | When off, side scrolling sends custom button events
|
||||
Scroll Wheel High Resolution | Higher-speed vertical scrolling
|
||||
Scroll Wheel HID++ Scrolling | When on, vertical scrolling uses HID++ events
|
||||
Scroll Wheel Direction | Reverse direction of vertical scrolling
|
||||
Scroll Wheel Resolution | Higher-speed vertical scrolling (use with caution)
|
||||
Scroll Wheel Rachet | Shift wheel ratchet on and off based on wheel speed
|
||||
Thumb Wheel HID++ Scrolling | When on, thumb-wheel scrolling uses HID++ events
|
||||
Thumb Wheel Direction | Reverse direction of thumb-wheel scrolling
|
||||
Sensitivity (DPI) | Mouse movement sensitivity
|
||||
Sensitivity (Pointer Speed) | Mouse movement sensitivity
|
||||
Backlight | Turn on backlight
|
||||
Swap Fx function | Change Fn keys to normally do their special action
|
||||
DPI Sliding Adjustment | Change Sensitivity (DPI) by holding a button and moving the mouse
|
||||
Mouse Gestures | Create HID++ events by holding a button and moving the mouse
|
||||
Key/Button Actions | Change what a key or button does
|
||||
Key/Button Diversion | Divert keys and buttons to create HID++ events
|
||||
Divert crown events | Divert crown actions to create HID++ events
|
||||
Divert G Keys | Divert G keys to create HID++ events
|
||||
Disable keys | Disable one or more keys
|
||||
Set OS | Change keys to match OS
|
||||
Change Host | Connect to a different host
|
||||
Gestures | Turn on and off various (mostly touchpad) gestures
|
||||
Gesture params | Modify parameters for gestures
|
||||
|
||||
HID++ events are mostly not processed by Linux input drivers.
|
||||
Settings that involve sending HID++ events exist so that these events can be
|
||||
processed by Solaar rules instead of by Linux.
|
||||
|
||||
Different Logitech devices may implement the same functionality in different ways,
|
||||
thus the different settings that do the same thing.
|
||||
429
docs/usb.ids.txt
Normal 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
|
After Width: | Height: | Size: 96 B |
BIN
jekyll/images/blacktocat.png
Normal file
|
After Width: | Height: | Size: 432 B |
BIN
jekyll/images/icon_download.png
Normal file
|
After Width: | Height: | Size: 230 B |
BIN
jekyll/images/sprite_download.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
@@ -1,10 +1,33 @@
|
||||
# -*- python-mode -*-
|
||||
|
||||
## 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."""
|
||||
|
||||
__author__ = "Daniel Pavel"
|
||||
__license__ = "GPL"
|
||||
__version__ = "0.4"
|
||||
from hidapi.udev import close # noqa: F401
|
||||
from hidapi.udev import enumerate # noqa: F401
|
||||
from hidapi.udev import find_paired_node # noqa: F401
|
||||
from hidapi.udev import find_paired_node_wpid # noqa: F401
|
||||
from hidapi.udev import get_manufacturer # noqa: F401
|
||||
from hidapi.udev import get_product # noqa: F401
|
||||
from hidapi.udev import get_serial # noqa: F401
|
||||
from hidapi.udev import monitor_glib # noqa: F401
|
||||
from hidapi.udev import open # noqa: F401
|
||||
from hidapi.udev import open_path # noqa: F401
|
||||
from hidapi.udev import read # noqa: F401
|
||||
from hidapi.udev import write # noqa: F401
|
||||
|
||||
try:
|
||||
from hidapi.udev import *
|
||||
except ImportError:
|
||||
from hidapi.native import *
|
||||
__version__ = '0.9'
|
||||
|
||||
@@ -1,109 +1,268 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- python-mode -*-
|
||||
|
||||
## 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.
|
||||
|
||||
import os
|
||||
import sys
|
||||
from select import select as _select
|
||||
import time
|
||||
from binascii import hexlify, unhexlify
|
||||
_hex = lambda d: hexlify(d).decode('ascii').upper()
|
||||
|
||||
from binascii import hexlify, unhexlify
|
||||
from select import select as _select
|
||||
from threading import Lock
|
||||
|
||||
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
|
||||
prompt = '?? Input: ' if interactive else ''
|
||||
start_time = time.time()
|
||||
|
||||
strhex = lambda d: hexlify(d).decode('ascii').upper()
|
||||
try:
|
||||
read_packet = raw_input
|
||||
except:
|
||||
read_packet = input
|
||||
unicode # noqa: F821
|
||||
# this is certanly Python 2
|
||||
is_string = lambda d: isinstance(d, unicode) # noqa: F821
|
||||
# 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 Exception:
|
||||
# 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)
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
print_lock = Lock()
|
||||
del Lock
|
||||
|
||||
|
||||
def _print(marker, data, scroll=False):
|
||||
t = time.time() - start_time
|
||||
t = time.time() - start_time
|
||||
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))
|
||||
|
||||
if interactive and scroll:
|
||||
sys.stdout.write('\033[s')
|
||||
sys.stdout.write('\033[S') # scroll up
|
||||
sys.stdout.write('\033[A\033[L\033[G') # insert new line above the current one, position on first column
|
||||
with print_lock:
|
||||
# allow only one thread at a time to write to the console, otherwise
|
||||
# the output gets garbled, especially with ANSI codes.
|
||||
|
||||
hexs = _hex(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))
|
||||
sys.stdout.write(s)
|
||||
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:
|
||||
sys.stdout.write('\033[u')
|
||||
else:
|
||||
sys.stdout.write('\n')
|
||||
# flush stdout manually...
|
||||
# because trying to open stdin/out unbuffered programmatically
|
||||
# works much too differently in Python 2/3
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def _continuous_read(handle, timeout=1000):
|
||||
while True:
|
||||
reply = hidapi.read(handle, 128, timeout)
|
||||
if reply is None:
|
||||
print ("!! Read failed, aborting")
|
||||
break
|
||||
elif reply:
|
||||
_print('>>', reply, True)
|
||||
def _error(text, scroll=False):
|
||||
_print('!!', text, scroll)
|
||||
|
||||
|
||||
def _continuous_read(handle, timeout=2000):
|
||||
while True:
|
||||
try:
|
||||
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)
|
||||
|
||||
|
||||
def _validate_input(line, hidpp=False):
|
||||
try:
|
||||
data = unhexlify(line.encode('ascii'))
|
||||
except Exception as e:
|
||||
_error('Invalid input: ' + str(e))
|
||||
return None
|
||||
|
||||
if hidpp:
|
||||
if len(data) < 4:
|
||||
_error('Invalid HID++ request: need at least 4 bytes')
|
||||
return None
|
||||
if data[:1] not in b'\x10\x11':
|
||||
_error('Invalid HID++ request: first byte must be 0x10 or 0x11')
|
||||
return None
|
||||
if data[1:2] not in b'\xFF\x01\x02\x03\x04\x05\x06':
|
||||
_error('Invalid HID++ request: second byte must be 0xFF or one of 0x01..0x06')
|
||||
return None
|
||||
if data[:1] == b'\x10':
|
||||
if len(data) > 7:
|
||||
_error('Invalid HID++ request: maximum length of a 0x10 request is 7 bytes')
|
||||
return None
|
||||
while len(data) < 7:
|
||||
data = (data + b'\x00' * 7)[:7]
|
||||
elif data[:1] == b'\x11':
|
||||
if len(data) > 20:
|
||||
_error('Invalid HID++ request: maximum length of a 0x11 request is 20 bytes')
|
||||
return None
|
||||
while len(data) < 20:
|
||||
data = (data + b'\x00' * 20)[:20]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def _open(args):
|
||||
def matchfn(bid, vid, pid):
|
||||
if vid == 0x046d:
|
||||
return {'vid': 0x046d}
|
||||
|
||||
device = args.device
|
||||
if args.hidpp and not device:
|
||||
for d in _hid.enumerate(matchfn):
|
||||
if d.driver == 'logitech-djreceiver':
|
||||
device = d.path
|
||||
break
|
||||
if not device:
|
||||
sys.exit('!! No HID++ receiver found.')
|
||||
if not device:
|
||||
sys.exit('!! Device path required.')
|
||||
|
||||
print('.. Opening device', device)
|
||||
handle = _hid.open_path(device)
|
||||
if not handle:
|
||||
sys.exit('!! Failed to open %s, aborting.' % device)
|
||||
|
||||
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 _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
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
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'
|
||||
)
|
||||
return arg_parser.parse_args()
|
||||
|
||||
|
||||
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.')
|
||||
|
||||
import readline
|
||||
if args.history is None:
|
||||
import os.path
|
||||
args.history = os.path.join(os.path.expanduser('~'), '.hidconsole-history')
|
||||
try:
|
||||
readline.read_history_file(args.history)
|
||||
except Exception:
|
||||
# file may not exist yet
|
||||
pass
|
||||
|
||||
try:
|
||||
from threading import Thread
|
||||
t = Thread(target=_continuous_read, args=(handle, ))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
if interactive:
|
||||
# move the cursor at the bottom of the screen
|
||||
sys.stdout.write('\033[300B') # move cusor at most 300 lines down, don't scroll
|
||||
|
||||
while t.is_alive():
|
||||
line = read_packet(prompt)
|
||||
line = line.strip().replace(' ', '')
|
||||
# print ("line", line)
|
||||
if not line:
|
||||
continue
|
||||
|
||||
data = _validate_input(line, args.hidpp)
|
||||
if data is None:
|
||||
continue
|
||||
|
||||
_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
|
||||
time.sleep(0.700)
|
||||
except EOFError:
|
||||
if interactive:
|
||||
print('')
|
||||
else:
|
||||
time.sleep(1)
|
||||
|
||||
finally:
|
||||
print('.. Closing handle %r' % handle)
|
||||
_hid.close(handle)
|
||||
if interactive:
|
||||
readline.write_history_file(args.history)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
arg_parser = argparse.ArgumentParser()
|
||||
arg_parser.add_argument('--history', help='history file')
|
||||
arg_parser.add_argument('device', default=None, help='linux device to connect to')
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
import hidapi
|
||||
print (".. Opening device %s" % args.device)
|
||||
handle = hidapi.open_path(args.device.encode('utf-8'))
|
||||
if handle:
|
||||
print (".. Opened handle %X, vendor %s product %s serial %s" % (handle,
|
||||
repr(hidapi.get_manufacturer(handle)),
|
||||
repr(hidapi.get_product(handle)),
|
||||
repr(hidapi.get_serial(handle))))
|
||||
if interactive:
|
||||
print (".. Press ^C/^D to exit, or type hex bytes to write to the device.")
|
||||
|
||||
import readline
|
||||
if args.history is None:
|
||||
import os.path
|
||||
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,))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
prompt = '?? Input: ' if interactive else ''
|
||||
|
||||
while t.is_alive():
|
||||
line = read_packet(prompt).strip().replace(' ', '')
|
||||
if line:
|
||||
try:
|
||||
data = unhexlify(line.encode('ascii'))
|
||||
except Exception as e:
|
||||
print ("!! Invalid input.")
|
||||
else:
|
||||
_print('<<', data)
|
||||
hidapi.write(handle, data)
|
||||
# wait for some kind of reply
|
||||
if not interactive:
|
||||
rlist, wlist, xlist = _select([handle], [], [], 1)
|
||||
time.sleep(0.1)
|
||||
except EOFError:
|
||||
pass
|
||||
except Exception as e:
|
||||
print ('%s: %s' % (type(e).__name__, e))
|
||||
|
||||
print (".. Closing handle %X" % handle)
|
||||
hidapi.close(handle)
|
||||
if interactive:
|
||||
readline.write_history_file(args.history)
|
||||
else:
|
||||
print ("!! Failed to open %s, aborting" % args.device)
|
||||
main()
|
||||
|
||||
@@ -1,380 +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.
|
||||
"""
|
||||
|
||||
__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', 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', 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)
|
||||
@@ -1,3 +1,20 @@
|
||||
# -*- python-mode -*-
|
||||
|
||||
## 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
|
||||
@@ -7,28 +24,43 @@ The docstrings are mostly copied from the hidapi API header, with changes where
|
||||
necessary.
|
||||
"""
|
||||
|
||||
import errno as _errno
|
||||
import os as _os
|
||||
from select import select as _select
|
||||
from pyudev import Context as _Context
|
||||
from pyudev import Device as _Device
|
||||
|
||||
|
||||
native_implementation = 'udev'
|
||||
|
||||
|
||||
# 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',
|
||||
])
|
||||
from logging import DEBUG as _DEBUG
|
||||
from logging import getLogger
|
||||
from select import select as _select
|
||||
from time import sleep
|
||||
from time import time as _timestamp
|
||||
|
||||
from pyudev import Context as _Context
|
||||
from pyudev import Device as _Device
|
||||
from pyudev import DeviceNotFoundError
|
||||
from pyudev import Devices as _Devices
|
||||
from pyudev import Monitor as _Monitor
|
||||
|
||||
_log = getLogger(__name__)
|
||||
del getLogger
|
||||
|
||||
native_implementation = 'udev'
|
||||
|
||||
DeviceInfo = namedtuple(
|
||||
'DeviceInfo', [
|
||||
'path',
|
||||
'vendor_id',
|
||||
'product_id',
|
||||
'serial',
|
||||
'release',
|
||||
'manufacturer',
|
||||
'product',
|
||||
'interface',
|
||||
'driver',
|
||||
'bus_id',
|
||||
'isDevice',
|
||||
]
|
||||
)
|
||||
del namedtuple
|
||||
|
||||
#
|
||||
@@ -36,222 +68,378 @@ del namedtuple
|
||||
# docstrings mostly copied from hidapi.h
|
||||
#
|
||||
|
||||
def init():
|
||||
"""This function is a no-op, and exists only to match the native hidapi
|
||||
implementation.
|
||||
|
||||
:returns: ``True``.
|
||||
"""
|
||||
return True
|
||||
def init():
|
||||
"""This function is a no-op, and exists only to match the native hidapi
|
||||
implementation.
|
||||
|
||||
:returns: ``True``.
|
||||
"""
|
||||
return True
|
||||
|
||||
|
||||
def exit():
|
||||
"""This function is a no-op, and exists only to match the native hidapi
|
||||
implementation.
|
||||
"""This function is a no-op, and exists only to match the native hidapi
|
||||
implementation.
|
||||
|
||||
:returns: ``True``.
|
||||
"""
|
||||
return True
|
||||
:returns: ``True``.
|
||||
"""
|
||||
return True
|
||||
|
||||
|
||||
def enumerate(vendor_id=None, product_id=None, interface_number=None):
|
||||
"""Enumerate the HID Devices.
|
||||
# The filterfn is used to determine whether this is a device of interest to Solaar.
|
||||
# It is given the bus id, vendor id, and product id and returns a dictionary
|
||||
# with the required hid_driver and usb_interface and whether this is a receiver or device.
|
||||
def _match(action, device, filterfn):
|
||||
hid_device = device.find_parent('hid')
|
||||
if not hid_device:
|
||||
return
|
||||
hid_id = hid_device.get('HID_ID')
|
||||
if not hid_id:
|
||||
return # there are reports that sometimes the id isn't set up right so be defensive
|
||||
bid, vid, pid = hid_id.split(':')
|
||||
|
||||
List all the HID devices attached to the system, optionally filtering by
|
||||
vendor_id, product_id, and/or interface_number.
|
||||
filter = filterfn(int(bid, 16), int(vid, 16), int(pid, 16))
|
||||
if not filter:
|
||||
return
|
||||
|
||||
: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
|
||||
hid_driver = filter.get('hid_driver')
|
||||
interface_number = filter.get('usb_interface')
|
||||
isDevice = filter.get('isDevice')
|
||||
|
||||
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 action == 'add':
|
||||
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
|
||||
|
||||
if bus == '0003': # USB
|
||||
intf_dev = dev.find_parent('usb', 'usb_interface')
|
||||
if not intf_dev:
|
||||
continue
|
||||
intf_device = device.find_parent('usb', 'usb_interface')
|
||||
# print ("*** usb interface", action, device, "usb_interface:", intf_device)
|
||||
usb_interface = None if intf_device is None else intf_device.attributes.asint('bInterfaceNumber')
|
||||
if _log.isEnabledFor(_DEBUG):
|
||||
_log.debug(
|
||||
'Found device BID %s VID %s PID %s INTERFACE %s FILTER %s', bid, vid, pid, usb_interface, interface_number
|
||||
)
|
||||
if not (interface_number is None or interface_number == usb_interface):
|
||||
return
|
||||
attrs = intf_device.attributes if intf_device else None
|
||||
|
||||
interface = intf_dev.attributes.asint('bInterfaceNumber')
|
||||
if interface_number is not None and interface_number != interface:
|
||||
continue
|
||||
d_info = DeviceInfo(
|
||||
path=device.device_node,
|
||||
bus_id=int(bid, 16),
|
||||
vendor_id=vid[-4:],
|
||||
product_id=pid[-4:],
|
||||
driver=hid_driver_name,
|
||||
interface=usb_interface,
|
||||
isDevice=isDevice,
|
||||
serial=hid_device.get('HID_UNIQ'),
|
||||
release=attrs.get('bcdDevice') if attrs else None,
|
||||
manufacturer=attrs.get('manufacturer') if attrs else None,
|
||||
product=attrs.get('product') if attrs else None
|
||||
)
|
||||
return d_info
|
||||
|
||||
serial = hid_dev['HID_UNIQ'] if 'HID_UNIQ' in hid_dev else None
|
||||
elif action == 'remove':
|
||||
# print (dict(device), dict(usb_device))
|
||||
|
||||
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
|
||||
d_info = DeviceInfo(
|
||||
path=device.device_node,
|
||||
bus_id=None,
|
||||
vendor_id=vid[-4:],
|
||||
product_id=pid[-4:],
|
||||
driver=None,
|
||||
interface=None,
|
||||
isDevice=isDevice,
|
||||
serial=None,
|
||||
release=None,
|
||||
manufacturer=None,
|
||||
product=None
|
||||
)
|
||||
return d_info
|
||||
|
||||
elif bus == '0005': # BLUETOOTH
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def find_paired_node(receiver_path, index, timeout):
|
||||
"""Find the node of a device paired with a receiver"""
|
||||
context = _Context()
|
||||
receiver_phys = _Devices.from_device_file(context, receiver_path).find_parent('hid').get('HID_PHYS')
|
||||
|
||||
if not receiver_phys:
|
||||
return None
|
||||
|
||||
phys = f'{receiver_phys}:{index}'
|
||||
timeout += _timestamp()
|
||||
delta = _timestamp()
|
||||
while delta < timeout:
|
||||
for dev in context.list_devices(subsystem='hidraw'):
|
||||
dev_phys = dev.find_parent('hid').get('HID_PHYS')
|
||||
if dev_phys and dev_phys == phys:
|
||||
return dev.device_node
|
||||
delta = _timestamp()
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def find_paired_node_wpid(receiver_path, index):
|
||||
"""Find the node of a device paired with a receiver, get wpid from udev"""
|
||||
context = _Context()
|
||||
receiver_phys = _Devices.from_device_file(context, receiver_path).find_parent('hid').get('HID_PHYS')
|
||||
|
||||
if not receiver_phys:
|
||||
return None
|
||||
|
||||
phys = f'{receiver_phys}:{index}'
|
||||
for dev in context.list_devices(subsystem='hidraw'):
|
||||
dev_phys = dev.find_parent('hid').get('HID_PHYS')
|
||||
if dev_phys and dev_phys == phys:
|
||||
# get hid id like 0003:0000046D:00000065
|
||||
hid_id = dev.find_parent('hid').get('HID_ID')
|
||||
# get wpid - last 4 symbols
|
||||
udev_wpid = hid_id[-4:]
|
||||
return udev_wpid
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def monitor_glib(callback, filterfn):
|
||||
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, filterfn):
|
||||
if condition == GLib.IO_IN:
|
||||
event = monitor.receive_device()
|
||||
if event:
|
||||
action, device = event
|
||||
# print ("***", action, device)
|
||||
if action == 'add':
|
||||
d_info = _match(action, device, filterfn)
|
||||
if d_info:
|
||||
GLib.idle_add(cb, action, d_info)
|
||||
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, filterfn)
|
||||
# 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, filterfn)
|
||||
# print ("did io_add_watch with priority")
|
||||
except Exception:
|
||||
GLib.io_add_watch(m, GLib.IO_IN, _process_udev_event, callback, filterfn)
|
||||
# print ("did io_add_watch")
|
||||
|
||||
m.start()
|
||||
|
||||
|
||||
def enumerate(filterfn):
|
||||
"""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: a list of matching ``DeviceInfo`` tuples.
|
||||
"""
|
||||
|
||||
for dev in _Context().list_devices(subsystem='hidraw'):
|
||||
dev_info = _match('add', dev, filterfn)
|
||||
if dev_info:
|
||||
yield dev_info
|
||||
|
||||
|
||||
def open(vendor_id, product_id, serial=None):
|
||||
"""Open a HID device by its Vendor ID, Product ID and optional serial number.
|
||||
"""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.
|
||||
If no serial is provided, the first device with the specified IDs is opened.
|
||||
|
||||
:returns: an opaque device handle, or ``None``.
|
||||
"""
|
||||
for device in enumerate(vendor_id, product_id):
|
||||
if serial is None or serial == device.serial:
|
||||
return open_path(device.path)
|
||||
:returns: an opaque device handle, or ``None``.
|
||||
"""
|
||||
def matchfn(bid, vid, pid):
|
||||
return vid == vendor_id and pid == product_id
|
||||
|
||||
for device in enumerate(matchfn):
|
||||
if serial is None or serial == device.serial:
|
||||
return open_path(device.path)
|
||||
|
||||
|
||||
def open_path(device_path):
|
||||
"""Open a HID device by its path name.
|
||||
"""Open a HID device by its path name.
|
||||
|
||||
:param device_path: the path of a ``DeviceInfo`` tuple returned by
|
||||
enumerate().
|
||||
:param device_path: the path of a ``DeviceInfo`` tuple returned by enumerate().
|
||||
|
||||
:returns: an opaque device handle, or ``None``.
|
||||
"""
|
||||
return _os.open(device_path, _os.O_RDWR | _os.O_SYNC)
|
||||
:returns: an opaque device handle, or ``None``.
|
||||
"""
|
||||
assert device_path
|
||||
assert device_path.startswith('/dev/hidraw')
|
||||
return _os.open(device_path, _os.O_RDWR | _os.O_SYNC)
|
||||
|
||||
|
||||
def close(device_handle):
|
||||
"""Close a HID device.
|
||||
"""Close a HID device.
|
||||
|
||||
:param device_handle: a device handle returned by open() or open_path().
|
||||
"""
|
||||
_os.close(device_handle)
|
||||
:param device_handle: a device handle returned by open() or open_path().
|
||||
"""
|
||||
assert device_handle
|
||||
_os.close(device_handle)
|
||||
|
||||
|
||||
def write(device_handle, data):
|
||||
"""Write an Output report to a HID device.
|
||||
"""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.
|
||||
: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.
|
||||
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.
|
||||
"""
|
||||
try:
|
||||
bytes_written = _os.write(device_handle, data)
|
||||
return bytes_written == len(data)
|
||||
except:
|
||||
pass
|
||||
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).
|
||||
"""
|
||||
assert device_handle
|
||||
assert data
|
||||
assert isinstance(data, bytes), (repr(data), type(data))
|
||||
retrycount = 0
|
||||
bytes_written = 0
|
||||
while (retrycount < 3):
|
||||
try:
|
||||
retrycount += 1
|
||||
bytes_written = _os.write(device_handle, data)
|
||||
except OSError as e:
|
||||
if e.errno == _errno.EPIPE:
|
||||
sleep(0.1)
|
||||
else:
|
||||
break
|
||||
if bytes_written != len(data):
|
||||
raise OSError(_errno.EIO, 'written %d bytes out of expected %d' % (bytes_written, len(data)))
|
||||
|
||||
|
||||
def read(device_handle, bytes_count, timeout_ms=-1):
|
||||
"""Read an Input report from a HID device.
|
||||
"""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.
|
||||
: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.
|
||||
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.
|
||||
"""
|
||||
try:
|
||||
timeout = None if timeout_ms < 0 else timeout_ms / 1000.0
|
||||
rlist, wlist, xlist = _select([device_handle], [], [], timeout)
|
||||
if rlist:
|
||||
assert rlist == [device_handle]
|
||||
return _os.read(device_handle, bytes_count)
|
||||
return b''
|
||||
except OSError:
|
||||
pass
|
||||
:returns: the data packet read, an empty bytes string if a timeout was
|
||||
reached, or None if there was an error while reading.
|
||||
"""
|
||||
assert device_handle
|
||||
timeout = None if timeout_ms < 0 else timeout_ms / 1000.0
|
||||
rlist, wlist, xlist = _select([device_handle], [], [device_handle], timeout)
|
||||
|
||||
if xlist:
|
||||
assert xlist == [device_handle]
|
||||
raise OSError(_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''
|
||||
|
||||
|
||||
_DEVICE_STRINGS = {
|
||||
0: 'manufacturer',
|
||||
1: 'product',
|
||||
2: 'serial',
|
||||
0: 'manufacturer',
|
||||
1: 'product',
|
||||
2: 'serial',
|
||||
}
|
||||
|
||||
|
||||
def get_manufacturer(device_handle):
|
||||
"""Get the Manufacturer String from a HID device.
|
||||
"""Get the Manufacturer String from a HID device.
|
||||
|
||||
:param device_handle: a device handle returned by open() or open_path().
|
||||
"""
|
||||
return get_indexed_string(device_handle, 0)
|
||||
:param device_handle: a device handle returned by open() or open_path().
|
||||
"""
|
||||
return get_indexed_string(device_handle, 0)
|
||||
|
||||
|
||||
def get_product(device_handle):
|
||||
"""Get the Product String from a HID device.
|
||||
"""Get the Product String from a HID device.
|
||||
|
||||
:param device_handle: a device handle returned by open() or open_path().
|
||||
"""
|
||||
return get_indexed_string(device_handle, 1)
|
||||
:param device_handle: a device handle returned by open() or open_path().
|
||||
"""
|
||||
return get_indexed_string(device_handle, 1)
|
||||
|
||||
|
||||
def get_serial(device_handle):
|
||||
"""Get the serial number from a HID device.
|
||||
"""Get the serial number from a HID device.
|
||||
|
||||
:param device_handle: a device handle returned by open() or open_path().
|
||||
"""
|
||||
serial = get_indexed_string(device_handle, 2)
|
||||
if serial is not None:
|
||||
return ''.join(hex(ord(c)) for c in serial)
|
||||
:param device_handle: a device handle returned by open() or open_path().
|
||||
"""
|
||||
serial = get_indexed_string(device_handle, 2)
|
||||
return serial
|
||||
|
||||
|
||||
def get_indexed_string(device_handle, index):
|
||||
"""Get a string from a HID device, based on its string index.
|
||||
"""Get a string from a HID device, based on its string index.
|
||||
|
||||
Note: currently not working in the ``hidraw`` native implementation.
|
||||
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.
|
||||
"""
|
||||
if index not in _DEVICE_STRINGS:
|
||||
return None
|
||||
: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
|
||||
"""
|
||||
try:
|
||||
key = _DEVICE_STRINGS[index]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
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(':')
|
||||
assert device_handle
|
||||
stat = _os.fstat(device_handle)
|
||||
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
|
||||
|
||||