Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pynput listeners causing system-wide input problems #15

Closed
Hyphen-ated opened this issue Jan 23, 2017 · 21 comments
Closed

Pynput listeners causing system-wide input problems #15

Hyphen-ated opened this issue Jan 23, 2017 · 21 comments

Comments

@Hyphen-ated
Copy link

Here is a minimal example program using pynput.

from pynput.keyboard import Listener
listener = Listener()
listener.start()
listener.join()

While this program is running, I experience some strange behavior with keyboard input.

1: I'm using a utility called "Steelseries Engine 3" version 3.9.6 to bind some of my mouse buttons to alt-left, alt-right, and ctrl-w. With pynput active in the background, about half of the time I press one of these buttons, the modifier key gets lost. So I sometimes get the letter "w" sent by itself instead of the ctrl-w shortcut combination. (tested in Chrome and notepad++)

2: Sometimes when I press enter, nothing happens. It seems to partially depend on what program has focus: Discord and Chrome usually have the problem, but Intellij doesn't. (they're using different ways of detecting input I guess?) I haven't exhaustively tested every key on the keyboard, but all the letters and punctuation appear to not have this problem.

These might even both be the same problem, just certain kinds of keystrokes being eaten by pynput, which can include ctrl and enter.

Both of these issues are inconsistent from one second to the next, but very consistent in the sense that over several seconds of trying to trigger the problem, the problem will occur. I've never had any problems remotely like this until I started working with pynput for a project.

System details:
Windows 8.1
Python 2.7.13 (was previously on 2.7.10, updated to see if it would fix this problem)
pynput 1.2

@Brett824
Copy link

Getting the 2nd issue (enter key problems) on my setup as well:

Windows 10
Python 2.7.10
pynput 1.2

@moses-palmer
Copy link
Owner

Thank you for your report and condensed sample code.

Unfortunately, I cannot reproduce the error. My setup is slightly different though:

  • Windows 10, running in VirtualBox.
  • No background utilities modifying keyboard events running.

1: I'm using a utility called "Steelseries Engine 3" version 3.9.6 to bind some of my mouse buttons to alt-left, alt-right, and ctrl-w. With pynput active in the background, about half of the time I press one of these buttons, the modifier key gets lost. So I sometimes get the letter "w" sent by itself instead of the ctrl-w shortcut combination. (tested in Chrome and notepad++)

Do you mean that only the virtual keypresses generated by Steelseries Engine 3 are dropped? Can you reproduce this without that utility running?

@Brett824: Do you also use a similar tool?

@Hyphen-ated
Copy link
Author

Hyphen-ated commented Jan 24, 2017

Do you mean that only the virtual keypresses generated by Steelseries Engine 3 are dropped? Can you reproduce this without that utility running?

I've been unable to trigger the problem by physically pressing ctrl-w, but the dropped Enter presses I described are from physical presses of the Enter key. I can reproduce the Enter problem without the Steelseries utility running.

These issues are more inconsistent than I described yesterday. When testing it again today, they're happening much less: it takes a minute or so of reproduction attempts before I start briefly seeing either problem, then it goes away again.

@moses-palmer
Copy link
Owner

I will continue testing to try to reproduce.

I think that the current system load might be a factor; pynput is registered as a keyboard hook, and during its execution, the keyboard event is not propagated further; a system under load could possibly cause a pause in the python process, which possibly could cause the event to be dropped.

Do you notice any difference when testing on a newly started system, and when testing under heavy load?

@Hyphen-ated
Copy link
Author

Today both variations of the problem are back to being instantly reproducible, with a lower CPU load than I had during my tests yesterday. So that suggests there's more to it than load. My guess is there's a race condition happening inside the windows keyboard input subsystem

@Hyphen-ated
Copy link
Author

A probably-related discovery: while playing the game Refunct ( http://store.steampowered.com/app/406150/ ) with the example program running in the background, physical presses of the Esc key are dropped about 98% of the time. (pressed Esc a few hundred times to test it.) The peak rate I ever got for the other problems was something like 50-60%.

While this game was running I tried launching a bunch of other CPU intensive things and seeing how reliably the ctrl-w problem would manifest, and I couldn't get it to happen at all in about 100 tries. So it looks unlikely to me that the problem is based on CPU load.

@moses-palmer
Copy link
Owner

I'm sorry, but I just cannot reproduce this.

I have tried several hundred keypresses, focussing on enter and escape, with HD video playing in the background, and not a single one has been lost. Are you absolutely certain that you can reproduce it without any of the input modifying tools you have installed running?

@Hyphen-ated
Copy link
Author

Yes, I am am absolutely certain.

I went and found a free game made on the same engine as Refunct (unreal engine 4) on the theory that any UE4 game will show the problem reliably. The first one I tried does give me the problem: https://bohrium.itch.io/age-of-snowmpires

I can click "start game", pick the top option, and then try to press esc to bring up a menu. It fails about 80-90% of the time for me when pynput is running.

@moses-palmer
Copy link
Owner

Thank you for the link.

Unfortunately the game does not work under VirtualBox, which I use to run Windows. I am going to have to ask you to help me troubleshoot.

Monitoring events enter pynput here on Windows and will eventually end up here.

The data passed to the handler is however not suitable to pass on to consumers of pynput, as only platform dependent key codes are passed. To convert these codes to usable data, KeyTranslator.__call__ is used. I suspect this is the culprit. What happens if you avoid calling self._translator in self._translate and just return a dummy value?

If that stops the problem from appearing, we are on to something. Possible causes of the error in that case are calls to ToUnicodeEx, which is called here, here and here.

@Hyphen-ated
Copy link
Author

I replaced the call to self._translator with "return {}" and all the problems I was having appeared to go away.

@moses-palmer
Copy link
Owner

Did you investigate further? Does the issue still occur if you comment out only parts of KeyTranslator.__call__? What if you replace line 460 with modified_char = None?

@Hyphen-ated
Copy link
Author

Sorry, I don't have enough interest to put that much more into this. I'm just going to switch to keyboard I think

@russelg
Copy link

russelg commented Feb 4, 2017

def new_translate(self, vk, is_press):
    """ Fix for moses-palmer/pynput/issues/15 """
    return {
        "vk": vk
    }

keyboardListener._translate = new_translate

I did this myself and it allowed everything to work fine, since for my use case I only needed the VK anyway.
(I'm very interested in this issue and I am experiencing the same problem as this)

Replacing line 460 with modified_char = None yields no effect.

@moses-palmer
Copy link
Owner

I will add similar functionality shortly. The translation routine cannot be changed like this, obviously, since then a lot of useful information is lost, but I will add a filter function to be invoked on the raw data with the ability to suppress normal handling. Your use case would then be covered.

@russelg
Copy link

russelg commented Feb 8, 2017 via email

@moses-palmer
Copy link
Owner

moses-palmer commented Feb 8, 2017 via email

@moses-palmer
Copy link
Owner

Sorry for the long delay, but I have been rather busy.

I have pushed a new feature branch that, while not solving the root cause, will help with your issues.

It allows passing an additional argument to listeners, win32_event_filter, which will be called before other system hooks are called and before the event is propagated further in the listener. It will be passed the arguments (msg, data), where msg is the current low-level message being handled, and data is associated data. You will find more information in the documentation, bu in short, you can return None to stop pynput from handling the event further and is similar to your new_translate function above.

@moses-palmer
Copy link
Owner

One thing you could to to help track down the issue would be to add debug prints to the code and perhaps wrap all of of SystemHook._handler in a try-catch block to verify that it is not caused by something silly like an unhandled exception.

@thebitpost
Copy link

A similar problem is with Autoit3.
With listeners ON, Send("^c",0) sends just character C rather than Ctrl+C.

Any work-arounds?

@moses-palmer
Copy link
Owner

In response to this issue, win32_event_filter was added. It allows you to intercept keyboard events before they are transformed by pynput; make sure to return False from your callback.

It does bring the limitation that you will have to write a special event callback just for Windows, and you get raw keyboard events rather than platform agnostic Key instances.

@moses-palmer
Copy link
Owner

I have created issue #49 as a container for all win32 keyboard listener related issues, as I suspect that the root cause is the same.

I will close this issue. If you think the problem is unrelated to #49, please reopen this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants