Added support for X11 compose key (Multi_key). This change fixes
the handling of compose key sequences. The key presses were suppressed but not the corresponding releases, confusing the clients. It also adds support for generating keysyms via the compose key if the necessary dead keys or Mode_switch are not available.
This commit is contained in:
parent
4be95841d2
commit
bdd3635f4b
|
@ -281,60 +281,41 @@ CXWindowsKeyState::mapKey(Keystrokes& keys, KeyID id,
|
|||
if (keyIndex != m_keysymMap.end()) {
|
||||
// the keysym is mapped to some keycode. create the keystrokes
|
||||
// for this keysym.
|
||||
return mapToKeystrokes(keys, keyIndex, isAutoRepeat);
|
||||
return mapToKeystrokes(keys, keyIndex, isAutoRepeat, false);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
if (!isAutoRepeat) {
|
||||
KeyButton keycode = mapDecompositionToKeystrokes(keys, keysym, true);
|
||||
if (keycode != 0) {
|
||||
return keycode;
|
||||
}
|
||||
keycode = mapDecompositionToKeystrokes(keys, keysym, false);
|
||||
if (keycode != 0) {
|
||||
// no key is left synthetically down when using the compose key
|
||||
// so return 0 even though we succeeded.
|
||||
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.
|
||||
if (keyIndex == m_keysymMap.end()) {
|
||||
KeySym lKey, uKey;
|
||||
XConvertCase(keysym, &lKey, &uKey);
|
||||
if (lKey != uKey) {
|
||||
if (lKey == keysym) {
|
||||
keyIndex = m_keysymMap.find(uKey);
|
||||
}
|
||||
else {
|
||||
keyIndex = m_keysymMap.find(lKey);
|
||||
}
|
||||
// if the keysym is caps lock sensitive then convert the case of
|
||||
// the keysym and try again.
|
||||
KeySym lKey, uKey;
|
||||
XConvertCase(keysym, &lKey, &uKey);
|
||||
if (lKey != uKey) {
|
||||
if (lKey == keysym) {
|
||||
keyIndex = m_keysymMap.find(uKey);
|
||||
}
|
||||
else {
|
||||
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);
|
||||
return mapToKeystrokes(keys, keyIndex, isAutoRepeat, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -786,7 +767,8 @@ CXWindowsKeyState::keyIDToKeySym(KeyID id, KeyModifierMask mask) const
|
|||
|
||||
KeyButton
|
||||
CXWindowsKeyState::mapToKeystrokes(Keystrokes& keys,
|
||||
KeySymIndex keyIndex, bool isAutoRepeat) const
|
||||
KeySymIndex keyIndex, bool isAutoRepeat,
|
||||
bool pressAndRelease) const
|
||||
{
|
||||
// keyIndex must be valid
|
||||
assert(keyIndex != m_keysymMap.end());
|
||||
|
@ -873,7 +855,14 @@ CXWindowsKeyState::mapToKeystrokes(Keystrokes& keys,
|
|||
// add the key event
|
||||
Keystroke keystroke;
|
||||
keystroke.m_key = keycode;
|
||||
if (!isAutoRepeat) {
|
||||
if (pressAndRelease) {
|
||||
keystroke.m_press = true;
|
||||
keystroke.m_repeat = false;
|
||||
keys.push_back(keystroke);
|
||||
keystroke.m_press = false;
|
||||
keys.push_back(keystroke);
|
||||
}
|
||||
else if (!isAutoRepeat) {
|
||||
keystroke.m_press = true;
|
||||
keystroke.m_repeat = false;
|
||||
keys.push_back(keystroke);
|
||||
|
@ -895,6 +884,60 @@ CXWindowsKeyState::mapToKeystrokes(Keystrokes& keys,
|
|||
return keycode;
|
||||
}
|
||||
|
||||
KeyButton
|
||||
CXWindowsKeyState::mapDecompositionToKeystrokes(
|
||||
Keystrokes& keys, KeySym keysym, bool usingDeadKeys) const
|
||||
{
|
||||
// decompose the keysym
|
||||
CXWindowsUtil::KeySyms decomposed;
|
||||
if (usingDeadKeys) {
|
||||
if (!CXWindowsUtil::decomposeKeySymWithDeadKeys(keysym, decomposed)) {
|
||||
// no decomposition
|
||||
return 0;
|
||||
}
|
||||
LOG((CLOG_DEBUG2 "decomposed keysym 0x%08x into %d keysyms using dead keys", keysym, decomposed.size()));
|
||||
}
|
||||
else {
|
||||
if (!CXWindowsUtil::decomposeKeySymWithCompose(keysym, decomposed)) {
|
||||
// no decomposition
|
||||
return 0;
|
||||
}
|
||||
LOG((CLOG_DEBUG2 "decomposed keysym 0x%08x into %d keysyms using compose key", keysym, decomposed.size()));
|
||||
}
|
||||
size_t n = decomposed.size();
|
||||
if (n == 0) {
|
||||
// nothing in the decomposition
|
||||
return 0;
|
||||
}
|
||||
|
||||
// map to keystrokes
|
||||
Keystrokes keystrokes;
|
||||
KeyButton keycode = 0;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
// lookup the key
|
||||
keysym = decomposed[i];
|
||||
KeySymIndex 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, keysym));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// the keysym is mapped to some keycode. add press and
|
||||
// release unless this is the last key and usingDeadKeys.
|
||||
keycode = mapToKeystrokes(keystrokes, keyIndex,
|
||||
false, (i + 1 < n || !usingDeadKeys));
|
||||
if (keycode == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// copy keystrokes
|
||||
keys.insert(keys.end(), keystrokes.begin(), keystrokes.end());
|
||||
|
||||
return keycode;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
CXWindowsKeyState::findBestKeyIndex(KeySymIndex keyIndex,
|
||||
KeyModifierMask /*currentMask*/) const
|
||||
|
|
|
@ -100,7 +100,13 @@ private:
|
|||
// map a KeySym into the keystrokes to produce it
|
||||
KeyButton mapToKeystrokes(Keystrokes& keys,
|
||||
KeySymIndex keyIndex,
|
||||
bool isAutoRepeat) const;
|
||||
bool isAutoRepeat,
|
||||
bool pressAndRelease) const;
|
||||
|
||||
// map a decomposition into keystrokes to produce it. returns the
|
||||
// last key added to keys iff successful and 0 otherwise.
|
||||
KeyButton mapDecompositionToKeystrokes(Keystrokes& keys,
|
||||
KeySym keysym, bool usingDeadKeys) const;
|
||||
|
||||
// choose the best set of modifiers to generate the KeySym
|
||||
unsigned int findBestKeyIndex(KeySymIndex keyIndex,
|
||||
|
|
|
@ -334,6 +334,7 @@ CXWindowsScreen::leave()
|
|||
if (m_ic != NULL) {
|
||||
XmbResetIC(m_ic);
|
||||
XSetICFocus(m_ic);
|
||||
m_filtered.clear();
|
||||
}
|
||||
|
||||
// now off screen
|
||||
|
@ -876,6 +877,18 @@ CXWindowsScreen::handleSystemEvent(const CEvent& event, void*)
|
|||
|
||||
// now filter the event
|
||||
if (XFilterEvent(xevent, None)) {
|
||||
if (xevent->type == KeyPress) {
|
||||
// add filtered presses to the filtered list
|
||||
m_filtered.insert(m_lastKeycode);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// discard matching key releases for key presses that were
|
||||
// filtered and remove them from our filtered list.
|
||||
else if (xevent->type == KeyRelease &&
|
||||
m_filtered.count(xevent->xkey.keycode) > 0) {
|
||||
m_filtered.erase(xevent->xkey.keycode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1030,14 +1043,26 @@ CXWindowsScreen::onKeyPress(XKeyEvent& xkey)
|
|||
|
||||
// get which button. see call to XFilterEvent() in onEvent()
|
||||
// for more info.
|
||||
bool isFake = false;
|
||||
KeyButton keycode = static_cast<KeyButton>(xkey.keycode);
|
||||
if (keycode == 0) {
|
||||
isFake = true;
|
||||
keycode = static_cast<KeyButton>(m_lastKeycode);
|
||||
if (keycode == 0) {
|
||||
// no keycode
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// handle key
|
||||
m_keyState->sendKeyEvent(getEventTarget(),
|
||||
true, false, key, mask, 1, keycode);
|
||||
|
||||
// do fake release if this is a fake press
|
||||
if (isFake) {
|
||||
m_keyState->sendKeyEvent(getEventTarget(),
|
||||
false, false, key, mask, 1, keycode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define CXWINDOWSSCREEN_H
|
||||
|
||||
#include "CPlatformScreen.h"
|
||||
#include "stdset.h"
|
||||
#include "stdvector.h"
|
||||
#if X_DISPLAY_MISSING
|
||||
# error X11 is required to build synergy
|
||||
|
@ -135,6 +136,7 @@ private:
|
|||
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
|
||||
|
||||
private:
|
||||
typedef std::set<bool> CFilteredKeycodes;
|
||||
// true if screen is being used as a primary screen, false otherwise
|
||||
bool m_isPrimary;
|
||||
|
||||
|
@ -164,6 +166,7 @@ private:
|
|||
XIM m_im;
|
||||
XIC m_ic;
|
||||
KeyCode m_lastKeycode;
|
||||
CFilteredKeycodes m_filtered;
|
||||
|
||||
// clipboards
|
||||
CXWindowsClipboard* m_clipboard[kClipboardEnd];
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "CLog.h"
|
||||
#include "CStringUtil.h"
|
||||
#include <X11/Xatom.h>
|
||||
#define XK_MISCELLANY
|
||||
#define XK_XKB_KEYS
|
||||
#define XK_LATIN1
|
||||
#define XK_LATIN2
|
||||
|
@ -814,7 +815,7 @@ struct codepair {
|
|||
{ 0x20ac, 0x20ac } /* EuroSign EURO SIGN */
|
||||
};
|
||||
|
||||
static const KeySym s_rawDecomposeTable[] = {
|
||||
static const KeySym s_rawDeadDecomposeTable[] = {
|
||||
// non-dead version of dead keys
|
||||
XK_grave, XK_dead_grave, XK_space, 0,
|
||||
XK_acute, XK_dead_acute, XK_space, 0,
|
||||
|
@ -1026,6 +1027,116 @@ static const KeySym s_rawDecomposeTable[] = {
|
|||
0
|
||||
};
|
||||
|
||||
static const KeySym s_rawComposedDecomposeTable[] = {
|
||||
XK_AE, XK_Multi_key, XK_A, XK_E, 0,
|
||||
XK_Aacute, XK_Multi_key, XK_A, XK_apostrophe, 0,
|
||||
XK_Acircumflex, XK_Multi_key, XK_A, XK_asciicircum, 0,
|
||||
XK_Adiaeresis, XK_Multi_key, XK_A, XK_quotedbl, 0,
|
||||
XK_Agrave, XK_Multi_key, XK_A, XK_grave, 0,
|
||||
XK_Aring, XK_Multi_key, XK_A, XK_asterisk, 0,
|
||||
XK_Atilde, XK_Multi_key, XK_A, XK_asciitilde, 0,
|
||||
XK_Ccedilla, XK_Multi_key, XK_C, XK_comma, 0,
|
||||
XK_ETH, XK_Multi_key, XK_D, XK_minus, 0,
|
||||
XK_Eacute, XK_Multi_key, XK_E, XK_apostrophe, 0,
|
||||
XK_Ecircumflex, XK_Multi_key, XK_E, XK_asciicircum, 0,
|
||||
XK_Ediaeresis, XK_Multi_key, XK_E, XK_quotedbl, 0,
|
||||
XK_Egrave, XK_Multi_key, XK_E, XK_grave, 0,
|
||||
XK_Iacute, XK_Multi_key, XK_I, XK_apostrophe, 0,
|
||||
XK_Icircumflex, XK_Multi_key, XK_I, XK_asciicircum, 0,
|
||||
XK_Idiaeresis, XK_Multi_key, XK_I, XK_quotedbl, 0,
|
||||
XK_Igrave, XK_Multi_key, XK_I, XK_grave, 0,
|
||||
XK_Ntilde, XK_Multi_key, XK_N, XK_asciitilde, 0,
|
||||
XK_Oacute, XK_Multi_key, XK_O, XK_apostrophe, 0,
|
||||
XK_Ocircumflex, XK_Multi_key, XK_O, XK_asciicircum, 0,
|
||||
XK_Odiaeresis, XK_Multi_key, XK_O, XK_quotedbl, 0,
|
||||
XK_Ograve, XK_Multi_key, XK_O, XK_grave, 0,
|
||||
XK_Ooblique, XK_Multi_key, XK_O, XK_slash, 0,
|
||||
XK_Otilde, XK_Multi_key, XK_O, XK_asciitilde, 0,
|
||||
XK_THORN, XK_Multi_key, XK_T, XK_H, 0,
|
||||
XK_Uacute, XK_Multi_key, XK_U, XK_apostrophe, 0,
|
||||
XK_Ucircumflex, XK_Multi_key, XK_U, XK_asciicircum, 0,
|
||||
XK_Udiaeresis, XK_Multi_key, XK_U, XK_quotedbl, 0,
|
||||
XK_Ugrave, XK_Multi_key, XK_U, XK_grave, 0,
|
||||
XK_Yacute, XK_Multi_key, XK_Y, XK_apostrophe, 0,
|
||||
XK_aacute, XK_Multi_key, XK_a, XK_apostrophe, 0,
|
||||
XK_acircumflex, XK_Multi_key, XK_a, XK_asciicircum, 0,
|
||||
XK_acute, XK_Multi_key, XK_apostrophe, XK_apostrophe, 0,
|
||||
XK_adiaeresis, XK_Multi_key, XK_a, XK_quotedbl, 0,
|
||||
XK_ae, XK_Multi_key, XK_a, XK_e, 0,
|
||||
XK_agrave, XK_Multi_key, XK_a, XK_grave, 0,
|
||||
XK_aring, XK_Multi_key, XK_a, XK_asterisk, 0,
|
||||
XK_at, XK_Multi_key, XK_A, XK_T, 0,
|
||||
XK_atilde, XK_Multi_key, XK_a, XK_asciitilde, 0,
|
||||
XK_backslash, XK_Multi_key, XK_slash, XK_slash, 0,
|
||||
XK_bar, XK_Multi_key, XK_L, XK_V, 0,
|
||||
XK_braceleft, XK_Multi_key, XK_parenleft, XK_minus, 0,
|
||||
XK_braceright, XK_Multi_key, XK_parenright, XK_minus, 0,
|
||||
XK_bracketleft, XK_Multi_key, XK_parenleft, XK_parenleft, 0,
|
||||
XK_bracketright, XK_Multi_key, XK_parenright, XK_parenright, 0,
|
||||
XK_brokenbar, XK_Multi_key, XK_B, XK_V, 0,
|
||||
XK_ccedilla, XK_Multi_key, XK_c, XK_comma, 0,
|
||||
XK_cedilla, XK_Multi_key, XK_comma, XK_comma, 0,
|
||||
XK_cent, XK_Multi_key, XK_c, XK_slash, 0,
|
||||
XK_copyright, XK_Multi_key, XK_parenleft, XK_c, 0,
|
||||
XK_currency, XK_Multi_key, XK_o, XK_x, 0,
|
||||
XK_degree, XK_Multi_key, XK_0, XK_asciicircum, 0,
|
||||
XK_diaeresis, XK_Multi_key, XK_quotedbl, XK_quotedbl, 0,
|
||||
XK_division, XK_Multi_key, XK_colon, XK_minus, 0,
|
||||
XK_eacute, XK_Multi_key, XK_e, XK_apostrophe, 0,
|
||||
XK_ecircumflex, XK_Multi_key, XK_e, XK_asciicircum, 0,
|
||||
XK_ediaeresis, XK_Multi_key, XK_e, XK_quotedbl, 0,
|
||||
XK_egrave, XK_Multi_key, XK_e, XK_grave, 0,
|
||||
XK_eth, XK_Multi_key, XK_d, XK_minus, 0,
|
||||
XK_exclamdown, XK_Multi_key, XK_exclam, XK_exclam, 0,
|
||||
XK_guillemotleft, XK_Multi_key, XK_less, XK_less, 0,
|
||||
XK_guillemotright, XK_Multi_key, XK_greater, XK_greater, 0,
|
||||
XK_numbersign, XK_Multi_key, XK_plus, XK_plus, 0,
|
||||
XK_hyphen, XK_Multi_key, XK_minus, XK_minus, 0,
|
||||
XK_iacute, XK_Multi_key, XK_i, XK_apostrophe, 0,
|
||||
XK_icircumflex, XK_Multi_key, XK_i, XK_asciicircum, 0,
|
||||
XK_idiaeresis, XK_Multi_key, XK_i, XK_quotedbl, 0,
|
||||
XK_igrave, XK_Multi_key, XK_i, XK_grave, 0,
|
||||
XK_macron, XK_Multi_key, XK_minus, XK_asciicircum, 0,
|
||||
XK_masculine, XK_Multi_key, XK_o, XK_underscore, 0,
|
||||
XK_mu, XK_Multi_key, XK_u, XK_slash, 0,
|
||||
XK_multiply, XK_Multi_key, XK_x, XK_x, 0,
|
||||
XK_nobreakspace, XK_Multi_key, XK_space, XK_space, 0,
|
||||
XK_notsign, XK_Multi_key, XK_comma, XK_minus, 0,
|
||||
XK_ntilde, XK_Multi_key, XK_n, XK_asciitilde, 0,
|
||||
XK_oacute, XK_Multi_key, XK_o, XK_apostrophe, 0,
|
||||
XK_ocircumflex, XK_Multi_key, XK_o, XK_asciicircum, 0,
|
||||
XK_odiaeresis, XK_Multi_key, XK_o, XK_quotedbl, 0,
|
||||
XK_ograve, XK_Multi_key, XK_o, XK_grave, 0,
|
||||
XK_onehalf, XK_Multi_key, XK_1, XK_2, 0,
|
||||
XK_onequarter, XK_Multi_key, XK_1, XK_4, 0,
|
||||
XK_onesuperior, XK_Multi_key, XK_1, XK_asciicircum, 0,
|
||||
XK_ordfeminine, XK_Multi_key, XK_a, XK_underscore, 0,
|
||||
XK_oslash, XK_Multi_key, XK_o, XK_slash, 0,
|
||||
XK_otilde, XK_Multi_key, XK_o, XK_asciitilde, 0,
|
||||
XK_paragraph, XK_Multi_key, XK_p, XK_exclam, 0,
|
||||
XK_periodcentered, XK_Multi_key, XK_period, XK_period, 0,
|
||||
XK_plusminus, XK_Multi_key, XK_plus, XK_minus, 0,
|
||||
XK_questiondown, XK_Multi_key, XK_question, XK_question, 0,
|
||||
XK_registered, XK_Multi_key, XK_parenleft, XK_r, 0,
|
||||
XK_section, XK_Multi_key, XK_s, XK_o, 0,
|
||||
XK_ssharp, XK_Multi_key, XK_s, XK_s, 0,
|
||||
XK_sterling, XK_Multi_key, XK_L, XK_minus, 0,
|
||||
XK_thorn, XK_Multi_key, XK_t, XK_h, 0,
|
||||
XK_threequarters, XK_Multi_key, XK_3, XK_4, 0,
|
||||
XK_threesuperior, XK_Multi_key, XK_3, XK_asciicircum, 0,
|
||||
XK_twosuperior, XK_Multi_key, XK_2, XK_asciicircum, 0,
|
||||
XK_uacute, XK_Multi_key, XK_u, XK_apostrophe, 0,
|
||||
XK_ucircumflex, XK_Multi_key, XK_u, XK_asciicircum, 0,
|
||||
XK_udiaeresis, XK_Multi_key, XK_u, XK_quotedbl, 0,
|
||||
XK_ugrave, XK_Multi_key, XK_u, XK_grave, 0,
|
||||
XK_yacute, XK_Multi_key, XK_y, XK_apostrophe, 0,
|
||||
XK_ydiaeresis, XK_Multi_key, XK_y, XK_quotedbl, 0,
|
||||
XK_yen, XK_Multi_key, XK_y, XK_equal, 0,
|
||||
|
||||
// end of table
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CXWindowsUtil
|
||||
|
@ -1033,7 +1144,8 @@ static const KeySym s_rawDecomposeTable[] = {
|
|||
|
||||
CXWindowsUtil::CKeySymMap CXWindowsUtil::s_keySymToUCS4;
|
||||
CXWindowsUtil::CUCS4Map CXWindowsUtil::s_UCS4ToKeySym;
|
||||
CXWindowsUtil::CKeySymsMap CXWindowsUtil::s_decomposedKeySyms;
|
||||
CXWindowsUtil::CKeySymsMap CXWindowsUtil::s_deadKeyDecomposedKeySyms;
|
||||
CXWindowsUtil::CKeySymsMap CXWindowsUtil::s_composeDecomposedKeySyms;
|
||||
|
||||
bool
|
||||
CXWindowsUtil::getWindowProperty(Display* display, Window window,
|
||||
|
@ -1231,18 +1343,33 @@ CXWindowsUtil::mapUCS4ToKeySym(UInt32 c)
|
|||
}
|
||||
|
||||
bool
|
||||
CXWindowsUtil::decomposeKeySym(KeySym keysym, KeySyms& decomposed)
|
||||
CXWindowsUtil::decomposeKeySymWithDeadKeys(KeySym keysym, KeySyms& decomposed)
|
||||
{
|
||||
// unfortunately, X11 doesn't appear to have any way of
|
||||
// decomposing a keysym into its component keysyms. we'll
|
||||
// use a lookup table for certain character sets.
|
||||
initKeyMaps();
|
||||
CKeySymsMap::const_iterator i = s_decomposedKeySyms.find(keysym);
|
||||
if (i == s_decomposedKeySyms.end()) {
|
||||
return false;
|
||||
CKeySymsMap::const_iterator i = s_deadKeyDecomposedKeySyms.find(keysym);
|
||||
if (i != s_deadKeyDecomposedKeySyms.end()) {
|
||||
decomposed = i->second;
|
||||
return true;
|
||||
}
|
||||
decomposed = i->second;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsUtil::decomposeKeySymWithCompose(KeySym keysym, KeySyms& decomposed)
|
||||
{
|
||||
// unfortunately, X11 doesn't appear to have any way of
|
||||
// decomposing a keysym into its component keysyms. we'll
|
||||
// use a lookup table for certain character sets.
|
||||
initKeyMaps();
|
||||
CKeySymsMap::const_iterator i = i = s_composeDecomposedKeySyms.find(keysym);
|
||||
if (i != s_composeDecomposedKeySyms.end()) {
|
||||
decomposed = i->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CString
|
||||
|
@ -1296,10 +1423,22 @@ CXWindowsUtil::initKeyMaps()
|
|||
}
|
||||
|
||||
// fill decomposed key table if not filled yet
|
||||
if (s_decomposedKeySyms.empty()) {
|
||||
for (const KeySym* scan = s_rawDecomposeTable; *scan != 0; ++scan) {
|
||||
if (s_deadKeyDecomposedKeySyms.empty()) {
|
||||
for (const KeySym* scan = s_rawDeadDecomposeTable; *scan != 0; ++scan) {
|
||||
// add an entry for this keysym
|
||||
KeySyms& entry = s_decomposedKeySyms[*scan];
|
||||
KeySyms& entry = s_deadKeyDecomposedKeySyms[*scan];
|
||||
|
||||
// add the decomposed keysyms for the keysym
|
||||
while (*++scan != 0) {
|
||||
entry.push_back(*scan);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s_composeDecomposedKeySyms.empty()) {
|
||||
for (const KeySym* scan =
|
||||
s_rawComposedDecomposeTable; *scan != 0; ++scan) {
|
||||
// add an entry for this keysym
|
||||
KeySyms& entry = s_composeDecomposedKeySyms[*scan];
|
||||
|
||||
// add the decomposed keysyms for the keysym
|
||||
while (*++scan != 0) {
|
||||
|
|
|
@ -73,13 +73,23 @@ public:
|
|||
*/
|
||||
static KeySym mapUCS4ToKeySym(UInt32);
|
||||
|
||||
//! Decompose a KeySym
|
||||
//! Decompose a KeySym using dead keys
|
||||
/*!
|
||||
Decomposes \c keysym into its component keysyms. All but the last
|
||||
decomposed KeySym are dead keys. Returns true iff the decomposition
|
||||
was successful.
|
||||
*/
|
||||
static bool decomposeKeySym(KeySym keysym, KeySyms& decomposed);
|
||||
static bool decomposeKeySymWithDeadKeys(KeySym keysym,
|
||||
KeySyms& decomposed);
|
||||
|
||||
//! Decompose a KeySym using the compose key
|
||||
/*!
|
||||
Decomposes \c keysym into its component keysyms. The first key is
|
||||
Multi_key and the rest are normal (i.e. not dead) keys. Returns
|
||||
true iff the decomposition was successful.
|
||||
*/
|
||||
static bool decomposeKeySymWithCompose(KeySym keysym,
|
||||
KeySyms& decomposed);
|
||||
|
||||
//! Convert Atom to its string
|
||||
/*!
|
||||
|
@ -162,7 +172,8 @@ private:
|
|||
|
||||
static CKeySymMap s_keySymToUCS4;
|
||||
static CUCS4Map s_UCS4ToKeySym;
|
||||
static CKeySymsMap s_decomposedKeySyms;
|
||||
static CKeySymsMap s_deadKeyDecomposedKeySyms;
|
||||
static CKeySymsMap s_composeDecomposedKeySyms;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue