0

I've a RaspberryPi 3 which will be used headless, and am using https://github.com/adafruit/Adafruit_DotStar_Pi for controlling LEDs, which constrains me to using Python 2. The LEDs are pretty much the only output of my device, and a single key (specifically a 'w' from a Bluefruit EZ-Key Bluetooth HID Keyboard Controller) is the only input - basically activating or deactivating the lights.

I want to have a callback function be called when a keypress event is detected, to change some state, but all available methods I've found so far (ie reading from /dev/input/event0) seem to be blocking. The python-evdev module looks useful, but all the async options appear to be Python 3.

In the GPIO python library (which works fine in Python 2) there are callback functions for when a pin changes state, so I guess I'm hoping that there is a similar API for detecting keypress events.

The code will be running in a systemd process, and it seems reading from /dev/input/event0 is more likely to get me useful key events than stdin (which doesn't seem to be hooked up to detect keypresses in systemd processes).

(This question was off-topic for https://raspberrypi.stackexchange.com/ btw )

asked Apr 26, 2016 at 7:35

1 Answer 1

2

An input device isn't substantially different from any other file. You can use select() and poll() (et al) on it to test if input is available. That is, given:

import select
dev = open('/dev/input/event4')
p = select.poll()
p.register(dev, select.POLLIN)

I can check and see if input is available by running:

events = p.poll(0)

This will either return an empty list, or it will return a list of (file descriptor, event) tuples; in either case it will not block. Depending on your code, you may actually want this to block a little; the 0 in the above call is actually a timeout (in milliseconds).

Having received a POLLIN event on this file descriptor, I know that I can read some data from it without blocking. A complete example might look like:

import os
import select
p = select.poll()
dev = open('/dev/input/event4')
p.register(dev, select.POLLIN)
while True:
 events = p.poll(500)
 if events:
 print 'events:', events
 data = os.read(dev.fileno(), 1024)
 print 'read: %s' % (repr(data))
 else:
 print 'no events...'

This calls poll in a loop, sleeping up to 500 milliseconds each time unless there is input, in which case it reacts immediately.

I like select.poll because the api is easier the the older select call, but I note that that the python-evdev module includes an example using select.

Taking a closer look at that example, you can actually just pass an InputDevice to poll, so we can rewrite the above like:

import os
import select
from evdev import InputDevice
p = select.poll()
dev = InputDevice('/dev/input/event4')
p.register(dev, select.POLLIN)
while True:
 events = p.poll(500)
 if events:
 print 'events:', events
 data = list(dev.read())
 print 'read: %s' % data

And see on output something like:

events: [(3, 1)]
read: [InputEvent(1461702764L, 854531L, 4, 4, 458789L), InputEvent(1461702764L, 854531L, 1, 9, 1L), InputEvent(1461702764L, 854531L, 0, 0, 0L)]

See the documentation on the select module for more details.

Hopefully that is enough to get you pointed in the right direction.

answered Apr 26, 2016 at 20:33
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.