tuxmark5 / ApexCtl

An utility to enable extra macro keys on Steelseries Apex keyboards
GNU Lesser General Public License v3.0
101 stars 19 forks source link

Keys are bound to random other keys? #4

Closed kiwistrongis closed 10 years ago

kiwistrongis commented 10 years ago

Hey, thanks for working this out :)

So what are the keys supposed to be bound to? For me, a bunch of the MX keys are bound to media keys and stuff (even though the apex already had media keys). Also, the colour profile buttons aren't supposed to work, right? I'm glad they're disabled at least XD . I used to keep accidentally hit them instead of Esc.

Also idk haskell, and I'm open to learning it. How (programmatically) easy would it be (for me) to make a tool that can set key codes for the macro keys and colour zones, etc?

Sorry for the wall of text, I'm just excited to finally get my awesome keyboard working on my favorite OS :).

Zimmux commented 10 years ago

Not all key codes available for Windows seem to work for Linux.

SteelSeries don't seem to publish their protocol, so we are reverse engineering it. For instance, I witnessed the packets listed below, but don't know what they do. We might have to send some of these to fix the key bindings to match those seen on Windows.

09 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

10 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

16 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

22 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
kiwistrongis commented 10 years ago

How are you doing it? A vm with windows and listening with wireshark? usbmon? Also, I don't suppose anyone's tried just asking steelseries for help? XD

tuxmark5 commented 10 years ago

Hey KiwiStrongis, you can already change color zones programmatically with ApexCtl. All you need to do is to change/uncomment the relevant line: --apexSetColorProfile devHndl cp0 to apexSetColorProfile devHndl cp0

The cp0 'variable' describes color profile which is defined towards the top of the file: cp0 = SetColorProfile colorRed colorRed colorRed colorRed colorRed

colorRed is defined using 4 components: red, green, blue and intensity, which can change from 0 (off) to 8 (max intensity): colorRed = Color 0xFF 0x00 0x00 0x08

A few example colors and color profiles are already defined.

Now for key codes, these can be changed using external tools. The way (more or less) USB input works is:

  1. Keyboard generates a scancode, which is just a key number you pressed.
  2. USBHID driver passes the scancode to evdev, which translates series of key presses to meaningful key events (this is used for VT, possibly wayland).
  3. X Server pulls raw scancodes from evdev and uses it's own separate translation method of scancodes to keyevents, which takes into account the keyboard layout you are using and other settings. (That is just my understanding of the whole process, I might be wrong)

So basically all you need to do, is to create a custom ~/.Xmodmap file, which rebinds custom scancodes to something more meaningful, like F13, F14, ..., F35.

tuxmark5 commented 10 years ago

I just googled a bit and it seems that the problem is in keyboard-specific scancode to keycode mappings, which only later get pet passed to evdev and to X server.

Here is a bit more info on the subject: https://wiki.archlinux.org/index.php/Map_scancodes_to_keycodes Later I'll try to create a custom udev mappings file, which should fix the problem Zimmux was mentioning (that several keys translate to the same keycode).

Zimmux commented 10 years ago

Do the M8 - M12 keys work for you? They did not show any keypresses through showkey if I remember correctly, I haven't tried with xev. Can you share your ~/.Xmodmap file?

tuxmark5 commented 10 years ago

I am using custom utility that takes events directly from evdev and executes commands when necessary, so I bypass the X11 layer entirely and therefore do not have (yet) an appropriate Xmodmap file. So M9-M12 keys do work for me, but only in this low level setting.

tuxmark5 commented 10 years ago

Ok, I've added a few things to get everything working properly: 1) config/90-apex.hwdb file, which adds necessary scancode to keycode bindings 2) config/Xmodmap (which should be placed to ~/.Xmodmap), which adds keycode to keysym bindings Now:

3) config/90-apexctl.rules file, which provides udev rule that automatically invokes /usr/local/bin/apexctl when Apex or Apex Raw keyboard is plugged in.

kiwistrongis commented 10 years ago

Cool, I'll give it a try when I get home tonight (my apex is at home). Maybe I'll work on a script for setting the colour/brightness for the zones. I was thinking something like command [-c|--colour north|south|east|west|logo|n|s|e|w|l #ffffff] [-b|--brightness (0..8)]. Idk what to call the command. Can I just tack it on to apexctl?

Also, I think you made a mistake. M1-M12 is 12 keys, but F13-F23 is 11. Also MX1-10 is 10 keys, but F25-35 plus XF86Launch5 is 12.

How you apply the udev rule? Like this?:

cp config/90-apexctl.rules /etc/udev/rules.d/
udevadm control --reload-rules
tuxmark5 commented 10 years ago

Yes, you are right. Two keys were unnecessary. And color management should be included directly into apexctl, but I was just too lazy to implement it at the time. As for reloading udev rules, after copying both files (.hwdb and .rules), i just: 1) sudo udevadm hwdb --update 2) sudo udevadm control --reload

kiwistrongis commented 10 years ago

Mkay, I'll write the colour management into apexctl tonight, if you're cool with that. :)

Does running apexctl repeatedly cause problems? It just resets the keys, right? Also, should we be storing profile data in a config file? At least for the colours, having a config file would be good, right? And would an install script be a good idea? Just being able to to `make && sudo make install`` would be nice.

tuxmark5 commented 10 years ago

I'm working on command line args right now, so you won't need to code it.

Running apexctl does not seem to cause any problems. However when I was developing the utility, if I changed colors really quickly (with no delay, like 1000 times per second or something), from time to time the keyboard would crash and would take the whole hub down with it. So in order to get back everything working, I had to reset the hub.

As for install script - I'm not sure whether make is the best way to do things, because Haskell uses cabal as it's build system and it is capable of installing binaries (by default it installs everything to ~/.cabal/bin; I haven't tried running 'cabal install' with root though).

kiwistrongis commented 10 years ago

Okidoke, aha. I was looking forward to some haskell practice. XD Maybe I'll write a gui for apexctl :).

I'm just thinking of packaging problems, when you install an rpm or dep, it would install to /usr/bin, not ~/.cabal/bin. You might not even have cabal installed, right?

tuxmark5 commented 10 years ago

Sorry from robbing you of opportunity for practice. I saw your comment when I was already working on it.

Anyway, I've just pushed a restructured version of apexctl with a bit nicer code and command line options.

A gui might be nice for this, but I don't think that Haskell has any nice GUI libraries. Most of them have more or less 'raw' bindings of C libraries. Though there exist some more Haskelly (and more exotic) abstractions for those libraries, but I don't think that Haskell community has come up with anything that is practically usable.

Cabal is necessary only for building apexctl. If you want to package it to rpm or deb, when you could package the apexctl just like a regular binary, since it has no external haskell dependencies (Haskell programs tend to be compiled statically). Though it will still depend on libusb.

I'd love a deb package for this though. I've never done anything packaging related, so I'm noob on that subject.

kiwistrongis commented 10 years ago

Oh, that's okay :). I'm completely new to haskell, I'm sure your work is better.

Re: gui - I was planning on doing it with gtk3/c++, and just use system calls to apexctl. Re: packaging - I'm a packaging noob too, just I really wanna learn it. I'm thinking that just a standard ./configure && make && sudo make install is probably more appropriate for this project, aha.

Also, were you planning user profiles of some sort?

tuxmark5 commented 10 years ago

Nope. I hadn't thought about user profiles. If you want, you can implement those :)

kiwistrongis commented 10 years ago

Mkay, I'll take crack at it tonight or tomorrow night. I'm just about to leave work, so it'll be soon. What time zone are you in? I just wanna know if you'll be available for help tonight. I'm in EDT (UTC - 4).

tuxmark5 commented 10 years ago

I live in GMT +2, so 6 hour difference. I usually stay up till 4:00 AM GMT +2.

Zimmux commented 10 years ago

This seems a bit off topic so I'll use this as a discussion thread.

Sorry about the many branches, didn't know github created a new one when clicking edit through the browser interface.

tuxmark5 commented 10 years ago

No problem.

kiwistrongis commented 10 years ago

so how does this makefile look to you? I think I got everything.

I also got to try your changes. The keys don't map to what you said they did - and a number of keys are duplicated. I'll write down what each key is currently mapped to tonight. Also the colour stuff was nice, with a bit of experimenting, I managed to get very close to the colours I like. The brightness is a bit bugged though, you can only set the brightness for the south zone - all the others are at maximum.

One other thing, mind if I markdown-ify the readme? :) I wanna make it prettier and stuff, aha.

tuxmark5 commented 10 years ago

Makefile looks great.

Brightness control is mainly intended for Apex [RAW] keyboards, where exists only one 'color' zone. If you want to adjust brightness on Apex keyboard, you should use this color notation: RRGGBB:A, where A is brightness. Or: RGB:A (a shorter version of the same thing). It's not documented, but it should be.

Also I would really accept all the help regarding proper version of README.

Today I also noticed another problem regarding 90-apexctl.rules file, which calls apexctl whenever you plug in the keyboard or on startup. Apparently, when apexctl is invoked, it counts as a short keyboard unplug/plug, which causes another invocation of apexctl and so it begins to recursively loop and spam a lot of apexctl invocations. I'm not sure whether this can be fixed by tweaking the rules file further. So probably additional apexctl mode is required (like apexctl boot or something), which before running should check when was the last apexctl invocation. If it was less than 3-5 seconds ago, apexctl should just quit without doing anything, thus preventing the loop.

kiwistrongis commented 10 years ago

What's the range for the values? The RRGGBB is obviously hex like ffffff:A. The range for A is 0..8, inclusive, right? What's the RGB:A format? 000:0 to fff:8 or 999:8?

One other thing, I think it's better to install to /usr/bin than /usr/local/bin. Have a look at this rant for the reasons, or just try:

sudo -s
echo $PATH

Maybe /usr/local/sbin would work?

Re: readme - I'll do that tonight, after work. It'll probably end up looking something like this, but with a few different sections. Also, have you thought about licenses? The MIT license is probably appropriate.

Re: makefile - Thanks :).

tuxmark5 commented 10 years ago

RGB:A format is 0-F inclusive for R, G and B. And 0-8 inclusive for A.

For installations I think we should use /usr/local/sbin then, because everything in /usr/bin is usually managed by a package manager.

I usually slap LGPL on everything I create. Though MIT might be suitable too. Not sure which one is better.

kiwistrongis commented 10 years ago

Unfortunately /usr/local/sbin won't work :(. It has to be one of the following to work with sudo:

[kiwistrongis@blackbox ^_^ opt]$ sudo -s
[sudo] password for kiwistrongis: 
[root@blackbox ^_^ opt]$ echo $PATH
/sbin:/bin:/usr/sbin:/usr/bin

and

[kiwistrongis@blackbox >_< ~]$ ls /usr/local/sbin
apexctl
[kiwistrongis@blackbox ^_^ ~]$ sudo apexctl 
sudo: apexctl: command not found

/usr/sbin is probably best? This is kinda a distro-specific problem though, a solution could be to add /usr/local/sbin to the secure_path in /etc/sudoers, if the distro requires it. I don't think this should be done by the install script though.

I just added LGPL 3 to my fork :). Feel free to pull. I was looking at choosealicense.com/licenses, and I think I like LGPL more. I think I'll use it for my projects in the future.

kiwistrongis commented 10 years ago

Another alternative is

sudo -i apexctl
tuxmark5 commented 10 years ago

I'm using (L)Ubuntu, so pretty much everything you can think of ends up in $PATH.

Also, would you mind sending me a pull request for the changes you've made?

You also previously mentioned that some key bindings are duplicated. Could you elaborate a bit more on that?

kiwistrongis commented 10 years ago

Pull request sent. Just FYI, you can always do:

git remote add kiwi https://github.com/KiwiStrongis/ApexCtl.git
git fetch kiwi
git merge kiwi/master

The L keys and M9 through M12 all give 0x0f with xev (i dont remember the key code). Some of the media keys (the right-most column) are duplicated on some of the MX keys, but i don't remember the specifics - I'll have to check when i get home. I think it was like this MX1 - Play MX2 - Stop MX6 - Volume Up MX7 - Volume Down MX8 - Mute I probably need to customize my ~/.Xmodmap

tuxmark5 commented 10 years ago

It seems that you haven't applied your Xmodmap at all. All extra keys should translate either to F* keys or to XLaunch1-XLaunch4. I have a script that (among other things) on startup calls "xmodmap ~/.Xmodmap". I know that some environments/DEs used to do or still do this automatically.

kiwistrongis commented 10 years ago

I'm pretty sure I did. Give me a couple (4) hours to get home and double check :).

Zimmux commented 10 years ago

For Apex RAW, I still can't get L1, L2, M9-M12 to send anything useful. The MX1, MX3 and MX4 keys overlap with media keys. The other codes seem arbitrary, but are at least distinct:

MX1   172 = Play/Pause
MX2   174
MX3   173 = AudioPrev
MX4   171 = AudioNext
MX5   169

M1    144 
M2    185
M3    186
M4    184

M5    150
M6    160
M7    181
M8    148

M9    248
M10   248
M11   248
M12   248

L1    248
L2    248
kiwistrongis commented 10 years ago

I made a whole bunch of changes. The only change i thought you might object to is that i renamed reset-usb to apexctl-reset. Lemme know if you want me to put it back or if you have a better idea for a name.

Also I mapped out what all my keys are currently bound to with xev: keys.txt

M1    144 = Find
M2    185 = F31
M3    186 = F32
M4    184 = F30
M5    xxx = Sleep
M6    xxx = Lock
M7    181 = F27
M8    148 = XF86Calculator
M9    248 = NoSymbol
M10   248 = NoSymbol
M11   248 = NoSymbol
M12   248 = NoSymbol

MX1   172 = XF86AudioPlay
MX2   174 = XF86AudioStop
MX3   173 = XF86AudioPrev
MX4   171 = XF86AudioNext
MX5   169 = XF86Eject
MX6   123 = XF86AudioRaiseVolume
MX7   122 = XF86AudioLowerVolume
MX8   121 = XF86AudioMute
MX9   158 = XF86WWW
MX10  166 = XF86Back

L1    248 = NoSymbol
L2    248 = NoSymbol
L3    248 = NoSymbol
L4    248 = NoSymbol

V+    123 = XF86AudioRaiseVolume
V-    122 = XF86AudioLowerVolume
Vmute 121 = XF86AudioMute
Mprev 173 = XF86AudioPrev
Mnext 171 = XF86AudioNext
Mpaus 172 = XF86AudioPlay
tuxmark5 commented 10 years ago

A few notes: reset-usb script is/was used to reset a specific hub in my machine. There is no guarantee that it will work on any other machine. So it should be either removed or parameterized with a variable that allows specification of target hub.

Regarding wrong key mappings: It seems that 90-apex.hwdb has failed to remap keys on your machine. Make sure that your distro allows placing hwdb files in /etc/udev/hwdb.d. Also check what is your udev version (hwdb file contract may change between different udev/systemd versions). Also try using evtest utility to see which scancodes translate to what keycodes. Test just M9-M12 keys and paste the results here.

Also try using: sudo udevadm test /sys/class/input/inputXX, where XX should correspond to your Apex keyboard input id. It should show whether hwdb mappings have been attached to XX input device.

Zimmux commented 10 years ago

Hmm, things have started working. :D

I probably forgot to reboot after changing the Xmodmap or hwdb.

kiwistrongis commented 10 years ago

How does this look?: https://github.com/KiwiStrongis/ApexCtl/blob/master/apexctl-reset What was the reason for the sleep between the unbind/rebind?

Fedora supposedly does support the hwdb.d folder. I couldn't figure out how to check the udev version, though.

The evtest log: github.com/KiwiStrongis/ApexCtl/blob/master/log.txt Weirdly enough there's two entries, one just for the media keys.

With evtest I was able to figure out the scancodes. I guess I just need to change my hwdb file to match them?

tuxmark5 commented 10 years ago

Zimmux: that's good to hear that you have everything working.

KiwiStrongis: The script looks awesome. As for sleep, I don't really remember why I put it there. In general, a 'normal' user shouldn't ever need to reset an USB hub. It's more of a measure of the last resort when you want your USB ports operational without rebooting the whole OS.

And you don't need to change anything, because we have the same model and our scancodes match. All you need to to is to figure how fedora handles hwdb files/where to place them/how to activate them (the log you posted proves that your udev currently does not 'see' the hwdb file; there should be an entry for each 700xx key there). Check /lib/udev/hwdb.d folder, that's where Ubuntu puts hwdb files that are managed by package manager.

kiwistrongis commented 10 years ago

Yeah /lib/udev/hwdb.d has a number of hwdb files, and I'm sure that'd work, but shouldn't non-package-manager-managed files stay out of there? (I'll try it tonight.)

I'll rename it to apexctl-resethubs? or reset-usbhub? Maybe it should be removed :S.

kiwistrongis commented 10 years ago

I was thinking - I'll add a user confirmation and warning to the script.

tuxmark5 commented 10 years ago

The script still could be useful for those who would like to add extra commands/functionality.

kiwistrongis commented 10 years ago

I've tried both /lib/udev/hwdb.d and /etc/udev/hwdb.d. man udevadm (and this forum post says they're both read from. I'm going to try rebooting with both, I guess.

I tried the udevadm test thing: https://gist.github.com/KiwiStrongis/9569981

Also, pull request. I made the readme pretty. Lemme know if you have any suggestions :).

tuxmark5 commented 10 years ago

Can you find 60-keyboard.hwdb file in your installation and upload it to gist? It could be that hwdb file contract is different in your machine.

kiwistrongis commented 10 years ago

There isn't one O_o maybe I accidentally deleted it? I'll see if i can grab it off a livecd.

tuxmark5 commented 10 years ago

Can you try then to find ANY *.hwdb file and upload some of them?

kiwistrongis commented 10 years ago

Here's all of them, but they just seem to be vendor identification stuff.

https://gist.github.com/KiwiStrongis/9598915

tuxmark5 commented 10 years ago

And does your installation anywhere contain 60-keyboard.rules file?

kiwistrongis commented 10 years ago

No, but I found one 95-keymap.rules that looks like it adds the mappings for some other special keyboards.

https://gist.github.com/KiwiStrongis/9602926

tuxmark5 commented 10 years ago

So that means that your udev (or systemd) is simply outdated and you need to upgrade.

kiwistrongis commented 10 years ago

I don't suppose you know which version of systemd adds the necessary support, or how new is the required features are? I was thinking i could just write a .rules file based on the keymap.rules for myself.

tuxmark5 commented 10 years ago

Unfortunately I don't think you can write your own .rules file, because keymap support is integrated directly into udev and depends on udev built-in commands. The minimum required systemd version is v206 which was released 8 months ago.

kiwistrongis commented 10 years ago

Mine (on fedora 19) is 204 :(. I guess I'll check if fedora 20 has it, and upgrade if it does.

kiwistrongis commented 10 years ago

So fedora 20 has 208, and i've been lusting for korora for a while now. I'm planning to upgrade this weekend. I'll let you know how it goes :).