arch: move X11 modifier-keymap discovery into X11 backend
xmodifier.c contained x_reset_modifier_mapping which walked the X
server's modifier map via XGetModifierMapping / XFreeModifiermap to
discover the X11 modifier indices for Meta/Hyper/Super/Alt keysyms.
This was 4 direct Xlib calls in shared src/.
Refactor:
src/xmodifier.c — now only holds the modifier-mask state and the
portable wXModifierFromKey / wXModifierToShortcut
Label / wSetModifierMasks helpers used by shared
policy code. No more Xlib symbols.
src/backend/x11/x11_backend.c — owns x11_reset_modifier_mapping,
called from x11_extensions_init. Calls
wSetModifierMasks at the end so shared code
answers modifier lookups correctly.
src/xmodifier.h — drops wXModifierInitialize. Wayland never needed
it; X11 calls the local x11_reset_modifier_mapping
directly.
The unused ModeMask static was dropped along the way.
This commit is contained in:
parent
a789abc09f
commit
9cca44c765
|
|
@ -2424,6 +2424,109 @@ x11_client_get_gnustep_attrs(WNativeWindow win, GNUstepWMAttributes **attr_out)
|
|||
return True;
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk the X server's modifier map to discover which X11 modifier
|
||||
* indices the Meta/Hyper/Super/Alt keysyms are bound to, then call
|
||||
* wSetModifierMasks so shared code (rootmenu, defaults, misc) can
|
||||
* answer wXModifierFromKey / wXModifierToShortcutLabel correctly.
|
||||
*
|
||||
* Originally lived in src/xmodifier.c (taken from XEmacs 20.3-b17,
|
||||
* Sept 1997); moved here so shared code carries no Xlib dependency.
|
||||
*/
|
||||
static const char *x11_modindex_to_name(int idx)
|
||||
{
|
||||
switch (idx) {
|
||||
case ShiftMapIndex: return "ModShift";
|
||||
case LockMapIndex: return "ModLock";
|
||||
case ControlMapIndex: return "ModControl";
|
||||
case Mod1MapIndex: return "Mod1";
|
||||
case Mod2MapIndex: return "Mod2";
|
||||
case Mod3MapIndex: return "Mod3";
|
||||
case Mod4MapIndex: return "Mod4";
|
||||
case Mod5MapIndex: return "Mod5";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
static void x11_reset_modifier_mapping(void)
|
||||
{
|
||||
int meta_bit = 0, hyper_bit = 0, super_bit = 0, alt_bit = 0, mode_bit = 0;
|
||||
XModifierKeymap *kmap = XGetModifierMapping(dpy);
|
||||
int mkpm = kmap->max_keypermod;
|
||||
|
||||
for (int idx = 0; idx < 8; idx++) {
|
||||
for (int k = 0; k < mkpm; k++) {
|
||||
KeySym last_sym = 0;
|
||||
for (int col = 0; col < 4; col += 2) {
|
||||
KeyCode code = kmap->modifiermap[idx * mkpm + k];
|
||||
KeySym sym = W_KeycodeToKeysym(dpy, code, col);
|
||||
if (sym == last_sym) continue;
|
||||
last_sym = sym;
|
||||
|
||||
int *target = NULL;
|
||||
int fixed_mask = 0;
|
||||
const char *name = NULL;
|
||||
switch (sym) {
|
||||
case WM_KEY_MODE_SWITCH: name = "Mode_switch"; target = &mode_bit; break;
|
||||
case WM_KEY_META_L: name = "Meta_L"; target = &meta_bit; break;
|
||||
case WM_KEY_META_R: name = "Meta_R"; target = &meta_bit; break;
|
||||
case WM_KEY_SUPER_L: name = "Super_L"; target = &super_bit; break;
|
||||
case WM_KEY_SUPER_R: name = "Super_R"; target = &super_bit; break;
|
||||
case WM_KEY_HYPER_L: name = "Hyper_L"; target = &hyper_bit; break;
|
||||
case WM_KEY_HYPER_R: name = "Hyper_R"; target = &hyper_bit; break;
|
||||
case WM_KEY_ALT_L: name = "Alt_L"; target = &alt_bit; break;
|
||||
case WM_KEY_ALT_R: name = "Alt_R"; target = &alt_bit; break;
|
||||
case WM_KEY_CONTROL_L: name = "Control_L"; fixed_mask = ControlMask; break;
|
||||
case WM_KEY_CONTROL_R: name = "Control_R"; fixed_mask = ControlMask; break;
|
||||
case WM_KEY_SHIFT_L: name = "Shift_L"; fixed_mask = ShiftMask; break;
|
||||
case WM_KEY_SHIFT_R: name = "Shift_R"; fixed_mask = ShiftMask; break;
|
||||
case WM_KEY_SHIFT_LOCK: name = "Shift_Lock"; fixed_mask = LockMask; break;
|
||||
case WM_KEY_CAPS_LOCK: name = "Caps_Lock"; fixed_mask = LockMask; break;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
if (fixed_mask) {
|
||||
if ((1 << idx) != fixed_mask)
|
||||
wwarning(_("key %s (0x%x) generates %s, which is nonsensical"),
|
||||
name, code, x11_modindex_to_name(idx));
|
||||
} else if (target) {
|
||||
if (*target && *target != idx)
|
||||
wwarning(_("key %s (0x%x) generates both %s and %s, "
|
||||
"which is nonsensical"),
|
||||
name, code, x11_modindex_to_name(*target),
|
||||
x11_modindex_to_name(idx));
|
||||
else
|
||||
*target = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If there was no Meta key, try using Alt instead. */
|
||||
if (!meta_bit && alt_bit) { meta_bit = alt_bit; alt_bit = 0; }
|
||||
|
||||
/* mode_bit overrides everything: XLookupString interprets it
|
||||
* unconditionally, so we cannot also call it Meta/Super/Hyper/Alt. */
|
||||
if (mode_bit) {
|
||||
const char *warn = NULL;
|
||||
if (mode_bit == meta_bit) { warn = "Meta"; meta_bit = 0; }
|
||||
else if (mode_bit == hyper_bit) { warn = "Hyper"; hyper_bit = 0; }
|
||||
else if (mode_bit == super_bit) { warn = "Super"; super_bit = 0; }
|
||||
else if (mode_bit == alt_bit) { warn = "Alt"; alt_bit = 0; }
|
||||
if (warn)
|
||||
wwarning("%s is being used for both Mode_switch and %s.",
|
||||
x11_modindex_to_name(mode_bit), warn);
|
||||
}
|
||||
|
||||
wSetModifierMasks(
|
||||
alt_bit ? (1 << alt_bit) : 0,
|
||||
meta_bit ? (1 << meta_bit) : 0,
|
||||
super_bit ? (1 << super_bit) : 0,
|
||||
hyper_bit ? (1 << hyper_bit) : 0);
|
||||
|
||||
XFreeModifiermap(kmap);
|
||||
}
|
||||
|
||||
static void
|
||||
x11_extensions_init(void)
|
||||
{
|
||||
|
|
@ -2442,7 +2545,7 @@ x11_extensions_init(void)
|
|||
}
|
||||
#endif
|
||||
(void) j;
|
||||
wXModifierInitialize();
|
||||
x11_reset_modifier_mapping();
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
|||
311
src/xmodifier.c
311
src/xmodifier.c
|
|
@ -1,276 +1,30 @@
|
|||
/* Grok X modifier mappings for shortcuts.
|
||||
|
||||
Most of this code was taken from src/event-Xt.c in XEmacs 20.3-b17.
|
||||
The copyright(s) from the original XEmacs code are included below.
|
||||
|
||||
Perpetrator: Sudish Joseph <sj@eng.mindspring.net>, Sept. 1997. */
|
||||
|
||||
/* The event_stream interface for X11 with Xt, and/or tty frames.
|
||||
Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995 Sun Microsystems, Inc.
|
||||
Copyright (C) 1996 Ben Wing.
|
||||
|
||||
This file is part of XEmacs.
|
||||
|
||||
XEmacs is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
XEmacs is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with XEmacs; see the file COPYING. if not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301 USA. */
|
||||
/*
|
||||
* xmodifier.c — modifier mask state shared between backends.
|
||||
*
|
||||
* The actual X11 keymap discovery (XGetModifierMapping et al.) lives in
|
||||
* the X11 backend; on Wayland the masks come from xkb via
|
||||
* wSetModifierMasks called from the Wayland backend. This file only
|
||||
* holds the cached masks and the portable name↔mask conversions used
|
||||
* by shared policy code (rootmenu.c, defaults.c, misc.c, usermenu.c).
|
||||
*
|
||||
* History: this file used to contain the modifier-keymap-walking code
|
||||
* (taken from XEmacs 20.3, original copyright Sudish Joseph, 1997, and
|
||||
* Free Software Foundation 1991-1995). That code now lives in
|
||||
* src/backend/x11/x11_backend.c (function x11_reset_modifier_mapping).
|
||||
*/
|
||||
|
||||
#include "wconfig.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <X11/X.h> /* ShiftMask, ControlMask, ModNMask constants */
|
||||
|
||||
#include <WINGs/WUtil.h>
|
||||
#include <WINGs/WINGsP.h>
|
||||
#include "WindowMaker.h"
|
||||
#include "xmodifier.h"
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* keymap handling */
|
||||
/************************************************************************/
|
||||
|
||||
/* X bogusly doesn't define the interpretations of any bits besides
|
||||
ModControl, ModShift, and ModLock; so the Interclient Communication
|
||||
Conventions Manual says that we have to bend over backwards to figure
|
||||
out what the other modifier bits mean. According to ICCCM:
|
||||
|
||||
- Any keycode which is assigned ModControl is a "control" key.
|
||||
|
||||
- Any modifier bit which is assigned to a keycode which generates Meta_L
|
||||
or Meta_R is the modifier bit meaning "meta". Likewise for Super, Hyper,
|
||||
etc.
|
||||
|
||||
- Any keypress event which contains ModControl in its state should be
|
||||
interpreted as a "control" character.
|
||||
|
||||
- Any keypress event which contains a modifier bit in its state which is
|
||||
generated by a keycode whose corresponding keysym is Meta_L or Meta_R
|
||||
should be interpreted as a "meta" character. Likewise for Super, Hyper,
|
||||
etc.
|
||||
|
||||
- It is illegal for a keysym to be associated with more than one modifier
|
||||
bit.
|
||||
|
||||
This means that the only thing that emacs can reasonably interpret as a
|
||||
"meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
|
||||
one of the modifier bits Mod1-Mod5.
|
||||
|
||||
Unfortunately, many keyboards don't have Meta keys in their default
|
||||
configuration. So, if there are no Meta keys, but there are "Alt" keys,
|
||||
emacs will interpret Alt as Meta. If there are both Meta and Alt keys,
|
||||
then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
|
||||
mean "Symbol," but that just confused the hell out of way too many people).
|
||||
|
||||
This works with the default configurations of the 19 keyboard-types I've
|
||||
checked.
|
||||
|
||||
Emacs detects keyboard configurations which violate the above rules, and
|
||||
prints an error message on the standard-error-output. (Perhaps it should
|
||||
use a pop-up-window instead.)
|
||||
*/
|
||||
|
||||
static int MetaMask, HyperMask, SuperMask, AltMask, ModeMask;
|
||||
|
||||
static const char *index_to_name(int indice)
|
||||
{
|
||||
switch (indice) {
|
||||
case ShiftMapIndex:
|
||||
return "ModShift";
|
||||
case LockMapIndex:
|
||||
return "ModLock";
|
||||
case ControlMapIndex:
|
||||
return "ModControl";
|
||||
case Mod1MapIndex:
|
||||
return "Mod1";
|
||||
case Mod2MapIndex:
|
||||
return "Mod2";
|
||||
case Mod3MapIndex:
|
||||
return "Mod3";
|
||||
case Mod4MapIndex:
|
||||
return "Mod4";
|
||||
case Mod5MapIndex:
|
||||
return "Mod5";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
static void x_reset_modifier_mapping(Display * display)
|
||||
{
|
||||
int modifier_index, modifier_key, column, mkpm;
|
||||
int meta_bit = 0;
|
||||
int hyper_bit = 0;
|
||||
int super_bit = 0;
|
||||
int alt_bit = 0;
|
||||
int mode_bit = 0;
|
||||
XModifierKeymap *x_modifier_keymap = XGetModifierMapping(display);
|
||||
|
||||
mkpm = x_modifier_keymap->max_keypermod;
|
||||
for (modifier_index = 0; modifier_index < 8; modifier_index++)
|
||||
for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
|
||||
KeySym last_sym = 0;
|
||||
|
||||
for (column = 0; column < 4; column += 2) {
|
||||
KeyCode code;
|
||||
KeySym sym;
|
||||
|
||||
inline void modwarn(const char *key_name, int old_mod, const char *other_key)
|
||||
{
|
||||
wwarning(_("key %s (0x%x) generates %s, which is generated by %s"),
|
||||
key_name, code, index_to_name(old_mod), other_key);
|
||||
}
|
||||
|
||||
inline void modbarf(const char *key_name, const char *other_mod)
|
||||
{
|
||||
wwarning(_("key %s (0x%x) generates %s, which is nonsensical"),
|
||||
key_name, code, other_mod);
|
||||
}
|
||||
|
||||
inline void check_modifier(const char *key_name, int mask)
|
||||
{
|
||||
if ((1 << modifier_index) != mask)
|
||||
modbarf(key_name, index_to_name(modifier_index));
|
||||
}
|
||||
|
||||
inline void store_modifier(const char *key_name, int *old_mod)
|
||||
{
|
||||
if (*old_mod && *old_mod != modifier_index)
|
||||
wwarning(_("key %s (0x%x) generates both %s and %s, which is nonsensical"),
|
||||
key_name, code, index_to_name(*old_mod), index_to_name(modifier_index));
|
||||
if (modifier_index == ShiftMapIndex) {
|
||||
modbarf(key_name, "ModShift");
|
||||
} else if (modifier_index == LockMapIndex) {
|
||||
modbarf(key_name, "ModLock");
|
||||
} else if (modifier_index == ControlMapIndex) {
|
||||
modbarf(key_name, "ModControl");
|
||||
} else if (sym == WM_KEY_MODE_SWITCH) {
|
||||
mode_bit = modifier_index; /* Mode_switch is special, see below... */
|
||||
} else if (modifier_index == meta_bit && *old_mod != meta_bit) {
|
||||
modwarn(key_name, meta_bit, "Meta");
|
||||
} else if (modifier_index == super_bit && *old_mod != super_bit) {
|
||||
modwarn(key_name, super_bit, "Super");
|
||||
} else if (modifier_index == hyper_bit && *old_mod != hyper_bit) {
|
||||
modwarn(key_name, hyper_bit, "Hyper");
|
||||
} else if (modifier_index == alt_bit && *old_mod != alt_bit) {
|
||||
modwarn(key_name, alt_bit, "Alt");
|
||||
} else {
|
||||
*(old_mod) = modifier_index;
|
||||
}
|
||||
}
|
||||
|
||||
code = x_modifier_keymap->modifiermap[modifier_index * mkpm + modifier_key];
|
||||
sym = W_KeycodeToKeysym(display, code, column);
|
||||
|
||||
if (sym == last_sym)
|
||||
continue;
|
||||
last_sym = sym;
|
||||
|
||||
switch (sym) {
|
||||
case WM_KEY_MODE_SWITCH:
|
||||
store_modifier("Mode_switch", &mode_bit);
|
||||
break;
|
||||
case WM_KEY_META_L:
|
||||
store_modifier("Meta_L", &meta_bit);
|
||||
break;
|
||||
case WM_KEY_META_R:
|
||||
store_modifier("Meta_R", &meta_bit);
|
||||
break;
|
||||
case WM_KEY_SUPER_L:
|
||||
store_modifier("Super_L", &super_bit);
|
||||
break;
|
||||
case WM_KEY_SUPER_R:
|
||||
store_modifier("Super_R", &super_bit);
|
||||
break;
|
||||
case WM_KEY_HYPER_L:
|
||||
store_modifier("Hyper_L", &hyper_bit);
|
||||
break;
|
||||
case WM_KEY_HYPER_R:
|
||||
store_modifier("Hyper_R", &hyper_bit);
|
||||
break;
|
||||
case WM_KEY_ALT_L:
|
||||
store_modifier("Alt_L", &alt_bit);
|
||||
break;
|
||||
case WM_KEY_ALT_R:
|
||||
store_modifier("Alt_R", &alt_bit);
|
||||
break;
|
||||
case WM_KEY_CONTROL_L:
|
||||
check_modifier("Control_L", ControlMask);
|
||||
break;
|
||||
case WM_KEY_CONTROL_R:
|
||||
check_modifier("Control_R", ControlMask);
|
||||
break;
|
||||
case WM_KEY_SHIFT_L:
|
||||
check_modifier("Shift_L", ShiftMask);
|
||||
break;
|
||||
case WM_KEY_SHIFT_R:
|
||||
check_modifier("Shift_R", ShiftMask);
|
||||
break;
|
||||
case WM_KEY_SHIFT_LOCK:
|
||||
check_modifier("Shift_Lock", LockMask);
|
||||
break;
|
||||
case WM_KEY_CAPS_LOCK:
|
||||
check_modifier("Caps_Lock", LockMask);
|
||||
break;
|
||||
|
||||
/* It probably doesn't make any sense for a modifier bit to be
|
||||
assigned to a key that is not one of the above, but OpenWindows
|
||||
assigns modifier bits to a couple of random function keys for
|
||||
no reason that I can discern, so printing a warning here would
|
||||
be annoying. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If there was no Meta key, then try using the Alt key instead.
|
||||
If there is both a Meta key and an Alt key, then the Alt key
|
||||
is not disturbed and remains an Alt key. */
|
||||
if (!meta_bit && alt_bit)
|
||||
meta_bit = alt_bit, alt_bit = 0;
|
||||
|
||||
/* mode_bit overrides everything, since it's processed down inside of
|
||||
XLookupString() instead of by us. If Meta and Mode_switch both
|
||||
generate the same modifier bit (which is an error), then we don't
|
||||
interpret that bit as Meta, because we can't make XLookupString()
|
||||
not interpret it as Mode_switch; and interpreting it as both would
|
||||
be totally wrong. */
|
||||
if (mode_bit) {
|
||||
const char *warn = NULL;
|
||||
|
||||
if (mode_bit == meta_bit)
|
||||
warn = "Meta", meta_bit = 0;
|
||||
else if (mode_bit == hyper_bit)
|
||||
warn = "Hyper", hyper_bit = 0;
|
||||
else if (mode_bit == super_bit)
|
||||
warn = "Super", super_bit = 0;
|
||||
else if (mode_bit == alt_bit)
|
||||
warn = "Alt", alt_bit = 0;
|
||||
if (warn) {
|
||||
wwarning("%s is being used for both Mode_switch and %s.",
|
||||
index_to_name(mode_bit), warn);
|
||||
}
|
||||
}
|
||||
|
||||
MetaMask = (meta_bit ? (1 << meta_bit) : 0);
|
||||
HyperMask = (hyper_bit ? (1 << hyper_bit) : 0);
|
||||
SuperMask = (super_bit ? (1 << super_bit) : 0);
|
||||
AltMask = (alt_bit ? (1 << alt_bit) : 0);
|
||||
ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */
|
||||
|
||||
XFreeModifiermap(x_modifier_keymap);
|
||||
}
|
||||
static int MetaMask, HyperMask, SuperMask, AltMask;
|
||||
|
||||
const char *wXModifierToShortcutLabel(int mask)
|
||||
{
|
||||
|
|
@ -279,21 +33,21 @@ const char *wXModifierToShortcutLabel(int mask)
|
|||
|
||||
if (mask == ShiftMask)
|
||||
return "Sh+";
|
||||
if (mask == ControlMask)
|
||||
if (mask == ControlMask)
|
||||
return "^";
|
||||
if (mask == AltMask)
|
||||
if (mask == AltMask)
|
||||
return "A+";
|
||||
if (mask == Mod1Mask)
|
||||
if (mask == Mod1Mask)
|
||||
return "M1+";
|
||||
if (mask == Mod2Mask)
|
||||
if (mask == Mod2Mask)
|
||||
return "M2+";
|
||||
if (mask == Mod3Mask)
|
||||
if (mask == Mod3Mask)
|
||||
return "M3+";
|
||||
if (mask == Mod4Mask)
|
||||
if (mask == Mod4Mask)
|
||||
return "M4+";
|
||||
if (mask == Mod5Mask)
|
||||
if (mask == Mod5Mask)
|
||||
return "M5+";
|
||||
if (mask == MetaMask)
|
||||
if (mask == MetaMask)
|
||||
return "M+";
|
||||
|
||||
wwarning(_("Can't convert keymask 0x%04X to a shortcut label"), mask);
|
||||
|
|
@ -328,9 +82,11 @@ int wXModifierFromKey(const char *key)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Phase 77: allow non-X11 backends to set standard modifier masks directly.
|
||||
* Called from wl_screen_create_internals with XKB-standard values:
|
||||
* AltMask=Mod1Mask, MetaMask=Mod1Mask, SuperMask=Mod4Mask, HyperMask=0. */
|
||||
/*
|
||||
* Set the standard modifier masks. Called from x11_backend.c after
|
||||
* XGetModifierMapping discovery, or from wl_backend.c with XKB defaults
|
||||
* (Mod1=Alt=Meta, Mod4=Super, Hyper=0).
|
||||
*/
|
||||
void wSetModifierMasks(int alt, int meta, int super, int hyper)
|
||||
{
|
||||
AltMask = alt;
|
||||
|
|
@ -338,10 +94,3 @@ void wSetModifierMasks(int alt, int meta, int super, int hyper)
|
|||
SuperMask = super;
|
||||
HyperMask = hyper;
|
||||
}
|
||||
|
||||
/* Wrapper so that we may fit the WM naming conventions, yet leave the
|
||||
original XEmacs function name in place. */
|
||||
void wXModifierInitialize(void)
|
||||
{
|
||||
x_reset_modifier_mapping(dpy);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,13 @@
|
|||
#ifndef _XMODIFIER_H_INCLUDED
|
||||
#define _XMODIFIER_H_INCLUDED
|
||||
|
||||
void wXModifierInitialize(void);
|
||||
int wXModifierFromKey(const char *key);
|
||||
const char *wXModifierToShortcutLabel(int mask);
|
||||
/* Phase 77: set modifier masks for non-X11 backends (Wayland). */
|
||||
/*
|
||||
* Set standard modifier masks. X11 backend calls this from its
|
||||
* extension-init path after walking the X server's modifier map;
|
||||
* Wayland backend calls this with XKB-standard values.
|
||||
*/
|
||||
void wSetModifierMasks(int alt, int meta, int super, int hyper);
|
||||
|
||||
#endif /* _XMODIFIER_H_INCLUDED */
|
||||
|
|
|
|||
Loading…
Reference in New Issue