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)
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,
/* 0x10 */ 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
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
// 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);
}
}
}
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)) {
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;
if (keyIndex != m_keysymMap.end()) {
// the keysym is mapped to some keycode. create the keystrokes
// for this keysym.
return mapToKeystrokes(keys, keyIndex, isAutoRepeat);
}
}
return keycode;
return 0;
}
void
@ -794,6 +800,7 @@ CXWindowsKeyState::mapToKeystrokes(Keystrokes& keys,
if (isAutoRepeat &&
(m_keyControl.auto_repeats[keycode >> 3] &
static_cast<char>(1 << (keycode & 7))) == 0) {
LOG((CLOG_DEBUG2 "non-autorepeating"));
return 0;
}
@ -923,24 +930,34 @@ CXWindowsKeyState::adjustModifiers(Keystrokes& keys,
// get mode switch set correctly. do this before shift because
// mode switch may be sensitive to the shift modifier and will
// set/reset it as necessary.
const bool wantModeSwitch = ((desiredMask & KeyModifierModeSwitch) != 0);
const bool haveModeSwitch = ((currentMask & KeyModifierModeSwitch) != 0);
bool forceShift = false;
bool wantShift = ((desiredMask & KeyModifierShift) != 0);
bool wantModeSwitch = ((desiredMask & KeyModifierModeSwitch) != 0);
bool haveModeSwitch = ((currentMask & KeyModifierModeSwitch) != 0);
if (wantModeSwitch != haveModeSwitch) {
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);
assert(modeSwitchIndex != m_keysymMap.end());
if (modeSwitchIndex->second.m_shiftSensitive[0]) {
const bool wantShift = false;
const bool haveShift = ((currentMask & KeyModifierShift) != 0);
if (wantShift != haveShift) {
bool haveShift = ((currentMask & KeyModifierShift) != 0);
if (haveShift) {
// add shift keystrokes
LOG((CLOG_DEBUG2 "fix shift for mode switch"));
if (!mapModifier(keys, undo, KeyModifierShift, wantShift)) {
if (!mapModifier(keys, undo, KeyModifierShift, false, true)) {
return false;
}
// our local concept of shift has flipped
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
const bool wantShift = ((desiredMask & KeyModifierShift) != 0);
const bool haveShift = ((currentMask & KeyModifierShift) != 0);
bool haveShift = ((currentMask & KeyModifierShift) != 0);
if (wantShift != haveShift) {
// add shift keystrokes
LOG((CLOG_DEBUG2 "fix shift"));
if (!mapModifier(keys, undo, KeyModifierShift, wantShift)) {
if (!mapModifier(keys, undo, KeyModifierShift, wantShift, forceShift)) {
return false;
}
currentMask ^= KeyModifierShift;

View File

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

View File

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