16

I want to write an application in Python that you can use with your default keyboard and a specially designed one for the application. I will design it simply by using a small numerical keyboard with stickers to give actions to the different keys. Both keyboards will be attached by USB.

However, when these keys are pressed, just their regular signals (numbers, operators and enters), will be send to Python and it will not be able to distinguish between the signals from the main keyboard and the special keyboard.

Because Python has (as far as I could find) no method for making this distinguishment, I want to do it on the OS itself. I will be programming it for the Raspberry Pi, so it will be Linux.

So, the main question: How can I remap the keys of a specific keyboard to other keycodes. I thought about using the F-keys which I won't use for other purposes; or just some characters that are not present on any keyboard (supposing that there are such).

Is this possible in Linux/Unix? And if so, how can I do it?

3
  • How is the keyboard going to be attached? You may want to read straight from the device. That's the most obvious way to me, although I suppose there's some better way. Commented Apr 15, 2013 at 13:30
  • I added that they will connect by USB. How can I read directly from the device using Python? Commented Apr 15, 2013 at 13:32
  • It looks like the not-accepted answer is a lot simpler than the accepted one. Commented Oct 21, 2017 at 3:17

3 Answers 3

17

If you're using Linux, the best way to distinguish between input devices is to use the Linux Event Interface. After a device's hardware-specific input is decoded, it's converted to an intermediate Linux-specific event structure and made available by reading one or more of the character devices under /dev/input/. This is completely independent of the programming language you use, by the way.

Each hardware device gets its own /dev/input/eventX device, and there are also aggregates (e.g. /dev/input/mice which represents the motion of all mice in the system). Your system may also have /dev/input/by-path and /dev/input/by-id.

There's an ioctl called EVIOCGNAME which returns the name of the device as a humanly-readable string, or you can use something like /dev/input/by-id/usb-Logitech_USB_Gaming_Mouse-mouse.

You open the device, and every time an event arrives from the input hardware, you'll get a packet of data. If you can read C, you can study the file /usr/include/linux/input.h which shows exactly how this stuff works. If you don't, you could read this question which provides all the information you need.

The good thing about the event interface is that you just find out what device you need, and you can read input from that input device only, ignoring all others. You'll also get notifications about keys, buttons and controls you normally wouldn't by just reading the ‘cooked’ character stream from a terminal: even dead keys like Shift, etc.

The bad thing is that the event interface doesn't return ‘cooked’ characters, it just uses numeric codes for keys (the codes corresponding to each key are found in the aforementioned header file — but also in the Python source of event.py. If your input device has unusual keys/buttons, you may need to experiment a bit till you get the right numbers.

5

An alternative approach (if your "keyboard" doesn't have many keys - many devices pretend to be keyboards) is to apply a keymapping to each keyboard specifically and ensure that keys are distinguished.

This is outlined here: https://superuser.com/questions/760602/how-to-remap-keys-under-linux-for-a-specific-keyboard-only. The main point being the setxkbmap takes a device argument.

If you are using the raw input approach the lsinput will find your raw device for you.

0

If you are using python - evdev

From the docs:

This package provides bindings to the generic input event interface in Linux. The evdev interface serves the purpose of passing events generated in the kernel directly to userspace through character devices that are typically located in /dev/input/.

This package also comes with bindings to uinput, the userspace input subsystem. Uinput allows userspace programs to create and handle input devices that can inject events directly into the input subsystem.

In other words, python-evdev allows you to read and write input events on Linux. An event can be a key or button press, a mouse movement or a tap on a touchscreen.

and later on the Tutorial page...

Reading events from multiple devices (using select)

>>> from evdev import InputDevice
>>> from select import select

# A mapping of file descriptors (integers) to InputDevice instances.
>>> devices = map(InputDevice, ('/dev/input/event1', '/dev/input/event2'))
>>> devices = {dev.fd: dev for dev in devices}

>>> for dev in devices.values(): print(dev)
device /dev/input/event1, name "Dell Dell USB Keyboard", phys "usb-0000:00:12.1-2/input0"
device /dev/input/event2, name "Logitech USB Laser Mouse", phys "usb-0000:00:12.0-2/input0"

>>> while True:
...    r, w, x = select(devices, [], [])
...    for fd in r:
...        for event in devices[fd].read():
...            print(event)
event at 1351116708.002230, code 01, type 02, val 01
event at 1351116708.002234, code 00, type 00, val 00
event at 1351116708.782231, code 04, type 04, val 458782
event at 1351116708.782237, code 02, type 01, val 01

You can handle each device separately.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.