Information
4.15.0-106solaar show:Unifying Receiver
Device path : /dev/hidraw3
USB id : 046d:c52b
Serial : BE57977A
Firmware : 24.11.B0036
Bootloader : 02.09
Other : AA.AC
Has 1 paired device(s) out of a maximum of 6.
Notifications: wireless, software present (0x000900)
Device activity counters: 1=193
1: Wireless Touch Keyboard K400 Plus
Codename : K400 Plus
Kind : keyboard
Wireless PID : 404D
Protocol : HID++ 4.1
Polling rate : 8 ms (125Hz)
Serial number: 6DC5C81C
Bootloader: BOT 22.02.B0002
Firmware: RQK 63.02.B0016
Other:
The power switch is located on the top edge.
Supports 24 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: REPROG CONTROLS V4 {1B04}
Actions: {'84': NamedInt(84, 'Mouse Back Button'), '34': NamedInt(34, 'HomePage'), '8': NamedInt(8, 'Application Switcher'), '79': NamedInt(79, 'RightClick'), '62': NamedInt(62, 'Search Files'), '110': NamedInt(110, 'Show Desktop'), '145': NamedInt(145, 'Maximize Window'), '149': NamedInt(149, 'Switch Screen'), '40': NamedInt(40, 'Music'), '64': NamedInt(64, 'Sleep')}
8: SWAP BUTTON CANCEL {2005}
9: NEW FN INVERSION {40A2}
Swap Fx function: True
10: ENCRYPTION {4100}
11: KEYBOARD DISABLE {4521}
12: TOUCHPAD RAW XY {6100}
13: GESTURE 2 {6501}
14: DFUCONTROL UNSIGNED {00C1}
15: unknown:1811 {1811} internal, hidden
16: unknown:1830 {1830} internal, hidden
17: unknown:1890 {1890} internal, hidden
18: unknown:1DF3 {1DF3} internal, hidden
19: unknown:1E00 {1E00} hidden
20: unknown:1EB0 {1EB0} internal, hidden
21: unknown:1861 {1861} internal, hidden
22: unknown:18B0 {18B0} internal, hidden
23: unknown:1F11 {1F11} internal, hidden
Has 20 reprogrammable keys:
0: unknown:00B8 , default: LeftClick => unknown:00B8
mse, divertable, pos:0, group:0, gmask:0
1: Back , default: Mouse Back Button => Back
is FN, FN sensitive, reprogrammable, divertable, pos:1, group:0, gmask:0
2: MY HOME , default: HomePage => MY HOME
is FN, FN sensitive, reprogrammable, divertable, pos:2, group:0, gmask:0
3: Application Switcher , default: Application Switcher => Application Switcher
is FN, FN sensitive, reprogrammable, divertable, pos:3, group:0, gmask:0
4: CONTEXTUAL MENU , default: RightClick => CONTEXTUAL MENU
is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, gmask:0
5: Search , default: Search Files => Search
is FN, FN sensitive, reprogrammable, divertable, pos:5, group:0, gmask:0
6: Show Desktop , default: Show Desktop => Show Desktop
is FN, FN sensitive, reprogrammable, divertable, pos:6, group:0, gmask:0
7: Maximize Window , default: Maximize Window => Maximize Window
is FN, FN sensitive, reprogrammable, divertable, pos:7, group:0, gmask:0
8: Switch Screen , default: Switch Screen => Switch Screen
is FN, FN sensitive, reprogrammable, divertable, pos:8, group:0, gmask:0
9: MEDIA PLAYER , default: Music => MEDIA PLAYER
is FN, FN sensitive, reprogrammable, divertable, pos:9, group:0, gmask:0
10: Previous , default: Previous => Previous
is FN, FN sensitive, divertable, pos:10, group:0, gmask:0
11: Play/Pause , default: Play/Pause => Play/Pause
is FN, FN sensitive, divertable, pos:11, group:0, gmask:0
12: Next , default: Next => Next
is FN, FN sensitive, divertable, pos:12, group:0, gmask:0
13: unknown:00B7 , default: ShowUI => unknown:00B7
divertable, pos:0, group:0, gmask:0
14: LEFT CLICK , default: LeftClick => LEFT CLICK
mse, pos:0, group:0, gmask:0
15: RIGHT CLICK , default: RightClick => RIGHT CLICK
mse, pos:0, group:0, gmask:0
16: Mute , default: Mute => Mute
nonstandard, divertable, pos:0, group:0, gmask:0
17: Volume Up , default: Volume Up => Volume Up
nonstandard, divertable, pos:0, group:0, gmask:0
18: Volume Down , default: Volume Down => Volume Down
nonstandard, divertable, pos:0, group:0, gmask:0
19: SLEEP , default: Sleep => SLEEP
reprogrammable, divertable, pos:0, group:0, gmask:0
Battery: 90%, discharging, next level 50%.
Describe the bug
This is a follow-up to #810. The K400+ keyboard supports REPROG CONTROLS V4, but the current implementation doesn't work. The reprogrammable keys and their options are displayed, but only the default action is executed regardless of the chosen option.
To Reproduce
Choose a reprogrammable key and change its action. Press the key. Instead of the chosen action, the default one is performed.
Additional context
From #810:
Please remove any "reprogrammable-keys" entries from ~/.config/solaar/config.json
Then run bin/solaar -dd, try a key change, and report any errors and tracebacks encountered.
K400plus_reprogramming_test.txt
I pressed the F1/back key once on a browser, tried to change its action and pressed it again on the browser. Only the default action was executed.
Then report the contents of ~/.config/solaar/config.json
{
"404D:6DC5C81C": {
"_name": "Wireless Touch Keyboard K400 Plus",
"fn-swap": true,
"reprogrammable-keys": {
"110": 110,
"145": 145,
"149": 149,
"34": 34,
"40": 40,
"62": 62,
"64": 64,
"79": 79,
"8": 8,
"84": 8
}
},
"_version": "1.0.2"
}
By the way, I've noticed that several keystrokes (multimedia keys and other special buttons) are incorrectly interpreted by Solaar as notifications for DEVICE NAME, for example:
WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000000003D00000000) for feature DEVICE NAME (index 03)
In the following, in both read and written bytes, I'll omit the trailing zeroes in the data, the prefix (10/11), the device number (e.g. 01) and the feature index (e.g. 07; the one that refers to 1B 04 = REPROG CONTROLS V4 on the device), and I'll use s to represent the software ID (4-bit, apparently chosen arbitrarily).
The way Solaar tries to reprogram a key XX XX to an action YY YY (3s XX XX 00 YY YY) is ignored with no errors, and this is probably the reason for the unexpected group 0 and gmask 0: it expects another pattern.
By using Wireshark and observing what happens when Logitech Options is running on a Windows VM, I figured this out:
3s XX XX 03 regardless of the chosen action. After that, the key no longer sends its normal value after being pressed; instead, it just sends 00 XX XX. At this point, if the Logitech processes are killed (or if the keyboard is transferred back to my Linux host), the key stops working, possibly because the data isn't recognised by the regular drivers and the keystrokes are actually handled by Logitech software. This does not persist after the device is powered off, and 00 00 00.00 XX XX ZZ ZZ WW WW... (real example: 00 00 54 00 08 00 22 00 3E), which could be used to create combinations of those keys. This isn't used by Logitech Options.Just as a proof of concept, I temporarily added the following code to _process_feature_notification():
if feature == _F.REPROG_CONTROLS_V4:
if n.address == 0x00 and len(n.data) == 16:
if _log.isEnabledFor(_INFO):
_log.info("%s: reprogrammable key: %s", device, n)
for i in range(8):
k = (n.data[2*i] << 8) | n.data[2*i + 1] # two bytes
if k != 0:
_log.debug('JUST A TEST: pressed the key 0x%04X' % k)
else:
_log.warn("%s: unknown REPROGRAMMABLE KEYS V4 %s", device, n)
return True
Now, after I manually send 0s XX XX 03 once for some of the divertable keys, they no longer execute the default actions, and their codes are logged whenever they're pressed.
To implement this feature, Solaar would have to re-implement all of the actions, just like Logitech Option does (it sends 0s XX XX 03 to all divertable keys on startup). To do this, Solaar would have to simulate keystrokes and mouse clicks. I'm not sure about the best way to do it from Python without depending on the Linux distribution or the destkop environment. Adding an external library as a dependency might help, but I'm not sure if it's worth it.
For now, regardless of whether this will be implemented, I think those "0" settings should be hidden, so that the user doesn't see options that produce no effect.
I'm not sure what that notification is for. If I had more examples maybe I could make a guess. Including the messages just before (the raw message information) would help.
Solaar tries to make sense of what it sees from the device, based mostly on documentation from Logitech, but there are lots of things that it has to just give up on.
What Solaar is trying to do is to reprogram the key, which changes the bits that it sends. This does not appear to be working for the K400 Plus.
What LO is doing is diverting the key, which as you have found out makes the key send back HID++ 2.0 notifications (with codes for up to four keys) which are handled specially by some Logitech software which presumably has remembered what has been set up for the key and does that. Getting Solaar to do that isn't going to be easy.
The reprogrammable flag for 10 of the K400 Plus keys is presumably on because they can be reprogrammed, but the usual way for reprogramming them isn't working for some reason. I'm trying to get information that might help, but this is likely to take some time.
I would like to keep the 0 gmask stuff in for a few days, just in case there is some keyboard where it works. You can undo this processing by changing
for g in range(0,9):
to
for g in range(1,9):
in settings_templates.py
One thing to note is that the device is supposed to respond to a successful reprogramming with the exact same information, but the response is slightly different
`
20:25:06,861 DEBUG [AsyncUI] logitech_receiver.base: (11) <= w[11 01 073F 00540000080000000000000000000000]
20:25:06,919 DEBUG [AsyncUI] logitech_receiver.base: (11) => r[11 01 073F 00540000000000000000000000000000]
I don't view this is as a problem because lots of other responses are different in this way (my mouse also responds to successful key reprogramming with a response different from the command).
I'm not sure what that notification is for.
The unknown notification warnings aren't a problem, and I only mentioned them because I noticed them when I was testing some keys. It looks like the notifications sent when some special keys get released are incorrectly interpreted by Solaar as begin about "device name".
If I had more examples maybe I could make a guess. Including the messages just before (the raw message information) would help.
Below, the 1st line is the key press, the 2nd line is the key release, and the 3rd line is the warning it causes. The pattern is repeated for other keys.
10:03:46,000 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 03B6 0000000000008700000000]
10:03:46,144 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 0300 0000000000003D00000000]
10:03:46,144 WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000000003D00000000) for feature DEVICE NAME (index 03)
10:03:46,782 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 03CD 0000000000007000000000]
10:03:46,966 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 0300 0000000000003D00000000]
10:03:46,966 WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000000003D00000000) for feature DEVICE NAME (index 03)
10:03:47,538 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 03B5 0000000000008800000000]
10:03:47,724 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 0300 0000000000003D00000000]
10:03:47,724 WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000000003D00000000) for feature DEVICE NAME (index 03)
10:03:51,452 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 03E2 0000000000005B00000000]
10:03:51,564 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 0300 0000000000003D00000000]
10:03:51,564 WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000000003D00000000) for feature DEVICE NAME (index 03)
10:03:52,634 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 03EA 0000000000005300000000]
10:03:52,762 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 0300 0000000000003D00000000]
10:03:52,763 WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000000003D00000000) for feature DEVICE NAME (index 03)
10:03:53,680 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 03E9 0000000000005400000000]
10:03:53,810 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 0300 0000000000003D00000000]
10:03:53,811 WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000000003D00000000) for feature DEVICE NAME (index 03)
[...]
10:14:35,337 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 03B6 0000000500008200000000]
10:14:35,433 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 0300 0000000500003800000000]
10:14:35,434 WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000500003800000000) for feature DEVICE NAME (index 03)
10:14:35,763 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 03CD 0000000500006B00000000]
10:14:35,843 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 0300 0000000500003800000000]
10:14:35,844 WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000500003800000000) for feature DEVICE NAME (index 03)
10:14:36,133 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 03B5 0000000500008300000000]
10:14:36,223 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 0300 0000000500003800000000]
10:14:36,224 WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000500003800000000) for feature DEVICE NAME (index 03)
10:14:36,971 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 03E2 0000000500005600000000]
10:14:37,036 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 0300 0000000500003800000000]
10:14:37,036 WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000500003800000000) for feature DEVICE NAME (index 03)
10:14:37,303 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 03EA 0000000500004E00000000]
10:14:37,375 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 0300 0000000500003800000000]
10:14:37,376 WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000500003800000000) for feature DEVICE NAME (index 03)
10:14:37,575 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 03E9 0000000500004F00000000]
10:14:37,655 DEBUG [ReceiverListener:hidraw3] logitech_receiver.base: (10) => r[20 01 0300 0000000500003800000000]
10:14:37,656 WARNING [ReceiverListener:hidraw3] logitech_receiver.notifications: <PairedDevice(1,404D,K400 Plus,6DC5C81C)>: unrecognized Notification(1,03,00,0000000500003800000000) for feature DEVICE NAME (index 03)
The notification warnings are for DJ messages, which didn't exist when that part of Solaar was written. I wrote a filter to remove some of them but I didn't have documentation so I didn't want to filter out too much. Now I have documentation so I can rewrite the filter to work better.
It may be that there is no way for Solaar to reprogram keys on the K400+. I'm going to back out the changes for gmask==0 and group==0. If anyone wants to test out how to get reprogramming working for these devices, please speak up here. To see if you have an affected device, do a solaar show and look for reprogrammable keys with group:0, gmask:0
Craft/Mx Keys are affected. Would be the sniffed out packets when reprogramming occurs useful? [ from Logitech Options ]
Those keys have shittoon of reprogramming options in L_Options, customs shortcuts, custom app launch, modifier keys, some weird hybrid keystrokes
@barolo Definitely maybe. :-)
Key "reprogramming" can be done in two main ways. Telling the device to send different bits for the key, but as regular keycodes, or telling the device to send the same bits but using a different protocol (HID++ vs HID). The former doesn't need any support from input drivers (and thus is perfect for Solaar). The latter needs the input driver to intercept these reports and turn them into something else (and this is essentially outside the scope of Solaar). So if Logitech Options uses the latter, even if the former is possible, looking at the sniffed packets won't be conclusive.
But it may be the Logitech Options does actually reprogram these keys so the information could easily be helpful, I think. What you want to do is to try to reprogram one of the keys indicated as reprogrammable as one of the keys in group 0. For the K400+ this could be Search as Show Desktop.
@pfps here you go, its "show desktop" --> "search"
tried to make it as clean as possible
show_desktop_to_search.zip
Thanks. That sure looks like Logitech Options is using diversion, i.e., the thing that is outside the scope of Solaar. A good way to check for sure is to try solaar show soon after reprogramming in Logitech Options, and without turning the device off.
This is suggestive that the nice kind of key reprogramming can't be done for this device, but it is not a complete demonstration.
For the morbidly curious:
The message that appears to be doing the diversion is:
11 01 0b 3e 006e 03 00000000000000000000000000
where
11 is an HID++ long message,
01 is the device number,
0b is the feature offset (on the Craft the 11th feature is indeed REPROG CONTROLS V4)
006e is the key number (006e is Show_Desktop)
03 is divert (send a special message instead of a regular message - the input driver remembers what do with this special message)
I think that I'm gettin what you mean. solaar show is back to normal, and the shortcut is back to "show desktop".
Still, they all have "reprogrammable, divertable, persistently divertable"
This is not surprising since bunch of possible reprogramming is context dependant, i.e per app/global and must know which app is in focus. So it's tracked on the hosts side
Precisely, so my reading is that these keys should be reprogrammable, but reprogramming them doesn't seem to do anything. If you want to see if you can get the reprogramming to work you can just change one line in settings_templates.py. In
for g in range(1,9): # group 0 and gmask 0 (k[3]) don't appear to work, don't consider group 0
change the 1,9 to 0,9
That will let you attempt to reprogram any key with gmask 0 to any key in group 0. After you do, check to see if the key behaviour changes and also whether there is a change in solaar show.
Nope, no go, I think we went through this already in another thread.
Solaar show shows it as changed but it doesn't work, is unchanged
The weird thing is that Swap Fx Funntion doesn't work either, II think that I remember it working, not sure.
Cant, activate standard F1-F12 keys
That's what bugs me. There is information on the device indicating that the key was reprogrammed, but nothing changes. I'm trying to get more information, but I don't know if that will come to anything.
I've noticed that Swap Fx function doesn't work either, it's for Fn behavior isn't it? It doesn't even change state in solaar show
Sincethose are Fn keys we're trying to reprogram, maybe it's related?
Disabling backlight works
Hmm. I thought that I had Swap Fx working on one of my keyboards (not one that I have with me now though). What it should do is swap the base behaviour of the Fn keys (between F
I was conflating reprogramming and remapping. Remapping is what Solaar does. A reprogrammable key is one that Logitech indicates should be given special handling, maybe by remapping or maybe by diverting or maybe by some other means. I'm going to make the (minor) changes to the code and documentation to reflect this new understanding.
The net result, however, is that Solaar can't reprogram any keys on the K400+.
PR #828 doesn't really fix this issue, but instead describes a bit about why Solaar can't remap keys for the K400+ (in docs/usage.md). Please test it out to make sure it does the right thing.
@pfps according to Logitech documentation for feature 0x1b04, only keys with non-zero value in gmask field can be reprogrammed. I think that Logitech mark this keys as "reprogrammable" to mark whot keys can change function by software command. Such key can be only diverted if they have "divertable" or "persistent" flags so instead of normal keycode pressing this key will send HID++ event.
@doctor64 Yes, that's right. I have a pending update to reflect this understanding. A previous update eliminated non-remappable keys from the setting but didn't update the documentation.
Thanks for explaining!
only keys with non-zero value in gmask field can be reprogrammed
I have a pending update to reflect this understanding.
Please test it out to make sure it does the right thing.
The additions to the text are very clear. Now we know why Logitech Options only diverts rather than remap (on this device), and it only lets the user divert the keys that are marked as reprogrammable. I guess the non-reprogrammable keys marked as divertable are intended to be diverted by third-party software for specific applications.
PR #828 doesn't really fix this issue
I think this issue can be closed, since now we know that key reprogramming on this device cannot be done (unless key diversion ever gets implemented).