I am finalizing the reverse-engineering of a linux driver for the Perixx MX-2000 IIB mouse. One of the features the mouse has is arbitrary button mapping. I can assign a button to produce various keys or mouse buttons. I have recorded a few button assignments available in the Windows driver, and figured out a few myself, but there doesn't seem to be a discernible (to me) pattern to map the whole address space.

The keys behave like this: Two bytes control a particular mouse button. I have learned a few keys and modifiers, and will post below. Setting the mouse button to the hex value gives me keyboard output when clicked.

keyboard output | hex value
a | 0x0400
b | 0x0500
c | 0x0600
z | 0x1D00
1 | 0x1E00
2 | 0x1F00
9 | 0x2600
0 | 0x2700
return | 0x2800
esc | 0x2900
backspace | 0x2A00
tab | 0x2B00
space | 0x2C00
Volume Up | 0x8000 (XF86AudioRaiseVolume)
Volume Down | 0x8100 (XF86AudioLowerVolume)

I've mapped through 0x8A00 but will spare you the whole table. The interesting things are that thing like XF86 commands appear pretty early, like in 0x6F00 is XF86AudioMicMute, or 0x6600 is the power off key.

As for the least significant byte, part of that is modifiers, applied as a mask. Ctl is (1 << 0), shift is (1 << 1), alt is (1 << 2) and super/meta/windows is (1<<3). So this way, shift+a (capital A) is 0x0402. Ctl+Alt+a would be 0x0405. All four modifiers give you 0x0F for the least sig. byte. Playing around with the high nybble of the LSB, say with values like 0x0440 gives me more keys, like XF86Mute. So it seems the address space is massive.

On top of this, there are some keys from the windows driver that presented as an entirely different scheme.

Output | hex value
aMouse Scroll up | 0x0143
Mouse Scroll down | 0xFF43
WWW Search | 0x2122
WWW Back | 0x2422
WWW Forward | 0x2522
Email | 0x8A21
Internet Expl Back | 0x8842 (presents as mouse button 8 in X11)
IE Forward | 0x9042 (mouse button 9)
Calculator | 0x9221
My Computer | 0x9421
Mute | 0xE220
Volume Up | 0xE920
Volume Down | 0xEA20

And a few mouse buttons:

output | hex
Left Click | 0x8142
Right Click | 0x8242
Wheel Click | 0x8442

and finally, these are internal mouse commands. They don't register any events on my linux machine, but do change things in the mouse's internal settings

action | hex

Cycle DPI setting | 0x034A
DPI increase | 0x014A
DPI decrease | 0x004A
Cycle mouse profile | 0x074A
Profile Up | 0x054A
Profile Down | 0x044A

And finally there is a special set that looks like 0x0a88 that point internally to macro memory.

I can't find any encoding schemes or keyboard mappings that might match this. Alphabetical keys? And If you notice, volume up is both 0x8000 and 0xE920 while vol down is both 0x8100 and 0xEA20. So somewhat of a light at the end of the tunnel that there is a consistent distance between those.

But really, I can't figure out a standard mapping this matches. Or any way to figure out all the keys without manually fiddling with the memory and looping through 0x0000 to 0xFFFF and clicking with xev each time.

Thoughts? is any of this familiar? or other patterns spotted?

edit: All key information I've mapped so far is in this gist including 0x0000 through 0xFF00 (leaving LSByte 0x00). So there is still a massive address space left. And it still makes no sense to me with the extra keys from the windows driver like 0x9421 = XF86Explorer

1 Answer 1


Those are 16-bit USB keyboard/Keypad scan codes. Please see Keyboard Scan Code Specification for details. Appendix C contains the complete mapping

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.