python-evdev icon indicating copy to clipboard operation
python-evdev copied to clipboard

Device.read_loop() misses button presses

Open nicholsonjf opened this issue 7 years ago • 9 comments

I'm using a Griffin PowerMate plugged into a Raspberry Pi running Stretch. I wrote a Python3 script using python-evdev to listen for events and print the categorized version. After starting the program, pressing the button multiple times and seeing the "up" and "down" events, it will randomly stop detecting events. It seems as though there is a timing or buffer issue. How can I prevent it from missing button presses?

from evdev import InputDevice, categorize, ecodes

dev = InputDevice('/dev/input/event0')
print(dev)

dev.grab()

for event in dev.read_loop():
       if event.type == ecodes.EV_KEY:
           cat = categorize(event)
           print(cat)

nicholsonjf avatar Oct 11 '18 03:10 nicholsonjf

Hi @nicholsonjf . Very interesting - it shouldn't do that :). Could you please check if events are dropped when using a tool like evtest?

gvalkov avatar Oct 14 '18 15:10 gvalkov

I had a similar issue in the past when I tried to handle events from a 1000 Hz mouse and a keyboard at the same time. I can't reproduce it now, but I remember that for example when I was moving the mouse and clicked at the same time, the click event would sometimes get lost. The situation improved a lot when I added a 0.5 ms sleep after each select() in a loop like this example https://python-evdev.readthedocs.io/en/latest/tutorial.html#reading-events-from-multiple-devices-using-select

siikamiika avatar Nov 03 '18 13:11 siikamiika

Similar experience here, I eventually had to build my own loop. I found that using device_read_many inside a loop works.

Worryingly though, my use-case is just regular keyboard processes, and it doesn't take much to trigger.

How to replicate: Code structure:

  1. set up an empty set, call it down_keys
  2. Identify the correct keyboard, bind exclusively using device.grab_context(), start the read_loop()
  3. with each iteration of the loop add the keycode to down_keys if the event is a key down event, remove the keycode from down_keys if it is an up event, and then print the down_keys set.

(Note that the code will crash if there was an up event without a preceding down event. Don't forget that you may be holding down a key when you start running the script. Failing to realize that will drive you mad while trying to debug it. :b) (And sorry, I don't have the snippet I used to prove there were dropped events anymore. It was a truncated version of a larger program I was/am working on, it only processes keyboard input.)

Physical actions:

  1. Place all of your fingers on different keys on your keyboard and press all of them down at the same time, do so quickly and reasonable hard. Note if there is anything missing from down_keys. (and don't forget that some keyboards have a maximum number of concurrent keys down, or have illegal combinations.)
  2. Similarly to step 1, remove all of your fingers from all the keys at the same time. Look to see if there is anything still in down_keys.
  3. Repeat. Missing up events are a lot easier to check for. It shouldn't take very long to find a missing event.
  4. Repeat on a different physical keyboard. I found that in regular typing missed events occurred maybe 1 in every 1000 keys pressed, but it was trivial to make it occur with the technique above... except on a lenovo thinkpad w530 built-in laptop keyboard, where it happened every time I pressed alt-tab. I think the issue there is that it has a particularly strong/fast key-spring, so when I "let go" all key-up events occurred in a particularly closely clustered fashion.

Was able to replicate on Ubuntu 18.04. Ubuntu 18.10, and Fedora 29.

Let me know if I can help or if you would like me to run a test on that thinkpad....

biblicabeebli avatar Mar 31 '19 04:03 biblicabeebli

Hi @biblicabeebli. Thanks for the thorough analysis. Just wanted to let you know that I'm really low on bandwidth these days and I haven't been able to troubleshoot this :(

gvalkov avatar Apr 07 '19 19:04 gvalkov

You were probably forgetting to handle SYN_DROPPED properly. The kernel will inject one if the buffer is overflowed.

DanielJoyce avatar Dec 28 '19 23:12 DanielJoyce

I am facing a similar issue with the asyncio variant:

async for event in input_device.async_read_loop():

I am trying to read key events from a USB barcode scanner, which spits out key events really fast when scanning a barcode. While most of the time the barcodes go though fine, sometimes they are just chopped off. Interestingly it seems to always happen at the same location, f.ex:

When scanning a barcode that is supposed to look like this:

4250168519463

when it is chopped off it is always looking like this:

463

so only the last three digits survive.

markusressel avatar Oct 16 '20 15:10 markusressel

I am facing a similar issue with the asyncio variant:

async for event in input_device.async_read_loop():

I am trying to read key events from a USB barcode scanner, which spits out key events really fast when scanning a barcode. While most of the time the barcodes go though fine, sometimes they are just chopped off. Interestingly it seems to always happen at the same location, f.ex:

When scanning a barcode that is supposed to look like this:

4250168519463

when it is chopped off it is always looking like this:

463

so only the last three digits survive.

HI! I am getting the same issue with a QR reader.

Any solution?

Thanks a lot

cmantaras avatar Apr 13 '21 21:04 cmantaras

I have another question, after getting the whole string from de qr. how can i stop getting more events for 5 seconds. I could nt do this, I tried time.sleep(5), sync methods, global variables, and always the loop still listening the port.

cmantaras avatar Apr 13 '21 21:04 cmantaras

No solution, but I am actually using the sync api variant inside of an async executor instead of the async api since it has a much higher success rate. Its also not perfect though. The commit diff is here: https://github.com/markusressel/barcode-server/commit/20bc3f1d05a19459c3d8a981fe748aa9c3f754aa

Your other question is off topic and should be a different/new issue.

markusressel avatar Apr 13 '21 21:04 markusressel