moses-palmer / pynput

Sends virtual input commands
GNU Lesser General Public License v3.0
1.79k stars 248 forks source link

Unable to type() arrow symbols. #346

Closed pklaus closed 3 years ago

pklaus commented 3 years ago

I'm expecting the following code to "type" a rightwards arrow (→):

import pynput
c = pynput.keyboard.Controller()
c.type("\u2192")

This, however, results only in a NoSymbol key press / release (output from xev):

KeyPress event, serial 67, synthetic YES, window 0x8600001,
    root 0x1e6, subw 0x0, time 0, (0,0), root:(0,0),
    state 0x0, keycode 103 (keysym 0x0, NoSymbol), same_screen NO,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

[...]

KeyRelease event, serial 76, synthetic YES, window 0x8600001,
    root 0x1e6, subw 0x0, time 0, (0,0), root:(0,0),
    state 0x0, keycode 103 (keysym 0x0, NoSymbol), same_screen NO,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

workaround

when I run the following code instead:

import Xlib.XK
Xlib.XK.load_keysym_group("technical")

import pynput
c = pynput.keyboard.Controller()
c.type("\u2192")

I get the right keypress:

KeyPress event, serial 76, synthetic YES, window 0x8600001,
    root 0x1e6, subw 0x0, time 0, (0,0), root:(0,0),
    state 0x0, keycode 97 (keysym 0x8fd, rightarrow), same_screen NO,
    XLookupString gives 3 bytes: (e2 86 92) "→"
    XmbLookupString gives 3 bytes: (e2 86 92) "→"
    XFilterEvent returns: False

KeyRelease event, serial 76, synthetic YES, window 0x8600001,
    root 0x1e6, subw 0x0, time 0, (0,0), root:(0,0),
    state 0x0, keycode 97 (keysym 0x8fd, rightarrow), same_screen NO,
    XLookupString gives 3 bytes: (e2 86 92) "→"
    XFilterEvent returns: False
moses-palmer commented 3 years ago

Thank you for your report and workaround!

I have pushed a proposed solution to fixup-xlib-keysymdef; instead of explicitly loading the group technical, the code on the branch loads all groups. Would you mind testing it on your system?

pklaus commented 3 years ago

A few observations without the Xlib.XK.load_keysym_group("technical") call:

import pynput

c = pynput.keyboard.Controller()

# a few calls with the debugger, I was able to step through the execution stack:
import pdb
pdb.runcall(c.press, "\u2192")
# with the subsequent debugging commands like next (n), step in (s) and continue (c) I was able to trace some details as follows:

k = c._resolve("\u2192")
# k contains now  pynput.keyboard._xorg.KeyCode(char="\u2192")

c._keysym(k)
# returns 0 ???

c._key_to_keysym(k)
# returns 0 ???

pynput._util.xorg_keysyms.CHARS.get("\u2192")
# returns 'rightarrow'

pynput._util.xorg.symbol_to_keysym("rightarrow")
# returns 0 ???

import Xlib
Xlib.XK.string_to_keysym(symbol)
# returns 0 ???

# this doesn't play a role, as the 'symbol' is found in 'CHARS', but interesting to know nevertheless:
pynput._util.xorg.char_to_keysym("\u2192")
# returns 0x1002192

So it all comes down to the fact that Xlib.XK.string_to_keysym() returns the integer 0 if the group the symbol belongs to isn't loaded before calling it.

After all, this issue might not only the arrow symbols but basically any symbol belonging to the 'groups' (i.e. Python modules) present in the folder Xlib.keysymdef.

pklaus commented 3 years ago

Thank you for your report and workaround!

I have pushed a proposed solution to fixup-xlib-keysymdef; instead of explicitly loading the group technical, the code on the branch loads all groups. Would you mind testing it on your system?

Sorry, I've seen this only after providing the further info and creating my pull request. Indeed, it will solve this issue. It works without problems.

In parallel, my pull request #347 also solves the issue and fixes a part of the code that could never be reached: the lookup in pynput._util.xorg_keysyms.SYMBOLS.

So after all, I think both changes, 96b7a1d (from your branch fixup-xlib-keysymdef) and 293e61d (from my pull request #347) should make it into the master branch.

moses-palmer commented 3 years ago

Thank you again.

I have incorporated your commit into the branch and I will merge it later---I'm currently working remotely using SSH over my phone, which is fine for git operations and coding, but does not really work when testing X applications.

pklaus commented 3 years ago

Great, thanks!