strodgers / epomaker-controller

37 stars 3 forks source link

Support for key mapping? #32

Closed cskau closed 1 month ago

cskau commented 1 month ago

Do you plan on supporting key mapping?

strodgers commented 1 month ago

I did go through and work out all the key mappings (the KeyboardKey class) so this could be possible

Do you mean mapping just like a colour for each key, or re-assigning the key value?

The only thing that stopped me was not knowing a good way for the user to actually set the RGB values per key since I don't really know about GUI stuff, but could give it a try. Or maybe just have a config file.

cskau commented 1 month ago

I was thinking of remapping the key layout of the keyboard. As in reassigning the key codes sent when a particular key is pressed.

I did notice the KeyboardKey class others, so I figure it's almost just a matter of sniffing the relevant USB packet from "Epomaker Driver" to create the corresponding initialization_data.

I've been trying and failing to set up a Windows VM to do this myself, but if I succeed I might put together a PR if there's interest.

strodgers commented 1 month ago

I was thinking of remapping the key layout of the keyboard. As in reassigning the key codes sent when a particular key is pressed.

I did notice the KeyboardKey class others, so I figure it's almost just a matter of sniffing the relevant USB packet from "Epomaker Driver" to create the corresponding initialization_data.

I've been trying and failing to set up a Windows VM to do this myself, but if I succeed I might put together a PR if there's interest.

Ah yes that should definitely be possible, I guess through use of 'macros'. They can be set using the Windows driver so should be able to work out how to replicate it

I sort of jumped the gun a bit and assumed you meant RGB assignments so I made this PR https://github.com/strodgers/epomaker-controller/pull/35

strodgers commented 1 month ago

@cskau I could probably do a little write up of how I've been capturing the packets and interpreting them? It's nothing special but might save you some time, currently I use a windows VM to run the official epomaker software and then capture with wireshark on linux (fedora)

cskau commented 1 month ago

Thank you for the offer! But I managed to get the VM running, so I've actually already mostly reverse engineered the "Key Setting" packet.

FWIW, It's basically:

f"1300{key_index:2x}00000000{check_sum:2x}{key_combo:8x}...{zero_pad_to_64_bytes}"

One interesting detail I've found though is that the "key_index" does not exactly match KeyboardKey as I believe this is more or less a sequence number of keys in the matrix going from top-left, down and right. So for the EP64 - since it has no F-key row - it skips the top row, and ESC is mapped to key_index=1, and several keys on the right side are also differently indexed due to the compact layout.

cskau commented 1 month ago

Oh and the key_combo is seemingly a sequence of up to 3 key codes where:

A B C ... Z  1  ... 0  ⏎  ␛ ...
4 5 6 ... 29 30 ... 39 40 41 ...

But mapping out each code is a bit of a pain, and it doesn't seem to follow any code page or encoding I recognise.

strodgers commented 1 month ago

Thank you for the offer! But I managed to get the VM running, so I've actually already mostly reverse engineered the "Key Setting" packet.

FWIW, It's basically:

f"1300{key_index:2x}00000000{check_sum:2x}00{key_combo:6x}...{zero_pad_to_64_bytes}"

One interesting detail I've found though is that the "key_index" does not exactly match KeyboardKey as I believe this is more or less a sequence number of keys in the matrix going from top-left, down and right. So for the EP64 - since it has no F-key row - it skips the top row, and ESC is mapped to key_index=1, and several keys on the right side are also differently indexed due to the compact layout.

I remember this top-left going downwards matrix from when I was working out the key mappings, I just made it sequential according to the byte order but maybe it would just be better to have the KeyboardKey maps use a matrix, to make it easier to support other keyboards? I never thought about this controller supporting anything other than the TH80, just since I mostly wanted to control the little screen, but could try and make it easier to add other Epomaker boards

cskau commented 1 month ago

But mapping out each code is a bit of a pain, and it doesn't seem to follow any code page or encoding I recognise.

FWIW, doing some sleuthing in the QMK repo, I realised the codes are more or less the USB HID codes: https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf#page=53

strodgers commented 1 month ago

But mapping out each code is a bit of a pain, and it doesn't seem to follow any code page or encoding I recognise.

FWIW, doing some sleuthing in the QMK repo, I realised the codes are more or less the USB HID codes: https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf#page=53

Just been playing around with this and for my RT100 I got the following data fragments and I think I can see what you mean now.

Remap FROM Remap TO Data fragment Relevant bytes
A B 13000900000000e3000005 0x09 -> 0x05
B C 13002800000000c4000006 0x28 -> 0x06
C D 13001c00000000d0000007 0x1c -> 0x07
D E 13001500000000d7000008 0x15 -> 0x08
Then resetting them: Remap FROM Remap TO Data fragment Relevant bytes
A A 13000900000000e3000004 0x09 -> 0x04
B B 13002800000000c4000005 0x28 -> 0x05
C C 13001c00000000d0000006 0x1c -> 0x06
D D 13001500000000d7000007 0x15 -> 0x07

So I see what you mean now about the USB HID codes (the final byte), since those all match up with what the keys are being mapped to, where as the from bytes seem to be something else. Strange that even when setting a key back to it's original state, the two numbers are not the same, however at least for my keyboard those first numbers do match up with the KeyboardKey indices. So I guess the only part missing for supporting a different keyboard is the numbers used internally by the keyboard to map keys eg a different set of KeyboardKey.

I wonder if I could set something up so that a user could work out their own key mapping, by changing the colours of keys one by one and having the user then just press that key to register it. Maybe a config file is in order to go with that.

cskau commented 1 month ago

Sorry I was a bit sparse on the details in my above comment - I didn't want a massive info-dump to derail the original question. :) But let me elaborate a bit.

There are basically four parts to the command:

  1. The command byte, which is the constant 0x13.
  2. The index of the physical key on the keyboard, which I arbitrarily called key_index above. This is probably either one or two bytes. But I don't have a keyboard with more than 255 keys to test that. This index is as mentioned basically the keys enumerated from top, left, going down and right. Meaning the Esc key will usually have index 0, backtick index 1, tab index 2, etc. Though in practice, the physical layout informs the exact values, and e.g. compact keyboards might skip rows and rearrange keys/indices. On my 60% keyboard Esc is index 1, Tab index 2, and since there are no F1-12, this row is skipped, leaving gaps in the sequence.
  3. The check sum at the end of the first 8 bytes appears to simply be check_sum = 0xff - (0x13 + key_index), hence for the "B" example above 0xff - (0x13 + 0x28) = 0xc4.
  4. The new key binding value ("key_combo") is a four byte sequence of keys that will be bound. So to bind "A", key_combo=0x00000400. "Alt" is 0x00e20000. "Ctrl + Alt" is 0x00e2e000. "Ctrl + Alt + A" is 0x00e0e204. "Fn" is 0x0a010000. And from the driver code it seems "Right Fn" is 0x0a010100.

The tricky part, as you say, is figuring out what the key_index is for a given key. I guess the "best" way would be to have configs for each model, same as the Epomaker software has. But that's also a pain to setup and maintain. So, yeah, perhaps the second best thing would be to use the RGB to help communicate which index is selected.

strodgers commented 1 month ago

@cskau yea I've never managed to find any config files online, but maybe it's possible to extract them by looking through the official software source code like this person did https://github.com/strodgers/epomaker-controller/issues/8#issuecomment-2240017588

Some sort of pattern might start to emerge if we map a few similar keyboards, I have a PR open for using a config file instead of hardcoded values for the KeyboardKey index which should make things a bit easier to manage (just need to test it a bit more). I will probably go ahead and add this interactive mode for creating a new keymap json.

Do you have anything to commit concerning a potential EpomakerKeyRemapCommand (or something like that)? If not I'll whip one up given the information you already found out. Then it would just mean creating a new keymap json for your own keyboard.

cskau commented 1 month ago

Do you have anything to commit concerning a potential EpomakerKeyRemapCommand (or something like that)? If not I'll whip one up given the information you already found out. Then it would just mean creating a new keymap json for your own keyboard.

I've not had a chance to do much coding on this, but I've put together a quick and dirty proof of concept: https://github.com/strodgers/epomaker-controller/pull/41

It works well enough that I can remap simple keys on my Gamakay TK68-HE, but it does not even try to implement anything other than that, meaning no modifiers or anything fancier than that.

The interface likewise is the most simple possible, requiring the raw key index and key code. This works well enough for me, but it is not very user friendly.

strodgers commented 1 month ago

@cskau I have added your changes in via https://github.com/strodgers/epomaker-controller/pull/43

There is now a couple of config files that you should be able to make use of. If you run the latest with some arbitrary command (like epomakercontroller --dev print) it should make you a config.json in $HOME/.epomakercontroller. There you can put in your keyboard description (eg Gamakay TK68-HE).

There's also an option for a keymapping config file (eg KeyboardKey indicies aka key_index values), you can either have a look at the default one and make changes yourself, or more preferably if you tell me the key_index values you already worked out for your keyboard I will add them in as an installed config. Don't worry about formatting a file for me or anything I can do that part.

Thanks again for your help!