From: Taylor R. Campbell Date: Sat, 21 Oct 2006 16:05:58 +0000 (+0000) Subject: Find interpretation of modifier masks through the X server's modifier X-Git-Tag: 20090517-FFI~886 X-Git-Url: https://birchwood-abbey.net/git?a=commitdiff_plain;h=eb1ca763b5ed550a5e526b97d8fa061a7bb14f1f;p=mit-scheme.git Find interpretation of modifier masks through the X server's modifier mapping and keyboard mapping by finding which modifier masks are associated with keycodes mapped to the keysyms for modifier keys. This now follows the ICCCM, rather than assuming that Mod1 means Meta, Mod2 means Super, and so on. Edwin also now recognizes Super and Hyper in key presses as a result; before it would ignore any modifier masks other than Control and Mod1 (Meta). --- diff --git a/v7/src/microcode/object.h b/v7/src/microcode/object.h index ed57eb64b..cfccb9871 100644 --- a/v7/src/microcode/object.h +++ b/v7/src/microcode/object.h @@ -1,6 +1,6 @@ /* -*-C-*- -$Id: object.h,v 9.60 2006/09/16 11:19:09 gjr Exp $ +$Id: object.h,v 9.61 2006/10/21 16:05:58 riastradh Exp $ Copyright 1986,1987,1988,1989,1990,1992 Massachusetts Institute of Technology Copyright 1993,1995,1997,1998,2000,2001 Massachusetts Institute of Technology @@ -352,7 +352,8 @@ extern SCHEME_OBJECT * memory_base; #define CHAR_BITS_META 0x1 #define CHAR_BITS_CONTROL 0x2 -#define CHAR_BITS_CONTROL_META 0x3 +#define CHAR_BITS_SUPER 0x4 +#define CHAR_BITS_HYPER 0x8 #define MAX_ASCII (1L << ASCII_LENGTH) #define MAX_CODE (1L << CODE_LENGTH) diff --git a/v7/src/microcode/x11.h b/v7/src/microcode/x11.h index a8e8d9e36..0f18b6654 100644 --- a/v7/src/microcode/x11.h +++ b/v7/src/microcode/x11.h @@ -1,9 +1,9 @@ /* -*-C-*- -$Id: x11.h,v 1.20 2005/11/12 22:53:29 cph Exp $ +$Id: x11.h,v 1.21 2006/10/21 16:05:58 riastradh Exp $ Copyright 1989,1990,1991,1992,1993,2000 Massachusetts Institute of Technology -Copyright 2005 Massachusetts Institute of Technology +Copyright 2005,2006 Massachusetts Institute of Technology This file is part of MIT/GNU Scheme. @@ -42,6 +42,22 @@ struct xdisplay XEvent cached_event; char cached_event_p; + /* X key events have 8-bit modifier masks, three bits of which are + defined to be Shift, Lock, and Control, identified with ShiftMask, + LockMask, and ControlMask; and five bits of which are unspecified + named only mod1 to mod5. Which ones mean Meta, Super, Hyper, &c., + vary from system to system, however, so, on initializing the display + record, we grovel through some tables (XGetKeyboardMapping and + XGetModifierMapping) to find which ones the various modifier + keysyms are assigned to, and cache them here. + + Scheme knows about Shift, Control, Meta, Super, and Hyper. Of + these, only Meta, Super, and Hyper are identified by numbered + modifier masks. All other modifiers are ignored. */ + int modifier_mask_meta; + int modifier_mask_super; + int modifier_mask_hyper; + /* The type of window manager we have. If we move FRAME_OUTER_WINDOW to x/y 0/0, some window managers (type A) puts the window manager decorations outside the screen and FRAME_OUTER_WINDOW exactly at 0/0. @@ -64,9 +80,28 @@ struct xdisplay #define XD_WM_TAKE_FOCUS(xd) ((xd) -> wm_take_focus) #define XD_CACHED_EVENT(xd) ((xd) -> cached_event) #define XD_CACHED_EVENT_P(xd) ((xd) -> cached_event_p) +#define XD_MODIFIER_MASK_SHIFT(xd) (ShiftMask) +#define XD_MODIFIER_MASK_CONTROL(xd) (ControlMask) +#define XD_MODIFIER_MASK_LOCK(xd) (LockMask) +#define XD_MODIFIER_MASK_META(xd) ((xd) -> modifier_mask_meta) +#define XD_MODIFIER_MASK_SUPER(xd) ((xd) -> modifier_mask_super) +#define XD_MODIFIER_MASK_HYPER(xd) ((xd) -> modifier_mask_hyper) #define XD_WM_TYPE(xd) ((xd) -> wm_type) #define XD_TO_OBJECT(xd) (LONG_TO_UNSIGNED_FIXNUM (XD_ALLOCATION_INDEX (xd))) +#define X_MODIFIER_MASK_SHIFT_P(modifier_mask, xd) \ + ((modifier_mask) & (XD_MODIFIER_MASK_SHIFT (xd))) +#define X_MODIFIER_MASK_CONTROL_P(modifier_mask, xd) \ + ((modifier_mask) & (XD_MODIFIER_MASK_CONTROL (xd))) +#define X_MODIFIER_MASK_LOCK_P(modifier_mask, xd) \ + ((modifier_mask) & (XD_MODIFIER_MASK_LOCK (xd))) +#define X_MODIFIER_MASK_META_P(modifier_mask, xd) \ + ((modifier_mask) & (XD_MODIFIER_MASK_META (xd))) +#define X_MODIFIER_MASK_SUPER_P(modifier_mask, xd) \ + ((modifier_mask) & (XD_MODIFIER_MASK_SUPER (xd))) +#define X_MODIFIER_MASK_HYPER_P(modifier_mask, xd) \ + ((modifier_mask) & (XD_MODIFIER_MASK_HYPER (xd))) + extern struct xdisplay * EXFUN (x_display_arg, (unsigned int arg)); struct drawing_attributes diff --git a/v7/src/microcode/x11base.c b/v7/src/microcode/x11base.c index b5bcf686c..7650d056d 100644 --- a/v7/src/microcode/x11base.c +++ b/v7/src/microcode/x11base.c @@ -1,10 +1,10 @@ /* -*-C-*- -$Id: x11base.c,v 1.85 2005/11/16 04:00:16 cph Exp $ +$Id: x11base.c,v 1.86 2006/10/21 16:05:58 riastradh Exp $ Copyright 1989,1990,1991,1992,1993,1994 Massachusetts Institute of Technology Copyright 1995,1996,1997,1998,2000,2001 Massachusetts Institute of Technology -Copyright 2003,2004,2005 Massachusetts Institute of Technology +Copyright 2003,2004,2005,2006 Massachusetts Institute of Technology This file is part of MIT/GNU Scheme. @@ -565,7 +565,7 @@ get_wm_decor_geometry (struct xwindow * xw) return (decor != (XW_WINDOW (xw))); } -/* Open/Close Windows and Displays */ +/* Open/Close Windows */ #define MAKE_GC(gc, fore, back) \ { \ @@ -669,6 +669,121 @@ DEFUN (x_close_window, (xw), struct xwindow * xw) XSetIOErrorHandler (x_io_error_handler); free (xw); } + +/* Initialize/Close Displays */ + +#define MODIFIER_INDEX_TO_MASK(N) (1 << (N)) + +/* Grovel through the X server's keycode and modifier mappings to find + out what we ought to interpret as Meta, Hyper, and Super, based on + what modifiers are associated with keycodes that are associated with + keysyms Meta_L, Meta_R, Alt_L, Alt_R, Hyper_L, &c. + + Adapted from GNU Emacs. */ + +static void +DEFUN (x_initialize_display_modifier_masks, (xd), struct xdisplay * xd) +{ + int min_keycode; + int max_keycode; + XModifierKeymap * modifier_keymap; + KeyCode * modifier_to_keycodes_table; + int keycodes_per_modifier; + KeySym * keycode_to_keysyms_table; + int keysyms_per_keycode; + + (XD_MODIFIER_MASK_META (xd)) = 0; + (XD_MODIFIER_MASK_SUPER (xd)) = 0; + (XD_MODIFIER_MASK_HYPER (xd)) = 0; + + modifier_keymap = (XGetModifierMapping ((XD_DISPLAY (xd)))); + modifier_to_keycodes_table = (modifier_keymap -> modifiermap); + keycodes_per_modifier = (modifier_keymap -> max_keypermod); + + XDisplayKeycodes ((XD_DISPLAY (xd)), (& min_keycode), (& max_keycode)); + + keycode_to_keysyms_table = + (XGetKeyboardMapping ((XD_DISPLAY (xd)), + min_keycode, + (max_keycode - min_keycode + 1), + (& keysyms_per_keycode))); + + /* Go through each of the 8 non-preassigned modifiers, which start at + 3 (Mod1), after Shift, Control, and Lock. For each modifier, go + through all of the (non-zero) keycodes attached to it; for each + keycode, go through all of the keysyms attached to it; check each + keysym for the modifiers that we're interested in (Meta, Hyper, + and Super). */ + + { + int modifier_index; + + for (modifier_index = 3; (modifier_index < 8); modifier_index += 1) + { + int modifier_mask = (MODIFIER_INDEX_TO_MASK (modifier_index)); + KeyCode * keycodes = + (& (modifier_to_keycodes_table + [modifier_index * keycodes_per_modifier])); + + /* This is a flag specifying whether the modifier has already + been identified as Meta, which takes precedence over Hyper + and Super. (What about precedence between Hyper and + Super...? This is GNU Emacs's behaviour.) */ + int modifier_is_meta_p = 0; + + int keycode_index; + + for (keycode_index = 0; + (keycode_index < keycodes_per_modifier); + keycode_index += 1) + { + KeyCode keycode = (keycodes [keycode_index]); + + if (keycode == 0) + continue; + + { + int keysym_index; + KeySym * keysyms = + (& (keycode_to_keysyms_table + [(keycode - min_keycode) * keysyms_per_keycode])); + + for (keysym_index = 0; + (keysym_index < keysyms_per_keycode); + keysym_index += 1) + switch (keysyms [keysym_index]) + { + case XK_Meta_L: + case XK_Meta_R: + case XK_Alt_L: + case XK_Alt_R: + modifier_is_meta_p = 1; + (XD_MODIFIER_MASK_META (xd)) |= modifier_mask; + break; + + case XK_Hyper_L: + case XK_Hyper_R: + if (! modifier_is_meta_p) + (XD_MODIFIER_MASK_HYPER (xd)) |= modifier_mask; + goto next_modifier; + + case XK_Super_L: + case XK_Super_R: + if (! modifier_is_meta_p) + (XD_MODIFIER_MASK_SUPER (xd)) |= modifier_mask; + goto next_modifier; + } + } + } + + next_modifier: + continue; + } + } + + XFree (((char *) keycode_to_keysyms_table)); + XFreeModifiermap (modifier_keymap); +} static void DEFUN (x_close_display, (xd), struct xdisplay * xd) @@ -1030,14 +1145,15 @@ DEFUN (button_event, (xw, event, type), default: button_number = 0; break; } if (button_number) { + struct xdisplay * xd = (XW_XD (xw)); --button_number; - if ((event -> state) & ShiftMask) { + if (X_MODIFIER_MASK_SHIFT_P ((event -> state), xd)) { button_number += 5; } - if ((event -> state) & ControlMask) { + if (X_MODIFIER_MASK_CONTROL_P ((event -> state), xd)) { button_number += 10; } - if ((event -> state) & Mod1Mask) { + if (X_MODIFIER_MASK_META_P ((event -> state), xd)) { button_number += 20; } conversion = (LONG_TO_UNSIGNED_FIXNUM (button_number)); @@ -1050,29 +1166,47 @@ DEFUN (button_event, (xw, event, type), return (result); } +/* This handles only the modifier bits that Scheme supports. + At the moment, these are Control, Meta, Super, and Hyper. + This might want to change if the character abstraction were ever to + change, or if the X11 interface were to be changed to use something + other than Scheme characters to convey key presses. */ + static SCHEME_OBJECT -DEFUN (convert_bucky_bits, (state, allp), unsigned int state AND int allp) +DEFUN (x_modifier_mask_to_bucky_bits, (mask, xd), + unsigned int mask AND + struct xdisplay * xd) { long bucky = 0; - if (state & Mod1Mask) bucky |= 0x0001; /* meta */ - if (state & ControlMask) bucky |= 0x0002; /* control */ - if (allp) - { - if (state & Mod2Mask) bucky |= 0x0004; /* super */ - if (state & Mod3Mask) bucky |= 0x0008; /* hyper */ - if (state & ShiftMask) bucky |= 0x0010; - if (state & LockMask) bucky |= 0x0020; - if (state & Mod4Mask) bucky |= 0x0040; - if (state & Mod5Mask) bucky |= 0x0080; - if (state & Button1Mask) bucky |= 0x0100; - if (state & Button2Mask) bucky |= 0x0200; - if (state & Button3Mask) bucky |= 0x0400; - if (state & Button4Mask) bucky |= 0x0800; - if (state & Button5Mask) bucky |= 0x1000; - } + if (X_MODIFIER_MASK_CONTROL_P (mask, xd)) bucky |= CHAR_BITS_CONTROL; + if (X_MODIFIER_MASK_META_P (mask, xd)) bucky |= CHAR_BITS_META; + if (X_MODIFIER_MASK_SUPER_P (mask, xd)) bucky |= CHAR_BITS_SUPER; + if (X_MODIFIER_MASK_HYPER_P (mask, xd)) bucky |= CHAR_BITS_HYPER; return (LONG_TO_UNSIGNED_FIXNUM (bucky)); } +/* I'm not sure why we have a function for this. */ + +static SCHEME_OBJECT +DEFUN (x_key_button_mask_to_scheme, (x_state), unsigned int x_state) +{ + long scheme_state = 0; + if (x_state & ControlMask) scheme_state |= 0x0001; + if (x_state & Mod1Mask) scheme_state |= 0x0002; + if (x_state & Mod2Mask) scheme_state |= 0x0004; + if (x_state & Mod3Mask) scheme_state |= 0x0008; + if (x_state & ShiftMask) scheme_state |= 0x0010; + if (x_state & LockMask) scheme_state |= 0x0020; + if (x_state & Mod4Mask) scheme_state |= 0x0040; + if (x_state & Mod5Mask) scheme_state |= 0x0080; + if (x_state & Button1Mask) scheme_state |= 0x0100; + if (x_state & Button2Mask) scheme_state |= 0x0200; + if (x_state & Button3Mask) scheme_state |= 0x0400; + if (x_state & Button4Mask) scheme_state |= 0x0800; + if (x_state & Button5Mask) scheme_state |= 0x1000; + return (LONG_TO_UNSIGNED_FIXNUM (scheme_state)); +} + static XComposeStatus compose_status; static SCHEME_OBJECT @@ -1117,7 +1251,9 @@ DEFUN (key_event, (xw, event, type), /* Create Scheme bucky bits (kept independent of the character). X has already controlified, so Scheme may choose to ignore the control bucky bit. */ - VECTOR_SET (result, EVENT_1, (convert_bucky_bits ((event -> state), 0))); + VECTOR_SET (result, EVENT_1, + (x_modifier_mask_to_bucky_bits ((event -> state), + (XW_XD (xw))))); /* Move vendor-specific bit from bit 28 (zero-based) to bit 23 so that all keysym values will fit in Scheme fixnums. */ VECTOR_SET @@ -1165,7 +1301,8 @@ DEFUN (x_event_to_object, (event), XEvent * event) EVENT_INTEGER (result, EVENT_0, ((event -> xmotion) . x)); EVENT_INTEGER (result, EVENT_1, ((event -> xmotion) . y)); VECTOR_SET (result, EVENT_2, - (convert_bucky_bits (((event -> xmotion) . state), 1))); + (x_key_button_mask_to_scheme + (((event -> xmotion) . state)))); } break; case ConfigureNotify: @@ -1547,6 +1684,7 @@ DEFINE_PRIMITIVE ("X-OPEN-DISPLAY", Prim_x_open_display, 1, 1, 0) (XD_WM_TAKE_FOCUS (xd)) = (XInternAtom ((XD_DISPLAY (xd)), "WM_TAKE_FOCUS", False)); (XD_CACHED_EVENT_P (xd)) = 0; + x_initialize_display_modifier_masks (xd); XRebindKeysym ((XD_DISPLAY (xd)), XK_BackSpace, 0, 0, "\177", 1); PRIMITIVE_RETURN (XD_TO_OBJECT (xd)); } @@ -1859,7 +1997,7 @@ DEFINE_PRIMITIVE ("X-WINDOW-QUERY-POINTER", Prim_x_window_query_pointer, 1, 1, 0 VECTOR_SET (result, 1, (long_to_integer (root_y))); VECTOR_SET (result, 2, (long_to_integer (win_x))); VECTOR_SET (result, 3, (long_to_integer (win_y))); - VECTOR_SET (result, 4, (convert_bucky_bits (keys_buttons, 1))); + VECTOR_SET (result, 4, (x_key_button_mask_to_scheme (keys_buttons))); PRIMITIVE_RETURN (result); } }