Fixed dead key and AltGr+shift handling on X windows. Also fixed

bug with decomposing characters that have no direct key mapping
but do have a direct key mapping for the character with the opposite
case.
This commit is contained in:
crs 2004-10-24 18:18:01 +00:00
parent 9f6c8f937a
commit f65d53d06a
3 changed files with 78 additions and 59 deletions

View File

@ -95,7 +95,7 @@
#if defined(HAVE_X11_XF86KEYSYM_H) #if defined(HAVE_X11_XF86KEYSYM_H)
static const KeySym g_mapE000[] = static const KeySym g_mapE000[] =
{ {
/* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */ 0, XF86XK_Eject, 0, 0, 0, 0, 0, 0,
/* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x18 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x18 */ 0, 0, 0, 0, 0, 0, 0, 0,
@ -278,6 +278,45 @@ CXWindowsKeyState::mapKey(Keystrokes& keys, KeyID id,
// get the mapping for this keysym // get the mapping for this keysym
KeySymIndex keyIndex = m_keysymMap.find(keysym); KeySymIndex keyIndex = m_keysymMap.find(keysym);
if (keyIndex != m_keysymMap.end()) {
// the keysym is mapped to some keycode. create the keystrokes
// for this keysym.
return mapToKeystrokes(keys, keyIndex, isAutoRepeat);
}
// we can't find the keysym mapped to any keycode. this doesn't
// necessarily mean we can't generate the keysym, though. if the
// keysym can be created by combining keysyms then we may still
// be okay.
CXWindowsUtil::KeySyms decomposition;
if (CXWindowsUtil::decomposeKeySym(keysym, decomposition)) {
LOG((CLOG_DEBUG2 "decomposed keysym 0x%08x into %d keysyms", keysym, decomposition.size()));
// map each decomposed keysym to keystrokes. we want the mask
// and the keycode from the last keysym (which should be the
// only non-dead key). the dead keys are not sensitive to
// anything but shift and mode switch.
KeyButton keycode = 0;
for (CXWindowsUtil::KeySyms::const_iterator i = decomposition.begin();
i != decomposition.end(); ++i) {
// lookup the key
keysym = *i;
keyIndex = m_keysymMap.find(keysym);
if (keyIndex == m_keysymMap.end()) {
// missing a required keysym
LOG((CLOG_DEBUG2 "can't map keysym %d: 0x%04x", i - decomposition.begin(), keysym));
return 0;
}
// the keysym is mapped to some keycode
keycode = mapToKeystrokes(keys, keyIndex, isAutoRepeat);
if (keycode == 0) {
return 0;
}
}
return keycode;
}
// if the mapping isn't found and keysym is caps lock sensitive // if the mapping isn't found and keysym is caps lock sensitive
// then convert the case of the keysym and try again. // then convert the case of the keysym and try again.
@ -292,47 +331,14 @@ CXWindowsKeyState::mapKey(Keystrokes& keys, KeyID id,
keyIndex = m_keysymMap.find(lKey); keyIndex = m_keysymMap.find(lKey);
} }
} }
} if (keyIndex != m_keysymMap.end()) {
// the keysym is mapped to some keycode. create the keystrokes
if (keyIndex != m_keysymMap.end()) { // for this keysym.
// the keysym is mapped to some keycode. create the keystrokes return mapToKeystrokes(keys, keyIndex, isAutoRepeat);
// for this keysym.
return mapToKeystrokes(keys, keyIndex, isAutoRepeat);
}
// we can't find the keysym mapped to any keycode. this doesn't
// necessarily mean we can't generate the keysym, though. if the
// keysym can be created by combining keysyms then we may still
// be okay.
CXWindowsUtil::KeySyms decomposition;
if (!CXWindowsUtil::decomposeKeySym(keysym, decomposition)) {
return 0;
}
LOG((CLOG_DEBUG2 "decomposed keysym 0x%08x into %d keysyms", keysym, decomposition.size()));
// map each decomposed keysym to keystrokes. we want the mask
// and the keycode from the last keysym (which should be the
// only non-dead key). the dead keys are not sensitive to
// anything but shift and mode switch.
KeyButton keycode = 0;
for (CXWindowsUtil::KeySyms::const_iterator i = decomposition.begin();
i != decomposition.end(); ++i) {
// lookup the key
keysym = *i;
keyIndex = m_keysymMap.find(keysym);
if (keyIndex == m_keysymMap.end()) {
// missing a required keysym
return 0;
}
// the keysym is mapped to some keycode
keycode = mapToKeystrokes(keys, keyIndex, isAutoRepeat);
if (keycode == 0) {
return 0;
} }
} }
return keycode; return 0;
} }
void void
@ -794,6 +800,7 @@ CXWindowsKeyState::mapToKeystrokes(Keystrokes& keys,
if (isAutoRepeat && if (isAutoRepeat &&
(m_keyControl.auto_repeats[keycode >> 3] & (m_keyControl.auto_repeats[keycode >> 3] &
static_cast<char>(1 << (keycode & 7))) == 0) { static_cast<char>(1 << (keycode & 7))) == 0) {
LOG((CLOG_DEBUG2 "non-autorepeating"));
return 0; return 0;
} }
@ -923,24 +930,34 @@ CXWindowsKeyState::adjustModifiers(Keystrokes& keys,
// get mode switch set correctly. do this before shift because // get mode switch set correctly. do this before shift because
// mode switch may be sensitive to the shift modifier and will // mode switch may be sensitive to the shift modifier and will
// set/reset it as necessary. // set/reset it as necessary.
const bool wantModeSwitch = ((desiredMask & KeyModifierModeSwitch) != 0); bool forceShift = false;
const bool haveModeSwitch = ((currentMask & KeyModifierModeSwitch) != 0); bool wantShift = ((desiredMask & KeyModifierShift) != 0);
bool wantModeSwitch = ((desiredMask & KeyModifierModeSwitch) != 0);
bool haveModeSwitch = ((currentMask & KeyModifierModeSwitch) != 0);
if (wantModeSwitch != haveModeSwitch) { if (wantModeSwitch != haveModeSwitch) {
LOG((CLOG_DEBUG2 "fix mode switch")); LOG((CLOG_DEBUG2 "fix mode switch"));
// adjust shift if necessary // adjust shift if necessary (i.e. turn it off it's on and mode
// shift is sensitive to the shift key)
KeySymIndex modeSwitchIndex = m_keysymMap.find(m_modeSwitchKeysym); KeySymIndex modeSwitchIndex = m_keysymMap.find(m_modeSwitchKeysym);
assert(modeSwitchIndex != m_keysymMap.end()); assert(modeSwitchIndex != m_keysymMap.end());
if (modeSwitchIndex->second.m_shiftSensitive[0]) { if (modeSwitchIndex->second.m_shiftSensitive[0]) {
const bool wantShift = false; bool haveShift = ((currentMask & KeyModifierShift) != 0);
const bool haveShift = ((currentMask & KeyModifierShift) != 0); if (haveShift) {
if (wantShift != haveShift) {
// add shift keystrokes // add shift keystrokes
LOG((CLOG_DEBUG2 "fix shift for mode switch")); LOG((CLOG_DEBUG2 "fix shift for mode switch"));
if (!mapModifier(keys, undo, KeyModifierShift, wantShift)) { if (!mapModifier(keys, undo, KeyModifierShift, false, true)) {
return false; return false;
} }
// our local concept of shift has flipped
currentMask ^= KeyModifierShift; currentMask ^= KeyModifierShift;
// force shift to get turned on below if we had to turn
// off here and shift is desired. if we didn't force it
// then mapModifier would think shift is already down
// and ignore the request.
forceShift = wantShift;
} }
} }
@ -952,12 +969,11 @@ CXWindowsKeyState::adjustModifiers(Keystrokes& keys,
} }
// get shift set correctly // get shift set correctly
const bool wantShift = ((desiredMask & KeyModifierShift) != 0); bool haveShift = ((currentMask & KeyModifierShift) != 0);
const bool haveShift = ((currentMask & KeyModifierShift) != 0);
if (wantShift != haveShift) { if (wantShift != haveShift) {
// add shift keystrokes // add shift keystrokes
LOG((CLOG_DEBUG2 "fix shift")); LOG((CLOG_DEBUG2 "fix shift"));
if (!mapModifier(keys, undo, KeyModifierShift, wantShift)) { if (!mapModifier(keys, undo, KeyModifierShift, wantShift, forceShift)) {
return false; return false;
} }
currentMask ^= KeyModifierShift; currentMask ^= KeyModifierShift;

View File

@ -295,7 +295,7 @@ CKeyState::addModifier(KeyModifierMask modifier, const KeyButtons& buttons)
bool bool
CKeyState::mapModifier(Keystrokes& keys, Keystrokes& undo, CKeyState::mapModifier(Keystrokes& keys, Keystrokes& undo,
KeyModifierMask mask, bool desireActive) const KeyModifierMask mask, bool desireActive, bool force) const
{ {
// look up modifier // look up modifier
const KeyButtons& buttons = m_maskToKeys[getIndexForModifier(mask)]; const KeyButtons& buttons = m_maskToKeys[getIndexForModifier(mask)];
@ -304,7 +304,7 @@ CKeyState::mapModifier(Keystrokes& keys, Keystrokes& undo,
} }
// ignore if already in desired state // ignore if already in desired state
if (isModifierActive(mask) == desireActive) { if (!force && isModifierActive(mask) == desireActive) {
return true; return true;
} }

View File

@ -102,16 +102,19 @@ protected:
//! Get key events to change modifier state //! Get key events to change modifier state
/*! /*!
Retrieves the key events necessary to activate (\c desireActive is true) Retrieves the key events necessary to activate (\p desireActive is true)
or deactivate (\c desireActive is false) the modifier given by \c mask or deactivate (\p desireActive is false) the modifier given by \p mask
by pushing them onto the back of \c keys. \c mask must specify exactly by pushing them onto the back of \p keys. \p mask must specify exactly
one modifier. \c undo receives the key events necessary to restore the one modifier. \p undo receives the key events necessary to restore the
modifier's previous state. They're pushed onto \c undo in the reverse modifier's previous state. They're pushed onto \p undo in the reverse
order they should be executed. Returns true if the modifier can be order they should be executed. If \p force is false then \p keys and
adjusted, false otherwise. \p undo are only changed if the modifier is not currently in the
desired state. If \p force is true then \p keys and \p undo are always
changed. Returns true if the modifier can be adjusted, false otherwise.
*/ */
bool mapModifier(Keystrokes& keys, Keystrokes& undo, bool mapModifier(Keystrokes& keys, Keystrokes& undo,
KeyModifierMask mask, bool desireActive) const; KeyModifierMask mask, bool desireActive,
bool force = false) const;
//! Update the key state //! Update the key state
/*! /*!