00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <QX11Info>
00022 #include <kapplication.h>
00023 #include <kdebug.h>
00024
00025 #include "kmodifierkeyinfo.h"
00026 #include "kmodifierkeyinfoprovider_p.h"
00027
00028 #define XK_MISCELLANY
00029 #define XK_XKB_KEYS
00030 #include <X11/keysymdef.h>
00031
00032 struct ModifierDefinition
00033 {
00034 ModifierDefinition( Qt::Key _key, unsigned int _mask, const char * _name, KeySym _keysym ) {
00035 key = _key;
00036 mask = _mask;
00037 name = _name;
00038 keysym = _keysym;
00039 }
00040 Qt::Key key;
00041 unsigned int mask;
00042 const char *name;
00043 KeySym keysym;
00044 };
00045
00046
00047
00048
00049 unsigned int xkbVirtualModifier(XkbDescPtr xkb, const char *name)
00050 {
00051 Q_ASSERT(xkb != 0);
00052
00053 unsigned int mask = 0;
00054 bool nameEqual;
00055 for (int i = 0; i < XkbNumVirtualMods; ++i) {
00056 char *modStr = XGetAtomName(xkb->dpy, xkb->names->vmods[i]);
00057 if (modStr != 0) {
00058 nameEqual = (strcmp(name, modStr) == 0);
00059 XFree(modStr);
00060 if (nameEqual) {
00061 XkbVirtualModsToReal(xkb, 1 << i, &mask);
00062 break;
00063 }
00064 }
00065 }
00066 return mask;
00067 }
00068
00069 KModifierKeyInfoProvider::KModifierKeyInfoProvider()
00070 : QWidget(0)
00071 {
00072 int code, xkberr, maj, min;
00073 m_xkbAvailable = XkbQueryExtension(QX11Info::display(), &code, &m_xkbEv, &xkberr, &maj, &min);
00074 if (m_xkbAvailable) {
00075 XkbSelectEvents(QX11Info::display(), XkbUseCoreKbd,
00076 XkbStateNotifyMask | XkbMapNotifyMask,
00077 XkbStateNotifyMask | XkbMapNotifyMask);
00078 unsigned long int stateMask = XkbModifierStateMask | XkbModifierBaseMask |
00079 XkbModifierLatchMask | XkbModifierLockMask |
00080 XkbPointerButtonMask;
00081 XkbSelectEventDetails(QX11Info::display(), XkbUseCoreKbd, XkbStateNotifyMask,
00082 stateMask, stateMask);
00083 }
00084
00085 xkbUpdateModifierMapping();
00086
00087
00088 m_xkbButtons.insert(Qt::LeftButton, Button1Mask);
00089 m_xkbButtons.insert(Qt::MidButton, Button2Mask);
00090 m_xkbButtons.insert(Qt::RightButton, Button3Mask);
00091 m_xkbButtons.insert(Qt::XButton1, Button4Mask);
00092 m_xkbButtons.insert(Qt::XButton2, Button5Mask);
00093
00094
00095 if (m_xkbAvailable) {
00096 XkbStateRec state;
00097 XkbGetState(QX11Info::display(), XkbUseCoreKbd, &state);
00098 xkbModifierStateChanged(state.mods, state.latched_mods, state.locked_mods);
00099 xkbButtonStateChanged(state.ptr_buttons);
00100 }
00101
00102 if (KApplication::kApplication()) {
00103 KApplication::kApplication()->installX11EventFilter(this);
00104 } else {
00105 kDebug() << "KModifierKeyInfo can't be used without KApplication";
00106 }
00107 }
00108
00109 KModifierKeyInfoProvider::~KModifierKeyInfoProvider()
00110 {
00111 }
00112
00113 bool KModifierKeyInfoProvider::setKeyLatched(Qt::Key key, bool latched)
00114 {
00115 if (!m_xkbModifiers.contains(key)) return false;
00116
00117 return XkbLatchModifiers(QX11Info::display(), XkbUseCoreKbd,
00118 m_xkbModifiers[key], latched ? m_xkbModifiers[key] : 0);
00119 }
00120
00121 bool KModifierKeyInfoProvider::setKeyLocked(Qt::Key key, bool locked)
00122 {
00123 if (!m_xkbModifiers.contains(key)) return false;
00124
00125 return XkbLockModifiers(QX11Info::display(), XkbUseCoreKbd,
00126 m_xkbModifiers[key], locked ? m_xkbModifiers[key] : 0);
00127 }
00128
00129 bool KModifierKeyInfoProvider::x11Event(XEvent *event)
00130 {
00131 if (m_xkbAvailable) {
00132 XkbEvent *kbevt;
00133 unsigned int stateMask = XkbModifierStateMask | XkbModifierBaseMask |
00134 XkbModifierLatchMask | XkbModifierLockMask;
00135 if (event->type == m_xkbEv + XkbEventCode &&
00136 (kbevt = (XkbEvent*)event) != 0)
00137 {
00138 if (kbevt->any.xkb_type == XkbMapNotify) {
00139 xkbUpdateModifierMapping();
00140 } else if (kbevt->any.xkb_type == XkbStateNotify) {
00141 XkbStateNotifyEvent *snevent = (XkbStateNotifyEvent*)event;
00142 if (snevent->changed & stateMask) {
00143 xkbModifierStateChanged(snevent->mods, snevent->latched_mods,
00144 snevent->locked_mods);
00145 } else if (snevent->changed & XkbPointerButtonMask) {
00146 xkbButtonStateChanged(snevent->ptr_buttons);
00147 }
00148 }
00149 return false;
00150 }
00151 }
00152
00153 return false;
00154 }
00155
00156 void KModifierKeyInfoProvider::xkbModifierStateChanged(unsigned char mods,
00157 unsigned char latched_mods,
00158 unsigned char locked_mods)
00159 {
00160
00161 ModifierStates oldState;
00162 ModifierStates newState;
00163
00164 QHash<Qt::Key, unsigned int>::const_iterator it;
00165 QHash<Qt::Key, unsigned int>::const_iterator end = m_xkbModifiers.constEnd();
00166 for (it = m_xkbModifiers.constBegin(); it != end; ++it) {
00167 if (!m_modifierStates.contains(it.key())) continue;
00168 newState = Nothing;
00169 oldState = m_modifierStates[it.key()];
00170
00171
00172 if (mods & it.value()) {
00173 newState |= Pressed;
00174 }
00175 if (latched_mods & it.value()) {
00176 newState |= Latched;
00177 }
00178 if (locked_mods & it.value()) {
00179 newState |= Locked;
00180 }
00181
00182 if (newState != oldState) {
00183 m_modifierStates[it.key()] = newState;
00184
00185 if ((newState ^ oldState) & Pressed) {
00186 emit keyPressed(it.key(), newState & Pressed);
00187 }
00188 if ((newState ^ oldState) & Latched) {
00189 emit keyLatched(it.key(), newState & Latched);
00190 }
00191 if ((newState ^ oldState) & Locked) {
00192 emit keyLocked(it.key(), newState & Locked);
00193 }
00194 }
00195 }
00196 }
00197
00198 void KModifierKeyInfoProvider::xkbButtonStateChanged(unsigned short ptr_buttons)
00199 {
00200
00201 bool newButtonState;
00202
00203 QHash<Qt::MouseButton, unsigned short>::const_iterator it;
00204 QHash<Qt::MouseButton, unsigned short>::const_iterator end = m_xkbButtons.constEnd();
00205 for (it = m_xkbButtons.constBegin(); it != end; ++it) {
00206 newButtonState = (ptr_buttons & it.value());
00207 if (newButtonState != m_buttonStates[it.key()]) {
00208 m_buttonStates[it.key()] = newButtonState;
00209 emit buttonPressed(it.key(), newButtonState);
00210 }
00211 }
00212 }
00213
00214 void KModifierKeyInfoProvider::xkbUpdateModifierMapping()
00215 {
00216 m_xkbModifiers.clear();
00217
00218 QList<ModifierDefinition> srcModifiers;
00219 srcModifiers << ModifierDefinition(Qt::Key_Shift, ShiftMask, 0, 0)
00220 << ModifierDefinition( Qt::Key_Control, ControlMask, 0, 0)
00221 << ModifierDefinition(Qt::Key_Alt, 0, "Alt", XK_Alt_L)
00222
00223 << ModifierDefinition(Qt::Key_Meta, 0, "Meta", XK_Meta_L)
00224 << ModifierDefinition(Qt::Key_Super_L, 0, "Super", XK_Super_L)
00225 << ModifierDefinition(Qt::Key_Hyper_L, 0, "Hyper", XK_Hyper_L)
00226 << ModifierDefinition(Qt::Key_AltGr, 0, "AltGr", 0)
00227 << ModifierDefinition(Qt::Key_NumLock, 0, "NumLock", XK_Num_Lock)
00228 << ModifierDefinition(Qt::Key_CapsLock, LockMask, 0, 0)
00229 << ModifierDefinition( Qt::Key_ScrollLock, 0, "ScrollLock", XK_Scroll_Lock);
00230
00231 XkbDescPtr xkb = XkbGetKeyboard(QX11Info::display(), XkbAllComponentsMask, XkbUseCoreKbd);
00232
00233 QList<ModifierDefinition>::const_iterator it;
00234 QList<ModifierDefinition>::const_iterator end = srcModifiers.constEnd();
00235 for (it = srcModifiers.constBegin(); it != end; ++it) {
00236 unsigned int mask = it->mask;
00237 if (mask == 0 && xkb != 0) {
00238
00239 if (it->name != 0) {
00240 mask = xkbVirtualModifier(xkb, it->name);
00241 }
00242 if (mask == 0 && it->keysym != 0) {
00243 mask = XkbKeysymToModifiers(QX11Info::display(), it->keysym);
00244 } else if (mask == 0) {
00245
00246 mask = XkbKeysymToModifiers(QX11Info::display(), XK_Mode_switch) |
00247 XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Shift) |
00248 XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Latch) |
00249 XkbKeysymToModifiers(QX11Info::display(), XK_ISO_Level3_Lock);
00250 }
00251 }
00252
00253 if (mask != 0) {
00254 m_xkbModifiers.insert(it->key, mask);
00255
00256 if (!m_modifierStates.contains(it->key)) {
00257 m_modifierStates.insert(it->key, Nothing);
00258 emit keyAdded(it->key);
00259 }
00260 }
00261 }
00262
00263
00264 QMutableHashIterator<Qt::Key, ModifierStates> i(m_modifierStates);
00265 while (i.hasNext()) {
00266 i.next();
00267 if (!m_xkbModifiers.contains(i.key())) {
00268 Qt::Key key = i.key();
00269 i.remove();
00270 emit keyRemoved(key);
00271 }
00272 }
00273
00274 if (xkb != 0) {
00275 XkbFreeKeyboard(xkb, 0, true);
00276 }
00277 }