37
votes

Short version of what I want to accomplish: I have a foot pedal (INFINITY-IN-USB-1, if that's of any interest) that is implemented as a generic HID device, and I would like it to be behave as Ctrl and Alt keys on Linux. I'm looking for something on the level on X, i.e. not just individual programs.

Longer version: I have this setup working in Windows XP by calling DLL functions RegisterRawInputDevices and GetRawInputData and listening to the input in a hidden window. All is accomplished with a fairly straightforward AutoHotkey script (I can post here if anyone is interested). The point is, there isn't any need for any extra driver, etc.; only the native Windows DLL files are needed.

I want this setup to work on Linux (more specifically GNOME under Ubuntu, but I do occasionally use other distributions/window managers, so a solution on the level of X is appreciated). This foot pedal does not register itself as keyboard or even joystick, but as a HID device with UsagePage 12, Usage 3.

I notice that the latest Ubuntu can detect and use the favorite keys on the Microsoft Natural Keyboard, which also register as HID device*. I make use of those keys on Windows using the same method as I use the foot pedal (i.e., without the bundled software). So I assume that this pedal thing can work on Linux as well, but the question is how?

(I'm new to the lower-level stuff on Linux, so please be generous with links to introduction or tutorial whenever applicable.)

* For those not in the know, the Microsoft Natural Keyboard registers as both a regular keyboard and a generic HID device. Without some application (such as the bundled application) knowing how to interpret the HID input, the regular keys will work, but the favorite keys and the special function keys are useless.


To clarify, Linux is not seeing the pedal presses as input. It does recognize the USB device, but xev doesn't give any output for pedal presses. I have seen reports of people successfully using the pedal under Wine for transcription software, but that must work in a Windows way and does not give what I want (which is making the pedal look like a keyboard to all native Linux applications). Is some low-level Linux keyboard driver needed?


Here's some more information: If I issue this in the terminal

cat /dev/usb/hiddev0

(dev/usb/hiddev0 is my pedal), I get raw codes corresponding to my pedal presses. That's a start. I know what those raw code means: in binary, 0001, 0010, 0100 corresponds to each pedal, respectively, and combination of pedal presses sends combination of those binary number, and releases of pedal trigger input of whatever pedal still being pressed (if all pedal is up, 0000 is sent).

How can I get X to listen to dev/usb/hiddev0 and translate the raw codes into maybe a special keycode so that I can map them with xmodmap or something?

6

6 Answers

22
votes

You'll want uinput. You'll listen on your /dev/usb/hiddev0 and then create new events that you'll send out on /dev/input/uinput.

This explains it and gives a little tutorial: Using uinput driver in Linux- 2.6.x to send user input {This is the EInfochips' "Dashboard" publication issue January 2007 "Tip of the Month" article mentioned on this archived page}.

5
votes

If the device shows up in /dev/input, use the "evdev" X driver to hook it up just like you would do for a keyboard or mouse.

4
votes

I wrote about how I got my Infinity IN-USB-1 (AKA "VEC USB Footpedal") to send arbitrary keysyms under X on my weblog:

Use VEC/Infinity USB Foot Pedal as a Keyboard Under Linux

(It should also work for IN-USB-2 and maybe some other USB foot controller models sold by VEC and P.I. Engineering and their clones.)

Here is the shorter version:

Get X to recognize the pedal

The pedal is an HID-compliant USB device and the kernel has no problem discovering it and making its events available to userspace via a /dev/input/eventX node. To see that you can run the evtest program (on Debian: sudo apt install evtest). So you don't need to go to the HID level to use the foot pedals.

The problem is that udev does not tag it as a keyboard or mouse, so X ignores it. This can be fixed with a one-line udev rule file (thanks to Parlatype developer Gabor Karsay for providing this solution in Parlatype Issue 28):

ACTION=="add|change", KERNEL=="event[0-9]*", ATTRS{idVendor}=="05f3", ATTRS{idProduct}=="00ff", ENV{ID_INPUT_KEYBOARD}="1"

Put that line in a file called /etc/udev/rules.d/10-vec-usb-footpedal.rules. No need to restart anything, udev should automatically detect the file.

Now when you unplug and replug the USB pedal, it should be recognized by X (and send mouse button events). To verify, run xev.

Remapping keysyms with udev hwdb

Having a pedal that sends only mouse clicks is probably not what you want. This key codes sent by the pedal switches can be remapped with a udev hwdb file.

Create a file under /etc/udev/hwdb.d/ (I put mine in /etc/udev/hwdb.d/60-usb-footpedal.hwdb) containing these lines: /etc/udev/hwdb.d/60-usb-footpedal.hwdb

evdev:input:b*v05F3p00FF*
 KEYBOARD_KEY_90001=f14
 KEYBOARD_KEY_90002=f15
 KEYBOARD_KEY_90003=f16

This time we do need to inform the system to update the binary hwdb file:

$ sudo systemd-hwdb update

And then unplug and repug the device.

The first line of the hwdb file matches our device (vendor 05F3, product 00FF), and the subsequent lines map a scancode (hex) to a keycode. I chose the F14, F15, and F16 function keys, but a list of available keycodes is defined in /usr/include/linux/input-event-codes.h; to use the names #defined in that file as hwdb keycodes, simply convert them to lowercase and remove the key_ prefix.

The default (pc+us) xkb keyboard layout on my computer maps F14, F15, and F16 to the XF86Launch5, XF86Launch6, and XF86Launch7 keysyms, respectively. If you open xev now and press the pedals, you should see those keysyms emitted. Using those keysyms, each pedal switch can be mapped as a hotkey in your desktop or window manager.

You can also remap the XF86* keysyms to other keys using something like xmodmap. For more details, including getting the keys to be mappable in vim, more links to documentation, pointers toward reading the HID device directly if you want, and a solution for Mac OS X, see my weblog post

Footcontroller

One last thing I will mention is a python program called footcontroller that reads events from the evdev device (/dev/input/eventX) and can be configured to issue key strokes (via xdotool) or run scripts in response to stepping on the pedals. It can be used in lieu of xmodmap to get your pedal to send any key stroke you want.

2
votes

You should investigate LIRC. It interprets input from remote controls. Some supported remotes apparently present themselves as generic HID devices, so you may be able to get your device to talk to LIRC.

2
votes

Same problem here, but with special keys on a wireless keyboard. I feel your pain.

Anyway, trying to get this to work, here's my method:

  1. sleep 10; killall cat then quickly in another terminal: cat /dev/usb/hiddevice0 > key1.usbdump and press/use the device. This will dump the hiddevice's binary output for that key.
  2. I quickly hacked together a Python script to read the hiddevice input and fire events. So far it works for the first time the key is hit. This is similar to what Adam suggested, but I think uinput is more difficult to program/use although perhaps more elegant, and Python is readily available.

So this is a work in progress (only works for the first time pressed), but maybe something like this could work for you:

sf1 = open("test.usbdump").read() # Read the earlier USB dump from hiddevice
kb = open("/dev/usb/hiddev0")
while 1:
    # Prints true if the specific key has been read.
    print (kb.read(len(sf1)) == sf1)
    # Basically all that has to be done is if ^ is true, then fire off the event you want.

If anyone can help me out with my program or if I'm doing this wrong, please tell me. ;)

I realise that there are some headers being included in the initial dump of the hiddevice. Using some bless hexadecimal editing and bit differencing, you could find which values are important and make a check for them in Python. (For example, the hexadecimal digit "B0" means a special function key has been pressed on my keyboard, and later on there is more information on which key was pressed, etc.)

My end result is this: hiddevice0 seems to hang and stop giving data after a while, not sure why, but instead, I use /dev/input/event* (it might work for you too), and that seems to work better. Again, the same hexadecimal editing and low-level parsing leads to success. Along the way I found that sudo cat /dev/input/event3 | hexdump is extremely helpful in determining which bytes are important to you.

So, if you have an SK-8812 IBM keyboard, and would like to use the special keys, you can talk to me to get the script I used.

0
votes

For my binding/shortcuts I use a combination of Compiz, easystroke and xmacro.

For your needs, I think the missing piece is xbindkeys. I have found this link for you that maybe helps you to set this up:

http://linux-trackball.dreamhosters.com/

I wonder anyway whether there is a way to distinguish between several mouse devices.