kennyhml / pyinterception

Modern Python port & wrapper for the interception device driver
MIT License
125 stars 26 forks source link

Cancel key press #32

Closed Juloup78 closed 4 months ago

Juloup78 commented 4 months ago

Is it possible to listen to a key press and cancel it while still being able to emulate it ?

kennyhml commented 4 months ago

I dont really understand the question, are you asking whether you can intercept a keystroke before it reaches the rest of the system and have the ability to decide whether you pass it on or remove it from the input queue?

If thats the case, this isnt something thats easily handled from the devices.

What you are actually looking for is most likely SetWindowsHookExA to hook LowLevelKeyboardProc with WH_KEYBOARD_LL. You can setup a custom low level callback for the keystroke and return 1 to suppress the event or calling the next hook to let it pass through as normal.

All of this is done through the windows API, if you are planning to code this up in python you can do so through ctypes.

Juloup78 commented 4 months ago

Sorry my question wasnt very precise but your answer seems to work thanks.

WHalcyon commented 2 months ago

I dont really understand the question, are you asking whether you can intercept a keystroke before it reaches the rest of the system and have the ability to decide whether you pass it on or remove it from the input queue?

If thats the case, this isnt something thats easily handled from the devices.

What you are actually looking for is most likely SetWindowsHookExA to hook LowLevelKeyboardProc with WH_KEYBOARD_LL. You can setup a custom low level callback for the keystroke and return 1 to suppress the event or calling the next hook to let it pass through as normal.

All of this is done through the windows API, if you are planning to code this up in python you can do so through ctypes.

I'm not sure I understand the question, but can't this be done easily in listen_to_events?

You can put your callback in here, with the right filter it'll get called every time you press the button. If you want to cancel it simply don't call context.send.

I've been doing this and it works well, except that it'll swallow my input once in a while mysteriously...

kennyhml commented 2 months ago

Never tested that, but good to know that works too.

Juloup78 commented 2 months ago

i managed to do it by setting up a hook with ctypes to the lowlevelmouse event and choosing using the injected flag wether or not to forward it

WHalcyon commented 2 months ago

I figured out the inputs disappearing, capturing only key_downs can cause timing issues where the key_up is sent before the key_down, so make sure you're hooking both.

kennyhml commented 2 months ago

I see. I still believe using the windows API is the simpler and more correct solution, since the hook dedicates its return value for whether the input should be passed on or not and you also get alot more information about the input than you do using interception.

WHalcyon commented 2 months ago

Yeah, no doubt. I used interception because I saw you had capture_mouse defined already and figured that's what you were doing.

I would consider changing the lines below from the top to the bottom:

context.set_filter(is_mouse, FilterMouseButtonFlag.FILTER_MOUSE_LEFT_BUTTON_DOWN)
context.set_filter(is_keyboard, FilterKeyFlag.FILTER_KEY_DOWN)
context.set_filter(is_mouse, FilterMouseButtonFlag.FILTER_MOUSE_LEFT_BUTTON_DOWN | FilterMouseButtonFlag.FILTER_MOUSE_LEFT_BUTTON_DOWN)
context.set_filter(is_keyboard, FilterKeyFlag.FILTER_KEY_ALL)

This would avoid issues with keys getting stuck caused by out of order execution. I'm not going to submit a PR because I don't know the intended use of these functions. It may also only affect me so if no one else has ever encountered this bug it's not important.

kennyhml commented 2 months ago

The reason it was done that way is because every input ends up being displayed twice which makes it more confusing to the user. May just capture all but not print certain strokes I guess