xpra icon
Bug tracker and wiki

Opened 5 years ago

Closed 5 years ago

Last modified 4 years ago

#588 closed defect (fixed)

Keyboard mapping issue: numerical keypad

Reported by: capitn Owned by: Antoine Martin
Priority: major Milestone: 0.14
Component: core Version: 0.13.x
Keywords: keyboard mapping numerical Cc:

Description (last modified by Antoine Martin)

Context:

  • Xpra 0.13.1 on server side (CentOS 6.4)
  • Xpra 0.13.2 on client side (windows7) with keymap FR

When the numerical keypad is activated (num lock on) and I press the '.' key
then it is printed ';' in the xpra client.

Here are some logs:

  • setxkbmap -print:
        xkb_keymap {
                xkb_keycodes  { include "xfree86+aliases(azerty)"       };
                xkb_types     { include "complete"      };
                xkb_compat    { include "complete"      };
                xkb_symbols   { include "pc+fr+inet(pc105)"     };
                xkb_geometry  { include "pc(pc105)"     };
        };
    
  • setxkbmap -query:
        rules:      base
        model:      pc105
        layout:     fr
    
  • xmodmap -pm:
        xmodmap:  up to 7 keys per modifier, (keycodes in parentheses):
    
        shift       Shift_L (0x32),  Shift_R (0x3e),  Shift_L (0x8e)
        lock        Caps_Lock (0x42)
        control     Control_L (0x25),  Control_R (0x6d),  Control_L (0x8f)
        mod1        Alt_L (0x40),  Alt_L (0x79),  Meta_R (0x7a),  Alt_L (0x7d),  Alt_L (0x91),  Alt_R (0x92),  Meta_L (0x9c)
        mod2        Num_Lock (0x4d)
        mod3        Super_L (0x73),  Super_R (0x74),  Super_L (0x7f)
        mod4        Hyper_L (0x80),  Hyper_R (0x94)
        mod5        Mode_switch (0x8),  ISO_Level3_Shift (0x71),  ISO_Level3_Shift (0x7c)
    
  • screenshot of the GTK_Keyboard_Test.exe on the

windows computer (I pressed the '.' key only once): screenshot.jpg

  • what xev prints when pressing '.' key on the numerical keypad (only 1

time).

    KeyPress event, serial 30, synthetic NO, window 0xe00001,
        root 0x44, subw 0x0, time 402278199, (94,80), root:(98,103),
        state 0x0, keycode 77 (keysym 0xff7f, Num_Lock), same_screen YES,
        XLookupString gives 0 bytes:
        XmbLookupString gives 0 bytes:
        XFilterEvent returns: False

    KeyRelease event, serial 30, synthetic NO, window 0xe00001,
        root 0x44, subw 0x0, time 402278199, (94,80), root:(98,103),
        state 0x10, keycode 77 (keysym 0xff7f, Num_Lock), same_screen YES,
        XLookupString gives 0 bytes:
        XFilterEvent returns: False

    KeyPress event, serial 30, synthetic NO, window 0xe00001,
        root 0x44, subw 0x0, time 402278200, (94,80), root:(98,103),
        state 0x10, keycode 59 (keysym 0x3b, semicolon), same_screen YES,
        XLookupString gives 1 bytes: (3b) ";"
        XmbLookupString gives 1 bytes: (3b) ";"
        XFilterEvent returns: False

    KeyRelease event, serial 30, synthetic NO, window 0xe00001,
        root 0x44, subw 0x0, time 402278201, (94,80), root:(98,103),
        state 0x10, keycode 59 (keysym 0x3b, semicolon), same_screen YES,
        XLookupString gives 1 bytes: (3b) ";"
        XFilterEvent returns: False

    KeyPress event, serial 30, synthetic NO, window 0xe00001,
        root 0x44, subw 0x0, time 402278201, (94,80), root:(98,103),
        state 0x10, keycode 77 (keysym 0xff7f, Num_Lock), same_screen YES,
        XLookupString gives 0 bytes:
        XmbLookupString gives 0 bytes:
        XFilterEvent returns: False

    KeyRelease event, serial 30, synthetic NO, window 0xe00001,
        root 0x44, subw 0x0, time 402278201, (94,80), root:(98,103),
        state 0x10, keycode 77 (keysym 0xff7f, Num_Lock), same_screen YES,
        XLookupString gives 0 bytes:
        XFilterEvent returns: False

    KeyPress event, serial 30, synthetic NO, window 0xe00001,
        root 0x44, subw 0x0, time 402278280, (94,80), root:(98,103),
        state 0x0, keycode 77 (keysym 0xff7f, Num_Lock), same_screen YES,
        XLookupString gives 0 bytes:
        XmbLookupString gives 0 bytes:
        XFilterEvent returns: False

Attachments (5)

screenshot.jpg (38.4 KB) - added by capitn 5 years ago.
xmodmap-pke.txt (12.1 KB) - added by Antoine Martin 5 years ago.
xmodmap -pke output (copy to attachment to make the ticket more readable)
win32-keymap-info.txt (28.1 KB) - added by Antoine Martin 5 years ago.
Keymap_info.exe output (copy to attachment to make the ticket more readable)
xpra-info-keyboard.txt (54.1 KB) - added by Antoine Martin 5 years ago.
"xpra info | grep keyboard" output (copy to attachment to make the ticket more readable)
rename-period-as-KP_Decimal.patch (2.0 KB) - added by Antoine Martin 5 years ago.
ugly patch which renames the windows keyboard keyname for the "."

Download all attachments as: .zip

Change History (14)

Changed 5 years ago by capitn

Attachment: screenshot.jpg added

Changed 5 years ago by Antoine Martin

Attachment: xmodmap-pke.txt added

xmodmap -pke output (copy to attachment to make the ticket more readable)

Changed 5 years ago by Antoine Martin

Attachment: win32-keymap-info.txt added

Keymap_info.exe output (copy to attachment to make the ticket more readable)

Changed 5 years ago by Antoine Martin

Attachment: xpra-info-keyboard.txt added

"xpra info | grep keyboard" output (copy to attachment to make the ticket more readable)

comment:1 Changed 5 years ago by Antoine Martin

Description: modified (diff)
Owner: changed from Antoine Martin to Antoine Martin
Status: newassigned

(edit: replacing large data with attachments)

comment:2 Changed 5 years ago by Antoine Martin

Description: modified (diff)

comment:3 Changed 5 years ago by Antoine Martin

Well, I've tried to reproduce this by plugging an external keyboard and using USB pass-through with virtualbox then setting mswindows to 'FR' layout, and I just cannot see any of this crazy behaviour where one keypress ends up generating almost a dozen key events. I always get exactly two events (key down, key up).

Are you using vmware or something else that could interfere with the keyboard?
It definitely looks like something is messing up with Num_Lock and we get two key-up events for a single key-down... which is very odd.

comment:4 Changed 5 years ago by Antoine Martin

Confirmed: I think it is safe to ignore the repeated keys and Num_Lock weirdness which are more than likely caused by a virtual machine (KVM) accessed over RDP. Not a problem with GTK or the OS reporting the wrong keys multiple times.

comment:5 Changed 5 years ago by Antoine Martin

Summary

Summary of the attachments above (parts relating to the key we are interested in) and more:

  • On a regular Fedora 20 Linux host (no xpra involved), with both 'gb' or 'fr' layouts, the dot (".") on the numeric keypad shows up as:
    • keycode: 91
    • keysym: 0xffae
    • keyname: KP_Decimal
    • XKeysymToKeycode: 129
    • XLookupString: "."
  • With Num_Lock off, we get the same keycode and keysym, the difference is:
    • keyname: KP_Delete
    • (no string representation)
  • The xmodmap -pke has it mapped as:
    keycode  91 = KP_Delete KP_Decimal KP_Delete KP_Decimal KP_Delete KP_Decimal KP_Delete KP_Decimal
    

Note that we also have:

keycode 134 = KP_Decimal KP_Decimal KP_Decimal KP_Decimal KP_Decimal KP_Decimal KP_Decimal KP_Decimal

This is broadly similar to what is found on a plain Linux host (bar 8 entries created instead of just 4.. caused by Xkb vs core api)

  • In the xpra info | grep keyboard output, we see KP_Decimal mapped as:
    keyboard.keycode.KP_Delete=91
    keyboard.keycode.KP_Decimal=134
    keyboard.keysym.Delete=107
    keyboard.keysym.Delete.46=107
    keyboard.keysym.KP_Decimal=134
    

So the automatic key mapping has chosen the second option for KP_Decimal.

  • on the windows side, the dot is showing up as:
    46                period            110               0                 0
    46                period            110               0                 1
    46                period            190               0                 1
    

Two keycodes... and quite different values from the ones we find for Delete:

65535             Delete            46                0                 0
65535             Delete            46                0                 1
65535             Delete            46                1                 0
65535             Delete            46                1                 1

The keycode for Delete is the keyval for KP_Decimal!?


  • Interesting testing notes:
    • via virtualbox with 'gb' layout and switching to 'fr' layout after connecting to the xpra server, the numeric keypad worked, but the dot found on the main section of the keyboard exhibited the problem instead!
    • using the same keyboard for the host and guests is just not reliable for testing (the keys are intercepted / interpreted by the host OS, then by virtualbox, before being forwarded to the guest)
  • With ms windows set to 'fr' layout globally and an external keyboard passed through to the guest vm, I can reproduce the problem reliably.

Testing with Fedora 20 Server / Windows XP Client

  • The client shows with -d keyboard:
    parse_key_event(<gtk.gdk.Event at 01E9AFC8: GDK_KEY_PRESS keyval=period>, True)=\
        <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': '.', \
         'keyname': 'period', 'pressed': True, 'keyval': 46, 'keycode': 110}>
    handle_key_action(ClientWindow(1), <GTKKeyEvent object, contents: \
        {'modifiers': ['mod2'], 'group': 0, 'string': '.', \
         'keyname': 'period', 'pressed': True, 'keyval': 46, 'keycode': 110}>) wid=1
    send_key_action(1, <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': '.', \
         'keyname': 'period', 'pressed': True, 'keyval': 46, 'keycode': 110}>)
    mask_to_names(<flags 0 of type GdkModifierType>) GetKeyState(VK_NUMLOCK)=1, names=['mod2']
    parse_key_event(<gtk.gdk.Event at 01E9AFE0: GDK_KEY_RELEASE keyval=period>, False)=\
        <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': '.', \
         'keyname': 'period', 'pressed': False, 'keyval': 46, 'keycode': 110}>
    handle_key_action(ClientWindow(1), <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string': '.', \
         'keyname': 'period', 'pressed': False, 'keyval': 46, 'keycode': 110}>) wid=1
    send_key_action(1, <GTKKeyEvent object, contents: {'modifiers': ['mod2'], 'group': 0, 'string':'.', \
         'keyname': 'period', 'pressed': False, 'keyval': 46, 'keycode': 110}>
    

TIL: the event contains: 'string': '.', 'keyname': 'period', 'pressed': True, 'keyval': 46, 'keycode': 110

  • The server shows with -d keyboard:
    get_keycode(110, period, ('mod2',)) is_native_keymap=False, found using translation: 59
    handle_key(1,True,period,46,59,('mod2',)) keyboard_sync=True
    is_modifier(59) not found
    handle keycode pressing 59: key period
    fake_key(59, True)
    scheduling key repeat timer with delay 750 for period / 59
    get_keycode(110, period, ('mod2',)) is_native_keymap=False, found using translation: 59
    handle_key(1,False,period,46,59,('mod2',)) keyboard_sync=True
    is_modifier(59) not found
    handle keycode unpressing 59: key period
    fake_key(59, False)
    cancelling key repeat timer: 10964 for period / 59
    

TIL: we translate (110, period) to (59, period).

Last edited 5 years ago by Antoine Martin (previous) (diff)

Changed 5 years ago by Antoine Martin

ugly patch which renames the windows keyboard keyname for the "."

comment:6 Changed 5 years ago by Antoine Martin

The patch above seems to work for me.
Before merging, I would like to find a cleaner way of patching the gtk keymap in the per-platform classes rather than having it completely hardcoded.
Then I'll worry about backports.

Does the beta win32 build work for you? (no need to update the server)



For reference, here's the server keymapping phase (edited log summary):

  • setxkbmap -layout fr
  • using gtk keycodes: [..., [46, 'KP_Decimal', 110, 0, 0], [46, 'KP_Decimal', 110, 0, 1], ...
  • keycodes={..., 110: set([('KP_Decimal', 0), ('KP_Decimal', 1)]), ...}
  • preserved mappings:
    ...
    60		=	['colon', 'slash', 'colon', 'slash', 'periodcentered', 'division', 'periodcentered']
    ...
    91		=	['KP_Delete', 'KP_Decimal', 'KP_Delete', 'KP_Decimal']
    ...
    
  • translation map
    translate_keycodes(8, 255, {...
       110: set([('KP_Decimal', 0), ('KP_Decimal', 1)]),
       ...
       91: set([('KP_Delete', 2), ('KP_Decimal', 1), ('KP_Decimal', 3), ('KP_Delete', 0)]),
       ...
       129: set([('KP_Decimal', 0), ('KP_Decimal', 2), ('KP_Decimal', 1), ('KP_Decimal', 3)]),
       ...}
    
  • key assignment:
    assign(110, set([('KP_Decimal', 0), ('KP_Decimal', 1)]))
    preserve matches for set([('KP_Decimal', 0)]) : {
        129: set([('KP_Decimal', 0), ('KP_Decimal', 2), ('KP_Decimal', 1), ('KP_Decimal', 3)]), \
        91: set([('KP_Delete', 2), ('KP_Decimal', 1), ('KP_Decimal', 3), ('KP_Delete', 0)])}
    found direct preserve superset for 110 : set([('KP_Decimal', 0)]) -> 129 : set([('KP_Decimal', 0), ('KP_Decimal', 2), ('KP_Decimal', 1), ('KP_Decimal', 3)])
    set_keycodes key 110 (set([('KP_Decimal', 0), ('KP_Decimal', 2), ('KP_Decimal', 1), ('KP_Decimal', 3)])) mapped to keycode=129
    
set_keycodes key -1 (set([('KP_Delete', 2), ('KP_Decimal', 1), ('KP_Decimal', 3), ('KP_Delete', 0)])) mapped to keycode=91
  • translation table:
    translated keycodes={..., (110, 'KP_Decimal'): 129, 'KP_Decimal': 91, ... }
    
  • keycode definitions:
    ['KP_Delete', 'KP_Decimal', 'KP_Delete', 'KP_Decimal', '', '', ''] -> [65439L, 65454L, 65439L, 65454L, None, None, None]
    ['KP_Decimal', 'KP_Decimal', 'KP_Decimal', 'KP_Decimal', '', '', ''] -> [65454L, 65454L, 65454L, 65454L, None, None, None]
    
Last edited 5 years ago by Antoine Martin (previous) (diff)

comment:7 Changed 5 years ago by Antoine Martin

Resolution: fixed
Status: assignedclosed

r6667 is a better fix, but too intrusive to backport.

So I've applied the more ugly workaround in r6669 for the v0.13.x branch, this will be part of 0.13.4

Last edited 5 years ago by Antoine Martin (previous) (diff)

comment:9 Changed 4 years ago by Antoine Martin

Description: modified (diff)
Note: See TracTickets for help on using tickets.