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:
crs 2004-11-04 21:26:43 +00:00
parent 4be95841d2
commit bdd3635f4b
6 changed files with 285 additions and 58 deletions

View File

@ -281,60 +281,41 @@ CXWindowsKeyState::mapKey(Keystrokes& keys, KeyID id,
if (keyIndex != m_keysymMap.end()) { if (keyIndex != m_keysymMap.end()) {
// the keysym is mapped to some keycode. create the keystrokes // the keysym is mapped to some keycode. create the keystrokes
// for this keysym. // 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 // we can't find the keysym mapped to any keycode. this doesn't
// necessarily mean we can't generate the keysym, though. if the // necessarily mean we can't generate the keysym, though. if the
// keysym can be created by combining keysyms then we may still // keysym can be created by combining keysyms then we may still
// be okay. // be okay.
CXWindowsUtil::KeySyms decomposition; if (!isAutoRepeat) {
if (CXWindowsUtil::decomposeKeySym(keysym, decomposition)) { KeyButton keycode = mapDecompositionToKeystrokes(keys, keysym, true);
LOG((CLOG_DEBUG2 "decomposed keysym 0x%08x into %d keysyms", keysym, decomposition.size())); if (keycode != 0) {
return keycode;
// map each decomposed keysym to keystrokes. we want the mask }
// and the keycode from the last keysym (which should be the keycode = mapDecompositionToKeystrokes(keys, keysym, false);
// only non-dead key). the dead keys are not sensitive to if (keycode != 0) {
// anything but shift and mode switch. // no key is left synthetically down when using the compose key
KeyButton keycode = 0; // so return 0 even though we succeeded.
for (CXWindowsUtil::KeySyms::const_iterator i = decomposition.begin(); return 0;
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 keysym is caps lock sensitive then convert the case of
// then convert the case of the keysym and try again. // the keysym and try again.
if (keyIndex == m_keysymMap.end()) { KeySym lKey, uKey;
KeySym lKey, uKey; XConvertCase(keysym, &lKey, &uKey);
XConvertCase(keysym, &lKey, &uKey); if (lKey != uKey) {
if (lKey != uKey) { if (lKey == keysym) {
if (lKey == keysym) { keyIndex = m_keysymMap.find(uKey);
keyIndex = m_keysymMap.find(uKey); }
} else {
else { keyIndex = m_keysymMap.find(lKey);
keyIndex = m_keysymMap.find(lKey);
}
} }
if (keyIndex != m_keysymMap.end()) { if (keyIndex != m_keysymMap.end()) {
// the keysym is mapped to some keycode. create the keystrokes // the keysym is mapped to some keycode. create the keystrokes
// for this keysym. // 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 KeyButton
CXWindowsKeyState::mapToKeystrokes(Keystrokes& keys, CXWindowsKeyState::mapToKeystrokes(Keystrokes& keys,
KeySymIndex keyIndex, bool isAutoRepeat) const KeySymIndex keyIndex, bool isAutoRepeat,
bool pressAndRelease) const
{ {
// keyIndex must be valid // keyIndex must be valid
assert(keyIndex != m_keysymMap.end()); assert(keyIndex != m_keysymMap.end());
@ -873,7 +855,14 @@ CXWindowsKeyState::mapToKeystrokes(Keystrokes& keys,
// add the key event // add the key event
Keystroke keystroke; Keystroke keystroke;
keystroke.m_key = keycode; 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_press = true;
keystroke.m_repeat = false; keystroke.m_repeat = false;
keys.push_back(keystroke); keys.push_back(keystroke);
@ -895,6 +884,60 @@ CXWindowsKeyState::mapToKeystrokes(Keystrokes& keys,
return keycode; 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 unsigned int
CXWindowsKeyState::findBestKeyIndex(KeySymIndex keyIndex, CXWindowsKeyState::findBestKeyIndex(KeySymIndex keyIndex,
KeyModifierMask /*currentMask*/) const KeyModifierMask /*currentMask*/) const

View File

@ -100,7 +100,13 @@ private:
// map a KeySym into the keystrokes to produce it // map a KeySym into the keystrokes to produce it
KeyButton mapToKeystrokes(Keystrokes& keys, KeyButton mapToKeystrokes(Keystrokes& keys,
KeySymIndex keyIndex, 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 // choose the best set of modifiers to generate the KeySym
unsigned int findBestKeyIndex(KeySymIndex keyIndex, unsigned int findBestKeyIndex(KeySymIndex keyIndex,

View File

@ -334,6 +334,7 @@ CXWindowsScreen::leave()
if (m_ic != NULL) { if (m_ic != NULL) {
XmbResetIC(m_ic); XmbResetIC(m_ic);
XSetICFocus(m_ic); XSetICFocus(m_ic);
m_filtered.clear();
} }
// now off screen // now off screen
@ -876,6 +877,18 @@ CXWindowsScreen::handleSystemEvent(const CEvent& event, void*)
// now filter the event // now filter the event
if (XFilterEvent(xevent, None)) { 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; return;
} }
} }
@ -1030,14 +1043,26 @@ CXWindowsScreen::onKeyPress(XKeyEvent& xkey)
// get which button. see call to XFilterEvent() in onEvent() // get which button. see call to XFilterEvent() in onEvent()
// for more info. // for more info.
bool isFake = false;
KeyButton keycode = static_cast<KeyButton>(xkey.keycode); KeyButton keycode = static_cast<KeyButton>(xkey.keycode);
if (keycode == 0) { if (keycode == 0) {
isFake = true;
keycode = static_cast<KeyButton>(m_lastKeycode); keycode = static_cast<KeyButton>(m_lastKeycode);
if (keycode == 0) {
// no keycode
return;
}
} }
// handle key // handle key
m_keyState->sendKeyEvent(getEventTarget(), m_keyState->sendKeyEvent(getEventTarget(),
true, false, key, mask, 1, keycode); 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);
}
} }
} }

View File

@ -16,6 +16,7 @@
#define CXWINDOWSSCREEN_H #define CXWINDOWSSCREEN_H
#include "CPlatformScreen.h" #include "CPlatformScreen.h"
#include "stdset.h"
#include "stdvector.h" #include "stdvector.h"
#if X_DISPLAY_MISSING #if X_DISPLAY_MISSING
# error X11 is required to build synergy # error X11 is required to build synergy
@ -135,6 +136,7 @@ private:
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg); static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
private: private:
typedef std::set<bool> CFilteredKeycodes;
// true if screen is being used as a primary screen, false otherwise // true if screen is being used as a primary screen, false otherwise
bool m_isPrimary; bool m_isPrimary;
@ -164,6 +166,7 @@ private:
XIM m_im; XIM m_im;
XIC m_ic; XIC m_ic;
KeyCode m_lastKeycode; KeyCode m_lastKeycode;
CFilteredKeycodes m_filtered;
// clipboards // clipboards
CXWindowsClipboard* m_clipboard[kClipboardEnd]; CXWindowsClipboard* m_clipboard[kClipboardEnd];

View File

@ -17,6 +17,7 @@
#include "CLog.h" #include "CLog.h"
#include "CStringUtil.h" #include "CStringUtil.h"
#include <X11/Xatom.h> #include <X11/Xatom.h>
#define XK_MISCELLANY
#define XK_XKB_KEYS #define XK_XKB_KEYS
#define XK_LATIN1 #define XK_LATIN1
#define XK_LATIN2 #define XK_LATIN2
@ -814,7 +815,7 @@ struct codepair {
{ 0x20ac, 0x20ac } /* EuroSign EURO SIGN */ { 0x20ac, 0x20ac } /* EuroSign EURO SIGN */
}; };
static const KeySym s_rawDecomposeTable[] = { static const KeySym s_rawDeadDecomposeTable[] = {
// non-dead version of dead keys // non-dead version of dead keys
XK_grave, XK_dead_grave, XK_space, 0, XK_grave, XK_dead_grave, XK_space, 0,
XK_acute, XK_dead_acute, XK_space, 0, XK_acute, XK_dead_acute, XK_space, 0,
@ -1026,6 +1027,116 @@ static const KeySym s_rawDecomposeTable[] = {
0 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 // CXWindowsUtil
@ -1033,7 +1144,8 @@ static const KeySym s_rawDecomposeTable[] = {
CXWindowsUtil::CKeySymMap CXWindowsUtil::s_keySymToUCS4; CXWindowsUtil::CKeySymMap CXWindowsUtil::s_keySymToUCS4;
CXWindowsUtil::CUCS4Map CXWindowsUtil::s_UCS4ToKeySym; CXWindowsUtil::CUCS4Map CXWindowsUtil::s_UCS4ToKeySym;
CXWindowsUtil::CKeySymsMap CXWindowsUtil::s_decomposedKeySyms; CXWindowsUtil::CKeySymsMap CXWindowsUtil::s_deadKeyDecomposedKeySyms;
CXWindowsUtil::CKeySymsMap CXWindowsUtil::s_composeDecomposedKeySyms;
bool bool
CXWindowsUtil::getWindowProperty(Display* display, Window window, CXWindowsUtil::getWindowProperty(Display* display, Window window,
@ -1231,18 +1343,33 @@ CXWindowsUtil::mapUCS4ToKeySym(UInt32 c)
} }
bool bool
CXWindowsUtil::decomposeKeySym(KeySym keysym, KeySyms& decomposed) CXWindowsUtil::decomposeKeySymWithDeadKeys(KeySym keysym, KeySyms& decomposed)
{ {
// unfortunately, X11 doesn't appear to have any way of // unfortunately, X11 doesn't appear to have any way of
// decomposing a keysym into its component keysyms. we'll // decomposing a keysym into its component keysyms. we'll
// use a lookup table for certain character sets. // use a lookup table for certain character sets.
initKeyMaps(); initKeyMaps();
CKeySymsMap::const_iterator i = s_decomposedKeySyms.find(keysym); CKeySymsMap::const_iterator i = s_deadKeyDecomposedKeySyms.find(keysym);
if (i == s_decomposedKeySyms.end()) { if (i != s_deadKeyDecomposedKeySyms.end()) {
return false; decomposed = i->second;
return true;
} }
decomposed = i->second; return false;
return true; }
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 CString
@ -1296,10 +1423,22 @@ CXWindowsUtil::initKeyMaps()
} }
// fill decomposed key table if not filled yet // fill decomposed key table if not filled yet
if (s_decomposedKeySyms.empty()) { if (s_deadKeyDecomposedKeySyms.empty()) {
for (const KeySym* scan = s_rawDecomposeTable; *scan != 0; ++scan) { for (const KeySym* scan = s_rawDeadDecomposeTable; *scan != 0; ++scan) {
// add an entry for this keysym // 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 // add the decomposed keysyms for the keysym
while (*++scan != 0) { while (*++scan != 0) {

View File

@ -73,13 +73,23 @@ public:
*/ */
static KeySym mapUCS4ToKeySym(UInt32); static KeySym mapUCS4ToKeySym(UInt32);
//! Decompose a KeySym //! Decompose a KeySym using dead keys
/*! /*!
Decomposes \c keysym into its component keysyms. All but the last Decomposes \c keysym into its component keysyms. All but the last
decomposed KeySym are dead keys. Returns true iff the decomposition decomposed KeySym are dead keys. Returns true iff the decomposition
was successful. 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 //! Convert Atom to its string
/*! /*!
@ -162,7 +172,8 @@ private:
static CKeySymMap s_keySymToUCS4; static CKeySymMap s_keySymToUCS4;
static CUCS4Map s_UCS4ToKeySym; static CUCS4Map s_UCS4ToKeySym;
static CKeySymsMap s_decomposedKeySyms; static CKeySymsMap s_deadKeyDecomposedKeySyms;
static CKeySymsMap s_composeDecomposedKeySyms;
}; };
#endif #endif