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:
parent
9f6c8f937a
commit
f65d53d06a
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
/*!
|
/*!
|
||||||
|
|
Loading…
Reference in New Issue