Solaar: Logitech Craft dial keycodes

Created on 20 Feb 2019  路  52Comments  路  Source: pwr-Solaar/Solaar

The dial has the same keycode as the media fn buttons for raise/lower volume. That means I cannot map the dial to another function without stealing that from the actual raise/lower volume buttons.

enhancement

Most helpful comment

PR #810 may fix this. Please clone the current version of this repository and see whether the new Action setting for reprogrammable keys can be used to fix your problem.

All 52 comments

Example from xev

    state 0x2010, keycode 123 (keysym 0x1008ff13, XF86AudioRaiseVolume), same_screen YES,

I fear it is impossible, at least with default configuration of device.
Can you provide output of 'solaar show' from repo version? May be it possible to remap some keys to different HID codes

Unifying Receiver
  Device path  : /dev/hidraw4
  USB id       : 046d:c52b
  Serial       : 43CC86FA
    Firmware   : 24.07.B0030
    Bootloader : 02.09
    Other      : AA.AC
  Has 2 paired device(s) out of a maximum of 6.
  Notifications: wireless, software present (0x000900)
  Device activity counters: 1=43, 2=152

  1: Craft Advanced Keyboard
     Codename     : Craft
     Kind         : keyboard
     Wireless PID : 4066
     Protocol     : HID++ 4.5
     Polling rate : 8 ms (125Hz)
     Serial number: B924F1B3
        Bootloader: BOT 41.01.B0015
          Firmware: MPK 07.01.B0015
             Other: 
             Other: 
     The power switch is located on the edge of top right corner.
     Supports 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: 50%, discharging.

  2: MX Ergo Multi-Device Trackball 
... cut out, I guess it's irrelevant ...

I hope there is something that can be done; I really like the keyboard apart from those dead key combinations...

@fiddur Unfortunately, most key codes unknown to Solaar. But, looking to output, i see only one key with function Volume UP/Volume Down (lines 14-15). So, i'm not sure what dial even exported to reprogramming function as a "key". So maybe it can't be remapped with function REPROG CONTROLS V4 {1B04}.
May be, dial can be controlled with "unknown" features (here is lot's of it) but without Logitech docs or extensive reverse engineering with tracing of usb packets it will be impossible. As I understand? under windows/mac operations of dial can be changed?
Unfortunately, i don't have Craft keyboard to verify.

Just got a Craft, indeed the dial sends keypresses to media volume and play/stop. Tried it on a windows machine and apart from the different bindings it seems that the Craft can switch the dial between a smooth and a stepped mode. Probably one or more of those unknown codes.

For now, I worked around the issue binding my DE's volume keys to CTRL+volume and I can bind the output of the dial for gimp zoom among other things.

In any case if you need a guinea pig for testing, @ me

@doctor64

@fiddur Unfortunately, most key codes unknown to Solaar. But, looking to output, i see only one key with function Volume UP/Volume Down (lines 14-15). So, i'm not sure what dial even exported to reprogramming function as a "key". So maybe it can't be remapped with function REPROG CONTROLS V4 {1B04}.
May be, dial can be controlled with "unknown" features (here is lot's of it) but without Logitech docs or extensive reverse engineering with tracing of usb packets it will be impossible. As I understand? under windows/mac operations of dial can be changed?
Unfortunately, i don't have Craft keyboard to verify.

As nobody answered you; yes, under both mac and win crown options can be changed, not only that, there are profiles which are auto activated [ just for some well known productivity apps from adobe, microsoft, etc ] and change crown functions depending on the app context/tool. Furthermore, the knob is touch sensitive, can be pressed for alt function and has two modes of operation, smooth and ratchet, which are switched on the fly depending on the context.

I have to say that I'm using it extensively for work in some of the Adobe's Apps.
It can be paired with MX Master for combined functions [ button on the mouse functions as modifier key ] but it's too much for me, and I've never used that

@barolo thank you. unfortunately, without usb traces we still can't say is this functionality implemented inside keyboard (so knob can send different scan codes) or just in driver in OS.

Hey guys I'd really like to switch to Linux on my main Computer and still be able to take advantage of all that great Dial Functions of My Logitech Craft and MX Master 3 like I do in Windows. I've currently installed a Debian based distribution on my laptop to check it its working and realized I won't be able to enjoy those features. I'd really appreciate it if you would add it.

We can add support to talk with the device, but applications will have to implement the actions themselves, which I think it's not going to happen. It's too niche.

I think the best way would be to perhaps add new event codes in the kernel level and write a driver. I am not sure about this, however. We need to look at the information the device sends and see if this makes sense.

We can add support to talk with the device, but applications will have to implement the actions themselves, which I think it's not going to happen. It's too niche.

I think the best way would be to perhaps add new event codes in the kernel level and write a driver. I am not sure about this, however. We need to look at the information the device sends and see if this makes sense.

The API is available for it and there are few external add-ons already, there's a simple one for vscode which would be something to aim for at least. But yeah, it's too niche unfortunately and it would require reverse engineering Logitech's Option app

I can capture whatever is needed.

PR #810 may fix this. Please clone the current version of this repository and see whether the new Action setting for reprogrammable keys can be used to fix your problem.

@pfps I can't reassign media keys at all for some reason, it just doesn't work e.g. play/pause to screen capture. So I can't test if it could help with the crown/dial

@barolo I'm assuming that you are running the current version of Solaar.
Can you do any reassignment at all or is it just the media keys? If it is the former, please run solaar -dd and report any errors and tracebacks. Also provide output of solaar show after you have tried to reprogram some keys.

@pfps Yeah, I'm on master, It doesn't seem to work at all. Debug is awfully spammy because of the mouse
Output of changing "Launchpad" to "Show Desktop"

00:25:45,758   DEBUG [AsyncUI] logitech_receiver.settings: reprogrammable-keys: settings write key '225' value 110 to <PairedDevice(2,4066,Craft,40163908)>
00:25:45,758     INFO [AsyncUI] solaar.configuration: saved {'1A20:265B0828': {'_name': 'Wireless Compact Keyboard K340'}, '1E40:3A64AEB2': {'_name': 'Wireless Mouse MX Master 2S', 'dpi': '1600', 'hires-smooth-invert': True, 'hires-smooth-resolution': True, 'reprogrammable-keys': {'195': 196, '196': 196, '82': 82, '83': 83, '86': 86}, 'smart-shift': 0}, '1E40:40163908': {'_name': 'Craft Advanced Keyboard', 'backlight': True, 'fn-swap': False, 'reprogrammable-keys': {'10': 10, '110': 110, '111': 111, '191': 191, '199': 199, '200': 200, '224': 224, '225': 225, '226': 226, '227': 227, '228': 228, '229': 229, '230': 230, '231': 231, '232': 232, '233': 10, '234': 234}}, '2007:265B0828': {'_name': 'Wireless Compact Keyboard K340'}, '4066:40163908': {'_name': 'Craft Advanced Keyboard', 'backlight': True, 'fn-swap': True, 'reprogrammable-keys': {'10': 10, '110': 110, '111': 111, '191': 231, '199': 199, '200': 200, '224': 224, '225': 110, '226': 226, '227': 227, '228': 228, '229': 229, '230': 230, '231': 231, '232': 232, '233': 233, '234': 234}}, '4069:3A64AEB2': {'_name': 'Wireless Mouse MX Master 2S', 'dpi': '1600', 'hires-smooth-invert': False, 'hires-smooth-resolution': True, 'reprogrammable-keys': {'195': 196, '196': 196, '82': 82, '83': 83, '86': 86}, 'smart-shift': 0}, '_version': '1.0.2'} to /home/gregory/.config/solaar/config.json
00:25:45,758    DEBUG [AsyncUI] logitech_receiver.settings: reprogrammable-keys: settings prepare key value write(225,110) => b'\x00\x00n'
00:25:45,759    DEBUG [AsyncUI] logitech_receiver.base: (23) <= w[11 02 0B38 00E100006E0000000000000000000000]
00:25:45,782    DEBUG [AsyncUI] logitech_receiver.base: (23) => r[11 02 0B38 00E100006E0000000000000000000000]
  2: Craft Advanced Keyboard
     Codename     : Craft
     Kind         : keyboard
     Wireless PID : 4066
     Protocol     : HID++ 4.5
     Polling rate : 8 ms (125Hz)
     Serial number: 40163908
        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: DEVICE FRIENDLY NAME   {0007}   
         7: BATTERY STATUS         {1000}   
         8: CHANGE HOST            {1814}   
         9: HOSTS INFO             {1815}   
        10: BACKLIGHT2             {1982}   
            Backlight: True
        11: REPROG CONTROLS V4     {1B04}   
            Actions: {'199': 199, '200': 200, '224': 224, '225': 110, '110': 110, '226': 226, '227': 227, '228': 228, '229': 229, '230': 230, '231': 231, '232': 232, '233': 233, '10': 10, '191': 231, '234': 234, '111': 111}
        12: PERSISTENT REMAPPABLE ACTION {1C00}   
        13: K375S FN INVERSION     {40A3}   
            Swap Fx function: False
        14: ENCRYPTION             {4100}   
        15: LOCK KEY STATE         {4220}   
        16: KEYBOARD DISABLE       {4521}   
        17: MULTIPLATFORM          {4531}   
        18: CROWN                  {4600}   
        19: DFUCONTROL SIGNED      {00C2}   
        20: unknown:1803           {1803}   internal, hidden
        21: CONFIG DEVICE PROPS    {1806}   internal, hidden
        22: unknown:1813           {1813}   internal, hidden
        23: OOBSTATE               {1805}   internal, hidden
        24: unknown:1830           {1830}   internal, hidden
        25: unknown:1890           {1890}   internal, hidden
        26: unknown:1891           {1891}   internal, hidden
        27: unknown:1801           {1801}   internal, hidden
        28: unknown:18A1           {18A1}   internal, hidden
        29: unknown:9280           {9280}   internal, hidden
        30: unknown:1A20           {1A20}   internal, hidden
        31: unknown:1DF3           {1DF3}   internal, hidden
        32: unknown:1E00           {1E00}   hidden
        33: unknown:1EB0           {1EB0}   internal, hidden
        34: unknown:1861           {1861}   internal, hidden
        35: unknown:18B0           {18B0}   internal, hidden
        36: unknown:92C0           {92C0}   internal, hidden
        37: unknown:9203           {9203}   internal, hidden
        38: unknown:3615           {3615}   internal, hidden
     Has 24 reprogrammable keys:
         0: unknown:00D1              , default: unknown:00AE                => unknown:00D1              
             nonstandard, divertable, persistently divertable, pos:0, group:0, gmask:0
         1: unknown:00D2              , default: unknown:00AF                => unknown:00D2              
             nonstandard, divertable, persistently divertable, pos:0, group:0, gmask:0
         2: unknown:00D3              , default: unknown:00B0                => unknown:00D3              
             nonstandard, divertable, persistently divertable, pos:0, group:0, gmask:0
         3: Brightness Down           , default: Brightness Down             => Brightness Down           
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:1, group:0, gmask:0
         4: Brightness Up             , default: Brightness Up               => Brightness Up             
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:2, group:0, gmask:0
         5: Mission Control           , default: Switch Workspace            => Mission Control           
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:3, group:0, gmask:0
         6: Launchpad                 , default: Launchpad                   => Show Desktop              
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, gmask:0
         7: Show Desktop              , default: Show Desktop                => Show Desktop              
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:5, group:0, gmask:0
         8: Backlight Down            , default: Backlight Down              => Backlight Down            
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:6, group:0, gmask:0
         9: Backlight Up              , default: Backlight Up                => Backlight Up              
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:7, group:0, gmask:0
        10: Previous Fn               , default: Previous                    => Previous Fn               
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:8, group:0, gmask:0
        11: Play/Pause Fn             , default: Play/Pause                  => Play/Pause Fn             
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:9, group:0, gmask:0
        12: Next Fn                   , default: Next                        => Next Fn                   
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:10, group:0, gmask:0
        13: Mute Fn                   , default: Mute                        => Mute Fn                   
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, gmask:0
        14: Volume Down Fn            , default: Volume Down                 => Volume Down Fn            
             is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, gmask:0
        15: Volume Up Fn              , default: Volume Up                   => Volume Up Fn              
             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, gmask:0
        16: Calculator                , default: Calculator                  => Calculator                
             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, gmask:0
        17: Screen Capture            , default: unknown:009B                => Mute Fn                   
             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, gmask:0
        18: Look Up                   , default: Context Menu                => Look Up                   
             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, gmask:0
        19: Lock PC                   , default: WindowsLock                 => Lock PC                   
             nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, gmask:0
        20: unknown:00EC              , default: unknown:00B8                => unknown:00EC              
             nonstandard, divertable, persistently divertable, pos:0, group:0, gmask:0
        21: unknown:00EB              , default: unknown:00B6                => unknown:00EB              
             nonstandard, divertable, 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: N/A, full, next level 0%.

The output of solaar show is saying that there are two reprogrammed keys:
Launchpad (Fn F4) as Show Desktop
Screen Capture as Mute
So the action performed by both of these keys should have changed (under the appropriate state of the Fn key, of course).

I know, it doesn't work though, in any combination, I wonder if it works with MX Keys since it's pretty much the same keyboard minus crown

Well them I'm stumped. Solaar appears to be doing what it should do, as far as I know. Maybe there is something special about group 0 and gmask 0 that has to be activated. I'll see if I can get more information.

It looks as if keys with gmask 0 cannot be reprogrammed by Solaar the same way that keys with other gmasks now can. I've asked for more information, but I expect that these keys need to be "diverted" which requires a lot more software support.

It may also be that 18: CROWN {4600} is the feature that changes how the dial works.

This is almost certain want me to sniff it out?

Sure, but I expect that this is another feature that is mostly implemented in software.

Sure, but I expect that this is another feature that is mostly implemented in software.

Some of it for sure, it's very contextual. It can be pressed too for alternate keystrokes and is touch sensitive
I use macOS for work and under it I use it for shitton of stuff, workspace switching, zooming, tab switching, and in programs like Photoshop, Illustrator its functions change with each tool
It also has smooth and ratchet modes.
It's pretty much a device on its own...

Ermmm... I think that it's all done in software, it's not sending anything upon remapping

anyway, captured some stuff: crown.zip
First 3~ HIDs are from touching Crown in its defaults state which is Volume, then switched it to Application Switcher [ Alt+Tab ] again 3~HIDs packets or so and then used "restore defaults" on Crown which resulted in the rest of the packets

It looks as if the dial just sends reports and the software turns these into whatever the user has selected. But that doesn't explain how the dial sends volume up and down in Linux. Without documentation on that feature I don't think that anything more can be done.

Volume control is its default inbuilt state so I'm guessing it just functions as standard media control/ volume knob under Linux

To be honest.. I don't think there is anything magical to this crown than the software. Might be better to change behavior of XF86AudioRaiseVolume, XF86AudioLowerVolume and XF86AudioMute instead..

One thing that would be useful is to run bin/solaar -dd and capture the output when you do things with the crown.

@pfps pressed and turned right, left. Doesn't seem to react to touch at all [ which it does under win/mac, mostly for tool change, so via software layer ]
```
12:46:38,069 DEBUG [ReceiverListener:hidraw0] logitech_receiver.base: (17) => r[20 02 03CD 0000003200003E00000000]
12:46:38,342 DEBUG [ReceiverListener:hidraw0] logitech_receiver.base: (17) => r[20 02 0300 0000003200000B00000000]
12:46:40,615 DEBUG [ReceiverListener:hidraw0] logitech_receiver.base: (17) => r[20 02 03E9 0000003200002200000000]
12:46:40,623 DEBUG [ReceiverListener:hidraw0] logitech_receiver.base: (17) => r[20 02 0300 0000003200000B00000000]
12:46:41,923 DEBUG [ReceiverListener:hidraw0] logitech_receiver.base: (17) => r[20 02 03EA 0000003200002100000000]
12:46:41,931 DEBUG [ReceiverListener:hidraw0] logitech_receiver.base: (17) => r[20 02 0300 0000003200000B00000000]
12:46:45,163 DEBUG [ReceiverListener:hidraw0] logitech_receiver.base: (17) => r[20 02 0101 0000000000000000000000]
12:46:45,406 DEBUG [ReceiverListener:hidraw0] logitech_receiver.base: (17) => r[20 02 0101 0600000000000000000000]

```

@barolo Thanks. The crown is producing USB HID consumer codes - play/pause, volume up, volume down. If the only way to modify how the Crown works is to divert it to HID++ then Solaar isn't going to help. If, however, these codes can be modified (using PERSISTENT_REMAPPABLE_ACTION) Solaar can do something.

I think that it only would be useful if it would be possible to assign custom ones like ctrl-Z | ctrl+Y, back/forward, undo/redo stuff. For the dial

@barolo If reassignment is possible then it is likely that reassignment to any key or consumer control is possible. But it may be that the HID reporting for the crown cannot be changed.

Here is my current understanding of what is going on with the Craft's "crown".

Normally an event (key press/release, etc., etc.) causes an HID device to send an HID message to the computer. Pressing the Tab key sends a Tab key down message. Pressing the Volume Up key sends a Volume Up consumer control message.

Logitech devices can be commanded to send a different HID message for some events, so the Volume Up key could send a Tab key down message. Which events can be changed and which messages they can be changed to depends on the device. Solaar is set up to do some of these changes.

Logitech devices can also be commanded to send an HID++ message for some events, so the Volume Up key could send a Volume Up HID++ message. This is, I think, how the crown on the Craft is handled. But these HID++ messages have to be interpreted by software. The Logitech software does this and gets information on what application is active so that it can determine how to interpret the HID++ message (usually by emulating the sending of an HID message that is important for active application).

Solaar is not set up to do this. Theoretically it would be possible for Solaar to do this, but it would probably be quite a bit of work (and changing automatically depending on the active application might not even be possible).

Yeah, you'd have to reverse engineer what LogitechOptions does pretty much, which I didn't expect to happen. It has its own API [ the crown ] and sdk for contextual in-app plugins.
But to make it minimally usefull at least I'd hope to see the possibility of assigning undo-redo shortcucts or horizontal scroll for video scrubbing.
Active app detection shouldn't be too hard but it's not something I'd expect from solaar of taking upon itself.
It also has a pressed state which is completely wasted under Linux.

I created small daemon that can react to crown events: https://github.com/prefiks/crown-controller. It's pretty basic, right now it allows only to simulate key presses, but i still find that useful.

It's written in rust, so you need that available to compile it, but you can find precompiled binary in https://github.com/prefiks/crown-controller/releases/tag/v0.1

How does the daemon work? Does it respond to the volume up/down keypresses that the crown normally generates or does it divert the crown and then handle the HID++ events?

There is a way to switch it from sending volume keys to sending custom events (it looks like it uses crown feature, it just something that i sniffed from windows driver does), and then in reacts to those event

@prefiks really cool, it does what I wanted pretty much [ but it doesn't work ]

@prefiks I think what you are doing is "diverting" the crown, using feature CROWN=0x4600. If you are blindly sending a command to the device to divert the crown then your code may only work for the firmware in your device and others may need to use a different command. I should be able to quickly add a setting in Solaar to do this diversion, which should then work for any device with a crown.

There are actually two commands, they are used for enabling/disabling ratchet on crown, sending any of them also disables that default behaviour where volume/playback keycodes are sent instead of hid++ events.

PR #960 adds a setting to divert crown events to HID++ messages. It can be used in the GUI or (assuming you have one Craft keyboard) as

solaar config Craft divert-crown true

to divert (false to send normal Volume keypresses). Try it out if you have a keyboard with a crown.

To download and work with Solar

git clone https://github.com/pwr-Solaar/Solaar.git
cd Solaar

Run Solaar as bin/solaar from this directory.

To run PR #960, first clone Solaar if you have not already done so and cd to the clone directory. The first time you download the pull request, fetch it into a new branch and checkout that branch, as in:

git fetch origin pull/960/head:pull_960
git checkout pull_960

To download a new version of the pull request, fetch it and then set your pull branch
to the new fetch, as in:

git checkout pull_960
git fetch origin pull/960/head
git reset --hard FETCH_HEAD

It works but that's just for testing purposes isn't it? just disables its media keys functionality basically @pfps

The crown has several features, including diverting to HID++, turning the ratchet on and off, and changing timeouts (for long presses, double tap, and rotation). Not all features may be available on all crowns, but diverting appears to be a universal feature.

@barolo Well it is similar to the other settings that divert to HID++. But the Solaar command could be used to reliably divert the crown and then @prefiks code could be used to do something useful with the HID++ messages.

Alternatively something could be added to Solaar to process the diverted messages. PR #733 does something with diverted mouse motions caused by pressing the DPI switch on an MX Vertical. I wasn't in favour of Solaar doing this but I can see the advantages.

@pfps I'm think it will be really useful to have separate daemon, but included in solaar distribution to parse make some action on HID++ events. It can be very useful, for example, to have control over vertical and, more important, horizontal scroll speed, etc

@doctor64 I'm not against the idea, but any such daemon will likely need a good design. Hopefully the daemon will not need special privileges. But if no special privileges are needed then Solaar already is listening to HID++ events and could simulate input events so maybe adding this capability to Solaar is reasonable?

So feel free to develop this idea further. :-)

@prefiks Too bad your daemon isn't written in Python. If it was it might be possible to integrate it into Solaar.

@prefiks Is it OK if I take your idea, generalize it, and pull it into Solaar?

Of course, i just write it as separate daemon mostly because i don't know python that much.

@prefiks I noticed that your code is sensitive to the modifier keys state on the keyboard. Is this something that the Logitech software does?

No, from what i seen, logitech shows window with multiple functions per app, that you can switch between by touching dial (so you can have let say zoom as one function, brush size as another, etc), and what happens when you rotate depends on what function is selected.

In supported apps, via plugins in them, you have per tool context you switch with touch tapping and value change via dial. e.g Brush [ Photohop ], you tap to switch the kind and dial to change the size, even during painting.
Of course it's out of scope for solaar

I have implemented much of @prefiks system in Solaar. I'll create a new enhancement issue for this new capability.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cement-head picture cement-head  路  5Comments

Petross404 picture Petross404  路  5Comments

hoemon picture hoemon  路  14Comments

AlexWayfer picture AlexWayfer  路  21Comments

meson11 picture meson11  路  5Comments