Here is a new version of the patch. Sorry it took so long. It addresses most of the notes I got: Notes by Po Lu: - I think now the associated modifier for a key is computed properly, with or without XKB for plain X, and for gtk. - 'ralt' not generated for ISO_Level3_Shift. This will have to stay like this. What we know about the keys if what the system lets us. - Don't call x_any_window_to_frame if already called for the event. Notes by Eli: - Change testing for Venable_low_level_key_events. This variable now is more complex. Notes by Stefan: - Created and used event-* functions to access event. - Only one event with both pieces of information. - Selection of keys. Now the variable enable-low-level-key-events can be used to select exactly which keys we want to process. - About creating lisp object in handle_one_xevent, it is done in other events too. The lisp interface is as follows: - A list of variables with keysym values is initialized (xk-*), so the user can select keys, not just modifiers. - Users can bind globally commands or functions with llk-bind to taps. - To use a tapped key as a new modifier, this works: (llk-bind 'tap 'xk-shift-r (lambda () (message "H-...") (setq unread-command-events (append (event-apply-hyper-modifier nil) nil)))) - Added the function describe-low-level-key to see what keysym/modifier it triggers. This is implemented for X, pgtkw and MS-Windows. The pgtj implementation detects that a key is a modifier to filter it, but can't decide which one it its.