/**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this ** file. Please review the following information to ensure the GNU Lesser ** General Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qkeymapper_p.h" #include "qdebug.h" #include "qtextcodec.h" #include "qwidget.h" #include "qapplication_p.h" #include "qevent_p.h" #include "qt_x11_p.h" #ifndef QT_NO_XKB # include #endif #define XK_MISCELLANY #define XK_LATIN1 #define XK_KOREAN #define XK_XKB_KEYS #include #include #ifdef QT_LINUXBASE // LSB's IsKeypadKey define is wrong - see // http://bugs.linuxbase.org/show_bug.cgi?id=2521 #undef IsKeypadKey #define IsKeypadKey(keysym) \ (((KeySym)(keysym) >= XK_KP_Space) && ((KeySym)(keysym) <= XK_KP_Equal)) #undef IsPrivateKeypadKey #define IsPrivateKeypadKey(keysym) \ (((KeySym)(keysym) >= 0x11000000) && ((KeySym)(keysym) <= 0x1100FFFF)) #endif QT_BEGIN_NAMESPACE #ifndef QT_NO_XKB // bring in the auto-generated xkbLayoutData #include "qkeymapper_x11_p.cpp" QLocale q_getKeyboardLocale(const QByteArray &layoutName, const QByteArray &variantName) { int i = 0; while (xkbLayoutData[i].layout != 0) { if (layoutName == xkbLayoutData[i].layout && variantName == xkbLayoutData[i].variant) return QLocale(xkbLayoutData[i].language, xkbLayoutData[i].country); ++i; } return QLocale::c(); } #endif // QT_NO_XKB // from qapplication_x11.cpp extern uchar qt_alt_mask; extern uchar qt_meta_mask; extern uchar qt_super_mask; extern uchar qt_hyper_mask; extern uchar qt_mode_switch_mask; uchar qt_num_lock_mask = 0; extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); // ### we should really resolve conflicts with other masks by // ### decomposing the Qt::KeyboardModifers in possibleKeys() #define SETMASK(sym, mask) \ do { \ if (qt_alt_mask == 0 \ && qt_meta_mask != mask \ && qt_super_mask != mask \ && qt_hyper_mask != mask \ && (sym == XK_Alt_L || sym == XK_Alt_R)) { \ qt_alt_mask = mask; \ } \ if (qt_meta_mask == 0 \ && qt_alt_mask != mask \ && qt_super_mask != mask \ && qt_hyper_mask != mask \ && (sym == XK_Meta_L || sym == XK_Meta_R)) { \ qt_meta_mask = mask; \ } \ if (qt_super_mask == 0 \ && qt_alt_mask != mask \ && qt_meta_mask != mask \ && qt_hyper_mask != mask \ && (sym == XK_Super_L || sym == XK_Super_R)) { \ qt_super_mask = mask; \ } \ if (qt_hyper_mask == 0 \ && qt_alt_mask != mask \ && qt_meta_mask != mask \ && qt_super_mask != mask \ && (sym == XK_Hyper_L || sym == XK_Hyper_R)) { \ qt_hyper_mask = mask; \ } \ if (qt_mode_switch_mask == 0 \ && qt_alt_mask != mask \ && qt_meta_mask != mask \ && qt_super_mask != mask \ && qt_hyper_mask != mask \ && sym == XK_Mode_switch) { \ qt_mode_switch_mask = mask; \ } \ if (qt_num_lock_mask == 0 \ && sym == XK_Num_Lock) { \ qt_num_lock_mask = mask; \ } \ } while(false) // qt_XTranslateKey() is based on _XTranslateKey() taken from: /* $Xorg: KeyBind.c,v 1.4 2001/02/09 02:03:34 xorgcvs Exp $ */ /* Copyright 1985, 1987, 1998 The Open Group Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of The Open Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group. */ static int qt_XTranslateKey(register QXCoreDesc *dpy, KeyCode keycode, register unsigned int modifiers, unsigned int *modifiers_return, KeySym *keysym_return) { int per; register KeySym *syms; KeySym sym, lsym, usym; if (! dpy->keysyms) return 0; *modifiers_return = ((ShiftMask|LockMask) | dpy->mode_switch | dpy->num_lock); if (((int)keycode < dpy->min_keycode) || ((int)keycode > dpy->max_keycode)) { *keysym_return = NoSymbol; return 1; } per = dpy->keysyms_per_keycode; syms = &dpy->keysyms[(keycode - dpy->min_keycode) * per]; while ((per > 2) && (syms[per - 1] == NoSymbol)) per--; if ((per > 2) && (modifiers & dpy->mode_switch)) { syms += 2; per -= 2; } if ((modifiers & dpy->num_lock) && (per > 1 && (IsKeypadKey(syms[1]) || IsPrivateKeypadKey(syms[1])))) { if ((modifiers & ShiftMask) || ((modifiers & LockMask) && (dpy->lock_meaning == XK_Shift_Lock))) *keysym_return = syms[0]; else *keysym_return = syms[1]; } else if (!(modifiers & ShiftMask) && (!(modifiers & LockMask) || (dpy->lock_meaning == NoSymbol))) { if ((per == 1) || (syms[1] == NoSymbol)) XConvertCase(syms[0], keysym_return, &usym); else *keysym_return = syms[0]; } else if (!(modifiers & LockMask) || (dpy->lock_meaning != XK_Caps_Lock)) { if ((per == 1) || ((usym = syms[1]) == NoSymbol)) XConvertCase(syms[0], &lsym, &usym); *keysym_return = usym; } else { if ((per == 1) || ((sym = syms[1]) == NoSymbol)) sym = syms[0]; XConvertCase(sym, &lsym, &usym); if (!(modifiers & ShiftMask) && (sym != syms[0]) && ((sym != usym) || (lsym == usym))) XConvertCase(syms[0], &lsym, &usym); *keysym_return = usym; } if (*keysym_return == XK_VoidSymbol) *keysym_return = NoSymbol; return 1; } QKeyMapperPrivate::QKeyMapperPrivate() : keyboardInputDirection(Qt::LeftToRight), xkb_currentGroup(0) { memset(&coreDesc, 0, sizeof(coreDesc)); #ifndef QT_NO_XKB if (X11->use_xkb) { // get the current group XkbStateRec xkbState; if (XkbGetState(X11->display, XkbUseCoreKbd, &xkbState) == Success) xkb_currentGroup = xkbState.group; } #endif } QKeyMapperPrivate::~QKeyMapperPrivate() { if (coreDesc.keysyms) XFree(coreDesc.keysyms); } QList QKeyMapperPrivate::possibleKeys(QKeyEvent *event) { #ifndef QT_NO_XKB if (X11->use_xkb) return possibleKeysXKB(event); #endif return possibleKeysCore(event); } enum { MaxBits = sizeof(uint) * 8 }; static QString translateKeySym(KeySym keysym, uint xmodifiers, int &code, Qt::KeyboardModifiers &modifiers, QByteArray &chars, int &count); QList QKeyMapperPrivate::possibleKeysXKB(QKeyEvent *event) { #ifndef QT_NO_XKB const int xkeycode = event->nativeScanCode(); const uint xmodifiers = event->nativeModifiers(); // first, translate key only using lock modifiers (there are no Qt equivalents for these, so we must // always use them when determining the baseKeySym) KeySym baseKeySym; uint consumedModifiers; if (!XkbLookupKeySym(X11->display, xkeycode, (xmodifiers & (LockMask | qt_num_lock_mask)), &consumedModifiers, &baseKeySym)) return QList(); QList result; // translate sym -> code Qt::KeyboardModifiers baseModifiers = 0; int baseCode = -1; QByteArray chars; int count = 0; QString text = translateKeySym(baseKeySym, xmodifiers, baseCode, baseModifiers, chars, count); if (baseCode == -1) { if (text.isEmpty()) return QList(); baseCode = text.at(0).unicode(); } if (baseCode && baseCode < 0xfffe) baseCode = QChar(baseCode).toUpper().unicode(); result += (baseCode | baseModifiers); int pos1Bits[MaxBits]; int num1Bits = 0; for (int i = 0; i < MaxBits; ++i) { if (consumedModifiers & (1 << i)) pos1Bits[num1Bits++] = i; } const int numPerms = (1 << num1Bits); // translate the key again using each permutation of consumedModifiers for (int i = 1; i < numPerms; ++i) { uint val = 0; for (int j = 0; j < num1Bits; ++j) { if (i & (1 << j)) val |= (1 << pos1Bits[j]); } if ((xmodifiers & val) != val) continue; KeySym sym; uint mods; if (!XkbLookupKeySym(X11->display, xkeycode, val, &mods, &sym)) continue; // translate sym -> code Qt::KeyboardModifiers modifiers = 0; int code = -1; chars.clear(); count = 0; // mask out the modifiers needed to translate keycode text = translateKeySym(sym, xmodifiers & ~val, code, modifiers, chars, count); if (code == -1) { if (text.isEmpty()) continue; code = text.at(0).unicode(); } if (code && code < 0xfffe) code = QChar(code).toUpper().unicode(); if (code == Qt::Key_Tab && (baseModifiers & Qt::ShiftModifier)) { // map shift+tab to shift+backtab code = Qt::Key_Backtab; text = QString(); } if (code == baseCode) continue; result += (code | modifiers); } #if 0 qDebug() << "possibleKeysXKB()" << hex << result; #endif return result; #else Q_UNUSED(event); return QList(); #endif // QT_NO_XKB } QList QKeyMapperPrivate::possibleKeysCore(QKeyEvent *event) { const int xkeycode = event->nativeScanCode(); const uint xmodifiers = event->nativeModifiers(); // first, translate key only using lock modifiers (there are no Qt equivalents for these, so we must // always use them when determining the baseKeySym) KeySym baseKeySym; uint consumedModifiers; if (!qt_XTranslateKey(&coreDesc, xkeycode, (xmodifiers & (LockMask | qt_num_lock_mask)), &consumedModifiers, &baseKeySym)) return QList(); QList result; // translate sym -> code Qt::KeyboardModifiers baseModifiers = 0; int baseCode = -1; QByteArray chars; int count = 0; QString text = translateKeySym(baseKeySym, xmodifiers, baseCode, baseModifiers, chars, count); if (baseCode == -1) { if (text.isEmpty()) return QList(); baseCode = text.at(0).unicode(); } if (baseCode && baseCode < 0xfffe) baseCode = QChar(baseCode).toUpper().unicode(); result += (baseCode | baseModifiers); int pos1Bits[MaxBits]; int num1Bits = 0; for (int i = 0; i < MaxBits; ++i) { if (consumedModifiers & (1 << i)) pos1Bits[num1Bits++] = i; } const int numPerms = (1 << num1Bits); // translate the key again using each permutation of consumedModifiers for (int i = 1; i < numPerms; ++i) { uint val = 0; for (int j = 0; j < num1Bits; ++j) { if (i & (1 << j)) val |= (1 << pos1Bits[j]); } if ((xmodifiers & val) != val) continue; KeySym sym; uint mods; if (!qt_XTranslateKey(&coreDesc, xkeycode, val, &mods, &sym)) continue; // translate sym -> code Qt::KeyboardModifiers modifiers = 0; int code = -1; chars.clear(); count = 0; // mask out the modifiers needed to translate keycode text = translateKeySym(sym, xmodifiers & ~val, code, modifiers, chars, count); if (code == -1) { if (text.isEmpty()) continue; code = text.at(0).unicode(); } if (code && code < 0xfffe) code = QChar(code).toUpper().unicode(); if (code == Qt::Key_Tab && (baseModifiers & Qt::ShiftModifier)) { // map shift+tab to shift+backtab code = Qt::Key_Backtab; text = QString(); } if (code == baseCode) continue; result += (code | modifiers); } #if 0 qDebug() << "possibleKeysCore()" << hex << result; #endif return result; } // for parsing the _XKB_RULES_NAMES property enum { RulesFileIndex = 0, ModelIndex = 1, LayoutIndex = 2, VariantIndex = 3, OptionsIndex = 4 }; void QKeyMapperPrivate::clearMappings() { #ifndef QT_NO_XKB if (X11->use_xkb) { // try to determine the layout name and input direction by reading the _XKB_RULES_NAMES property off // the root window QByteArray layoutName; QByteArray variantName; Atom type = XNone; int format = 0; ulong nitems = 0; ulong bytesAfter = 0; uchar *data = 0; if (XGetWindowProperty(X11->display, RootWindow(X11->display, 0), ATOM(_XKB_RULES_NAMES), 0, 1024, false, XA_STRING, &type, &format, &nitems, &bytesAfter, &data) == Success && type == XA_STRING && format == 8 && nitems > 2) { /* index 0 == rules file name index 1 == model name index 2 == layout name index 3 == variant name index 4 == options */ char *names[5] = { 0, 0, 0, 0, 0 }; char *p = reinterpret_cast(data), *end = p + nitems; int i = 0; do { names[i++] = p; p += qstrlen(p) + 1; } while (p < end); // the layout names and variants are saved in the _XKB_RULES_NAMES property as a comma separated list QList layoutNames = QByteArray::fromRawData(names[2], qstrlen(names[2])).split(','); if (uint(xkb_currentGroup) < uint(layoutNames.count())) layoutName = layoutNames.at(xkb_currentGroup); QList variantNames = QByteArray::fromRawData(names[3], qstrlen(names[3])).split(','); if (uint(xkb_currentGroup) < uint(variantNames.count())) variantName = variantNames.at(xkb_currentGroup); } // ### ??? // if (keyboardLayoutName.isEmpty()) // qWarning("Qt: unable to determine keyboard layout, please talk to qt-info@nokia.com"); ? keyboardInputLocale = q_getKeyboardLocale(layoutName, variantName); keyboardInputDirection = keyboardInputLocale.textDirection(); #if 0 qDebug() << "keyboard input locale =" << keyboardInputLocale.name() << "direction =" << keyboardInputDirection; #endif if (data) XFree(data); } else #endif // QT_NO_XKB { if (coreDesc.keysyms) XFree(coreDesc.keysyms); coreDesc.min_keycode = 8; coreDesc.max_keycode = 255; XDisplayKeycodes(X11->display, &coreDesc.min_keycode, &coreDesc.max_keycode); coreDesc.keysyms_per_keycode = 0; coreDesc.keysyms = XGetKeyboardMapping(X11->display, coreDesc.min_keycode, coreDesc.max_keycode - coreDesc.min_keycode + 1, &coreDesc.keysyms_per_keycode); #if 0 qDebug() << "min_keycode =" << coreDesc.min_keycode; qDebug() << "max_keycode =" << coreDesc.max_keycode; qDebug() << "keysyms_per_keycode =" << coreDesc.keysyms_per_keycode; qDebug() << "keysyms =" << coreDesc.keysyms; #endif // ### cannot get/guess the locale with the core protocol keyboardInputLocale = QLocale::c(); // ### could examine group 0 for RTL keys keyboardInputDirection = Qt::LeftToRight; } qt_alt_mask = 0; qt_meta_mask = 0; qt_super_mask = 0; qt_hyper_mask = 0; qt_mode_switch_mask = 0; // look at the modifier mapping, and get the correct masks for alt, meta, super, hyper, and mode_switch #ifndef QT_NO_XKB if (X11->use_xkb) { XkbDescPtr xkbDesc = XkbGetMap(X11->display, XkbAllClientInfoMask, XkbUseCoreKbd); for (int i = xkbDesc->min_key_code; i < xkbDesc->max_key_code; ++i) { const uint mask = xkbDesc->map->modmap ? xkbDesc->map->modmap[i] : 0; if (mask == 0) { // key is not bound to a modifier continue; } for (int j = 0; j < XkbKeyGroupsWidth(xkbDesc, i); ++j) { KeySym keySym = XkbKeySym(xkbDesc, i, j); if (keySym == NoSymbol) continue; SETMASK(keySym, mask); } } XkbFreeKeyboard(xkbDesc, XkbAllComponentsMask, true); } else #endif // QT_NO_XKB { coreDesc.lock_meaning = NoSymbol; XModifierKeymap *map = XGetModifierMapping(X11->display); if (map) { int i, maskIndex = 0, mapIndex = 0; for (maskIndex = 0; maskIndex < 8; maskIndex++) { for (i = 0; i < map->max_keypermod; i++) { if (map->modifiermap[mapIndex]) { KeySym sym; int x = 0; do { sym = XKeycodeToKeysym(X11->display, map->modifiermap[mapIndex], x++); } while (sym == NoSymbol && x < coreDesc.keysyms_per_keycode); const uchar mask = 1 << maskIndex; SETMASK(sym, mask); } mapIndex++; } } // determine the meaning of the Lock modifier for (i = 0; i < map->max_keypermod; ++i) { for (int x = 0; x < coreDesc.keysyms_per_keycode; ++x) { KeySym sym = XKeycodeToKeysym(X11->display, map->modifiermap[LockMapIndex], x); if (sym == XK_Caps_Lock || sym == XK_ISO_Lock) { coreDesc.lock_meaning = XK_Caps_Lock; break; } else if (sym == XK_Shift_Lock) { coreDesc.lock_meaning = XK_Shift_Lock; } } } XFreeModifiermap(map); } // for qt_XTranslateKey() coreDesc.num_lock = qt_num_lock_mask; coreDesc.mode_switch = qt_mode_switch_mask; #if 0 qDebug() << "lock_meaning =" << coreDesc.lock_meaning; qDebug() << "num_lock =" << coreDesc.num_lock; qDebug() << "mode_switch =" << coreDesc.mode_switch; #endif } // set default modifier masks if needed if( qt_alt_mask == 0 ) qt_alt_mask = Mod1Mask; if( qt_meta_mask == 0 ) qt_meta_mask = Mod4Mask; // if we don't have a meta key (or it's hidden behind alt), use super or hyper to generate // Qt::Key_Meta and Qt::MetaModifier, since most newer XFree86/Xorg installations map the Windows // key to Super if (qt_meta_mask == 0 || qt_meta_mask == qt_alt_mask) { // no meta keys... s,meta,super, qt_meta_mask = qt_super_mask; if (qt_meta_mask == 0 || qt_meta_mask == qt_alt_mask) { // no super keys either? guess we'll use hyper then qt_meta_mask = qt_hyper_mask; } } #if 0 qDebug() << "qt_alt_mask =" << hex << qt_alt_mask; qDebug() << "qt_meta_mask =" << hex << qt_meta_mask; qDebug() << "qt_super_mask =" << hex << qt_super_mask; qDebug() << "qt_hyper_mask =" << hex << qt_hyper_mask; qDebug() << "qt_mode_switch_mask =" << hex << qt_mode_switch_mask; qDebug() << "qt_num_lock_mask =" << hex << qt_num_lock_mask; #endif } extern bool qt_sm_blockUserInput; // // Keyboard event translation // #ifndef XK_ISO_Left_Tab #define XK_ISO_Left_Tab 0xFE20 #endif #ifndef XK_dead_hook #define XK_dead_hook 0xFE61 #endif #ifndef XK_dead_horn #define XK_dead_horn 0xFE62 #endif #ifndef XK_Codeinput #define XK_Codeinput 0xFF37 #endif #ifndef XK_Kanji_Bangou #define XK_Kanji_Bangou 0xFF37 /* same as codeinput */ #endif // Fix old X libraries #ifndef XK_KP_Home #define XK_KP_Home 0xFF95 #endif #ifndef XK_KP_Left #define XK_KP_Left 0xFF96 #endif #ifndef XK_KP_Up #define XK_KP_Up 0xFF97 #endif #ifndef XK_KP_Right #define XK_KP_Right 0xFF98 #endif #ifndef XK_KP_Down #define XK_KP_Down 0xFF99 #endif #ifndef XK_KP_Prior #define XK_KP_Prior 0xFF9A #endif #ifndef XK_KP_Next #define XK_KP_Next 0xFF9B #endif #ifndef XK_KP_End #define XK_KP_End 0xFF9C #endif #ifndef XK_KP_Insert #define XK_KP_Insert 0xFF9E #endif #ifndef XK_KP_Delete #define XK_KP_Delete 0xFF9F #endif // the next lines are taken on 10/2009 from X.org (X11/XF86keysym.h), defining some special // multimedia keys. They are included here as not every system has them. #define XF86XK_MonBrightnessUp 0x1008FF02 #define XF86XK_MonBrightnessDown 0x1008FF03 #define XF86XK_KbdLightOnOff 0x1008FF04 #define XF86XK_KbdBrightnessUp 0x1008FF05 #define XF86XK_KbdBrightnessDown 0x1008FF06 #define XF86XK_Standby 0x1008FF10 #define XF86XK_AudioLowerVolume 0x1008FF11 #define XF86XK_AudioMute 0x1008FF12 #define XF86XK_AudioRaiseVolume 0x1008FF13 #define XF86XK_AudioPlay 0x1008FF14 #define XF86XK_AudioStop 0x1008FF15 #define XF86XK_AudioPrev 0x1008FF16 #define XF86XK_AudioNext 0x1008FF17 #define XF86XK_HomePage 0x1008FF18 #define XF86XK_Mail 0x1008FF19 #define XF86XK_Start 0x1008FF1A #define XF86XK_Search 0x1008FF1B #define XF86XK_AudioRecord 0x1008FF1C #define XF86XK_Calculator 0x1008FF1D #define XF86XK_Memo 0x1008FF1E #define XF86XK_ToDoList 0x1008FF1F #define XF86XK_Calendar 0x1008FF20 #define XF86XK_PowerDown 0x1008FF21 #define XF86XK_ContrastAdjust 0x1008FF22 #define XF86XK_Back 0x1008FF26 #define XF86XK_Forward 0x1008FF27 #define XF86XK_Stop 0x1008FF28 #define XF86XK_Refresh 0x1008FF29 #define XF86XK_PowerOff 0x1008FF2A #define XF86XK_WakeUp 0x1008FF2B #define XF86XK_Eject 0x1008FF2C #define XF86XK_ScreenSaver 0x1008FF2D #define XF86XK_WWW 0x1008FF2E #define XF86XK_Sleep 0x1008FF2F #define XF86XK_Favorites 0x1008FF30 #define XF86XK_AudioPause 0x1008FF31 #define XF86XK_AudioMedia 0x1008FF32 #define XF86XK_MyComputer 0x1008FF33 #define XF86XK_LightBulb 0x1008FF35 #define XF86XK_Shop 0x1008FF36 #define XF86XK_History 0x1008FF37 #define XF86XK_OpenURL 0x1008FF38 #define XF86XK_AddFavorite 0x1008FF39 #define XF86XK_HotLinks 0x1008FF3A #define XF86XK_BrightnessAdjust 0x1008FF3B #define XF86XK_Finance 0x1008FF3C #define XF86XK_Community 0x1008FF3D #define XF86XK_AudioRewind 0x1008FF3E #define XF86XK_BackForward 0x1008FF3F #define XF86XK_Launch0 0x1008FF40 #define XF86XK_Launch1 0x1008FF41 #define XF86XK_Launch2 0x1008FF42 #define XF86XK_Launch3 0x1008FF43 #define XF86XK_Launch4 0x1008FF44 #define XF86XK_Launch5 0x1008FF45 #define XF86XK_Launch6 0x1008FF46 #define XF86XK_Launch7 0x1008FF47 #define XF86XK_Launch8 0x1008FF48 #define XF86XK_Launch9 0x1008FF49 #define XF86XK_LaunchA 0x1008FF4A #define XF86XK_LaunchB 0x1008FF4B #define XF86XK_LaunchC 0x1008FF4C #define XF86XK_LaunchD 0x1008FF4D #define XF86XK_LaunchE 0x1008FF4E #define XF86XK_LaunchF 0x1008FF4F #define XF86XK_ApplicationLeft 0x1008FF50 #define XF86XK_ApplicationRight 0x1008FF51 #define XF86XK_Book 0x1008FF52 #define XF86XK_CD 0x1008FF53 #define XF86XK_Calculater 0x1008FF54 #define XF86XK_Clear 0x1008FF55 #define XF86XK_ClearGrab 0x1008FE21 #define XF86XK_Close 0x1008FF56 #define XF86XK_Copy 0x1008FF57 #define XF86XK_Cut 0x1008FF58 #define XF86XK_Display 0x1008FF59 #define XF86XK_DOS 0x1008FF5A #define XF86XK_Documents 0x1008FF5B #define XF86XK_Excel 0x1008FF5C #define XF86XK_Explorer 0x1008FF5D #define XF86XK_Game 0x1008FF5E #define XF86XK_Go 0x1008FF5F #define XF86XK_iTouch 0x1008FF60 #define XF86XK_LogOff 0x1008FF61 #define XF86XK_Market 0x1008FF62 #define XF86XK_Meeting 0x1008FF63 #define XF86XK_MenuKB 0x1008FF65 #define XF86XK_MenuPB 0x1008FF66 #define XF86XK_MySites 0x1008FF67 #define XF86XK_News 0x1008FF69 #define XF86XK_OfficeHome 0x1008FF6A #define XF86XK_Option 0x1008FF6C #define XF86XK_Paste 0x1008FF6D #define XF86XK_Phone 0x1008FF6E #define XF86XK_Reply 0x1008FF72 #define XF86XK_Reload 0x1008FF73 #define XF86XK_RotateWindows 0x1008FF74 #define XF86XK_RotationPB 0x1008FF75 #define XF86XK_RotationKB 0x1008FF76 #define XF86XK_Save 0x1008FF77 #define XF86XK_Send 0x1008FF7B #define XF86XK_Spell 0x1008FF7C #define XF86XK_SplitScreen 0x1008FF7D #define XF86XK_Support 0x1008FF7E #define XF86XK_TaskPane 0x1008FF7F #define XF86XK_Terminal 0x1008FF80 #define XF86XK_Tools 0x1008FF81 #define XF86XK_Travel 0x1008FF82 #define XF86XK_Video 0x1008FF87 #define XF86XK_Word 0x1008FF89 #define XF86XK_Xfer 0x1008FF8A #define XF86XK_ZoomIn 0x1008FF8B #define XF86XK_ZoomOut 0x1008FF8C #define XF86XK_Away 0x1008FF8D #define XF86XK_Messenger 0x1008FF8E #define XF86XK_WebCam 0x1008FF8F #define XF86XK_MailForward 0x1008FF90 #define XF86XK_Pictures 0x1008FF91 #define XF86XK_Music 0x1008FF92 #define XF86XK_Battery 0x1008FF93 #define XF86XK_Bluetooth 0x1008FF94 #define XF86XK_WLAN 0x1008FF95 #define XF86XK_UWB 0x1008FF96 #define XF86XK_AudioForward 0x1008FF97 #define XF86XK_AudioRepeat 0x1008FF98 #define XF86XK_AudioRandomPlay 0x1008FF99 #define XF86XK_Subtitle 0x1008FF9A #define XF86XK_AudioCycleTrack 0x1008FF9B #define XF86XK_Time 0x1008FF9F #define XF86XK_Select 0x1008FFA0 #define XF86XK_View 0x1008FFA1 #define XF86XK_TopMenu 0x1008FFA2 #define XF86XK_Suspend 0x1008FFA7 #define XF86XK_Hibernate 0x1008FFA8 // end of XF86keysyms.h // Special keys used by Qtopia, mapped into the X11 private keypad range. #define QTOPIAXK_Select 0x11000601 #define QTOPIAXK_Yes 0x11000602 #define QTOPIAXK_No 0x11000603 #define QTOPIAXK_Cancel 0x11000604 #define QTOPIAXK_Printer 0x11000605 #define QTOPIAXK_Execute 0x11000606 #define QTOPIAXK_Sleep 0x11000607 #define QTOPIAXK_Play 0x11000608 #define QTOPIAXK_Zoom 0x11000609 #define QTOPIAXK_Context1 0x1100060A #define QTOPIAXK_Context2 0x1100060B #define QTOPIAXK_Context3 0x1100060C #define QTOPIAXK_Context4 0x1100060D #define QTOPIAXK_Call 0x1100060E #define QTOPIAXK_Hangup 0x1100060F #define QTOPIAXK_Flip 0x11000610 // keyboard mapping table static const unsigned int KeyTbl[] = { // misc keys XK_Escape, Qt::Key_Escape, XK_Tab, Qt::Key_Tab, XK_ISO_Left_Tab, Qt::Key_Backtab, XK_BackSpace, Qt::Key_Backspace, XK_Return, Qt::Key_Return, XK_Insert, Qt::Key_Insert, XK_Delete, Qt::Key_Delete, XK_Clear, Qt::Key_Delete, XK_Pause, Qt::Key_Pause, XK_Print, Qt::Key_Print, 0x1005FF60, Qt::Key_SysReq, // hardcoded Sun SysReq 0x1007ff00, Qt::Key_SysReq, // hardcoded X386 SysReq // cursor movement XK_Home, Qt::Key_Home, XK_End, Qt::Key_End, XK_Left, Qt::Key_Left, XK_Up, Qt::Key_Up, XK_Right, Qt::Key_Right, XK_Down, Qt::Key_Down, XK_Prior, Qt::Key_PageUp, XK_Next, Qt::Key_PageDown, // modifiers XK_Shift_L, Qt::Key_Shift, XK_Shift_R, Qt::Key_Shift, XK_Shift_Lock, Qt::Key_Shift, XK_Control_L, Qt::Key_Control, XK_Control_R, Qt::Key_Control, XK_Meta_L, Qt::Key_Meta, XK_Meta_R, Qt::Key_Meta, XK_Alt_L, Qt::Key_Alt, XK_Alt_R, Qt::Key_Alt, XK_Caps_Lock, Qt::Key_CapsLock, XK_Num_Lock, Qt::Key_NumLock, XK_Scroll_Lock, Qt::Key_ScrollLock, XK_Super_L, Qt::Key_Super_L, XK_Super_R, Qt::Key_Super_R, XK_Menu, Qt::Key_Menu, XK_Hyper_L, Qt::Key_Hyper_L, XK_Hyper_R, Qt::Key_Hyper_R, XK_Help, Qt::Key_Help, 0x1000FF74, Qt::Key_Backtab, // hardcoded HP backtab 0x1005FF10, Qt::Key_F11, // hardcoded Sun F36 (labeled F11) 0x1005FF11, Qt::Key_F12, // hardcoded Sun F37 (labeled F12) // numeric and function keypad keys XK_KP_Space, Qt::Key_Space, XK_KP_Tab, Qt::Key_Tab, XK_KP_Enter, Qt::Key_Enter, //XK_KP_F1, Qt::Key_F1, //XK_KP_F2, Qt::Key_F2, //XK_KP_F3, Qt::Key_F3, //XK_KP_F4, Qt::Key_F4, XK_KP_Home, Qt::Key_Home, XK_KP_Left, Qt::Key_Left, XK_KP_Up, Qt::Key_Up, XK_KP_Right, Qt::Key_Right, XK_KP_Down, Qt::Key_Down, XK_KP_Prior, Qt::Key_PageUp, XK_KP_Next, Qt::Key_PageDown, XK_KP_End, Qt::Key_End, XK_KP_Begin, Qt::Key_Clear, XK_KP_Insert, Qt::Key_Insert, XK_KP_Delete, Qt::Key_Delete, XK_KP_Equal, Qt::Key_Equal, XK_KP_Multiply, Qt::Key_Asterisk, XK_KP_Add, Qt::Key_Plus, XK_KP_Separator, Qt::Key_Comma, XK_KP_Subtract, Qt::Key_Minus, XK_KP_Decimal, Qt::Key_Period, XK_KP_Divide, Qt::Key_Slash, // International input method support keys // International & multi-key character composition XK_ISO_Level3_Shift, Qt::Key_AltGr, XK_Multi_key, Qt::Key_Multi_key, XK_Codeinput, Qt::Key_Codeinput, XK_SingleCandidate, Qt::Key_SingleCandidate, XK_MultipleCandidate, Qt::Key_MultipleCandidate, XK_PreviousCandidate, Qt::Key_PreviousCandidate, // Misc Functions XK_Mode_switch, Qt::Key_Mode_switch, XK_script_switch, Qt::Key_Mode_switch, // Japanese keyboard support XK_Kanji, Qt::Key_Kanji, XK_Muhenkan, Qt::Key_Muhenkan, //XK_Henkan_Mode, Qt::Key_Henkan_Mode, XK_Henkan_Mode, Qt::Key_Henkan, XK_Henkan, Qt::Key_Henkan, XK_Romaji, Qt::Key_Romaji, XK_Hiragana, Qt::Key_Hiragana, XK_Katakana, Qt::Key_Katakana, XK_Hiragana_Katakana, Qt::Key_Hiragana_Katakana, XK_Zenkaku, Qt::Key_Zenkaku, XK_Hankaku, Qt::Key_Hankaku, XK_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku, XK_Touroku, Qt::Key_Touroku, XK_Massyo, Qt::Key_Massyo, XK_Kana_Lock, Qt::Key_Kana_Lock, XK_Kana_Shift, Qt::Key_Kana_Shift, XK_Eisu_Shift, Qt::Key_Eisu_Shift, XK_Eisu_toggle, Qt::Key_Eisu_toggle, //XK_Kanji_Bangou, Qt::Key_Kanji_Bangou, //XK_Zen_Koho, Qt::Key_Zen_Koho, //XK_Mae_Koho, Qt::Key_Mae_Koho, XK_Kanji_Bangou, Qt::Key_Codeinput, XK_Zen_Koho, Qt::Key_MultipleCandidate, XK_Mae_Koho, Qt::Key_PreviousCandidate, #ifdef XK_KOREAN // Korean keyboard support XK_Hangul, Qt::Key_Hangul, XK_Hangul_Start, Qt::Key_Hangul_Start, XK_Hangul_End, Qt::Key_Hangul_End, XK_Hangul_Hanja, Qt::Key_Hangul_Hanja, XK_Hangul_Jamo, Qt::Key_Hangul_Jamo, XK_Hangul_Romaja, Qt::Key_Hangul_Romaja, //XK_Hangul_Codeinput, Qt::Key_Hangul_Codeinput, XK_Hangul_Codeinput, Qt::Key_Codeinput, XK_Hangul_Jeonja, Qt::Key_Hangul_Jeonja, XK_Hangul_Banja, Qt::Key_Hangul_Banja, XK_Hangul_PreHanja, Qt::Key_Hangul_PreHanja, XK_Hangul_PostHanja, Qt::Key_Hangul_PostHanja, //XK_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate, //XK_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate, //XK_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate, XK_Hangul_SingleCandidate, Qt::Key_SingleCandidate, XK_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate, XK_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate, XK_Hangul_Special, Qt::Key_Hangul_Special, //XK_Hangul_switch, Qt::Key_Hangul_switch, XK_Hangul_switch, Qt::Key_Mode_switch, #endif // XK_KOREAN // dead keys XK_dead_grave, Qt::Key_Dead_Grave, XK_dead_acute, Qt::Key_Dead_Acute, XK_dead_circumflex, Qt::Key_Dead_Circumflex, XK_dead_tilde, Qt::Key_Dead_Tilde, XK_dead_macron, Qt::Key_Dead_Macron, XK_dead_breve, Qt::Key_Dead_Breve, XK_dead_abovedot, Qt::Key_Dead_Abovedot, XK_dead_diaeresis, Qt::Key_Dead_Diaeresis, XK_dead_abovering, Qt::Key_Dead_Abovering, XK_dead_doubleacute, Qt::Key_Dead_Doubleacute, XK_dead_caron, Qt::Key_Dead_Caron, XK_dead_cedilla, Qt::Key_Dead_Cedilla, XK_dead_ogonek, Qt::Key_Dead_Ogonek, XK_dead_iota, Qt::Key_Dead_Iota, XK_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound, XK_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound, XK_dead_belowdot, Qt::Key_Dead_Belowdot, XK_dead_hook, Qt::Key_Dead_Hook, XK_dead_horn, Qt::Key_Dead_Horn, // Special keys from X.org - This include multimedia keys, // wireless/bluetooth/uwb keys, special launcher keys, etc. XF86XK_Back, Qt::Key_Back, XF86XK_Forward, Qt::Key_Forward, XF86XK_Stop, Qt::Key_Stop, XF86XK_Refresh, Qt::Key_Refresh, XF86XK_Favorites, Qt::Key_Favorites, XF86XK_AudioMedia, Qt::Key_LaunchMedia, XF86XK_OpenURL, Qt::Key_OpenUrl, XF86XK_HomePage, Qt::Key_HomePage, XF86XK_Search, Qt::Key_Search, XF86XK_AudioLowerVolume, Qt::Key_VolumeDown, XF86XK_AudioMute, Qt::Key_VolumeMute, XF86XK_AudioRaiseVolume, Qt::Key_VolumeUp, XF86XK_AudioPlay, Qt::Key_MediaPlay, XF86XK_AudioStop, Qt::Key_MediaStop, XF86XK_AudioPrev, Qt::Key_MediaPrevious, XF86XK_AudioNext, Qt::Key_MediaNext, XF86XK_AudioRecord, Qt::Key_MediaRecord, XF86XK_Mail, Qt::Key_LaunchMail, XF86XK_MyComputer, Qt::Key_Launch0, // ### Qt 5: remap properly XF86XK_Calculator, Qt::Key_Launch1, XF86XK_Memo, Qt::Key_Memo, XF86XK_ToDoList, Qt::Key_ToDoList, XF86XK_Calendar, Qt::Key_Calendar, XF86XK_PowerDown, Qt::Key_PowerDown, XF86XK_ContrastAdjust, Qt::Key_ContrastAdjust, XF86XK_Standby, Qt::Key_Standby, XF86XK_MonBrightnessUp, Qt::Key_MonBrightnessUp, XF86XK_MonBrightnessDown, Qt::Key_MonBrightnessDown, XF86XK_KbdLightOnOff, Qt::Key_KeyboardLightOnOff, XF86XK_KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp, XF86XK_KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown, XF86XK_PowerOff, Qt::Key_PowerOff, XF86XK_WakeUp, Qt::Key_WakeUp, XF86XK_Eject, Qt::Key_Eject, XF86XK_ScreenSaver, Qt::Key_ScreenSaver, XF86XK_WWW, Qt::Key_WWW, XF86XK_Sleep, Qt::Key_Sleep, XF86XK_LightBulb, Qt::Key_LightBulb, XF86XK_Shop, Qt::Key_Shop, XF86XK_History, Qt::Key_History, XF86XK_AddFavorite, Qt::Key_AddFavorite, XF86XK_HotLinks, Qt::Key_HotLinks, XF86XK_BrightnessAdjust, Qt::Key_BrightnessAdjust, XF86XK_Finance, Qt::Key_Finance, XF86XK_Community, Qt::Key_Community, XF86XK_AudioRewind, Qt::Key_AudioRewind, XF86XK_BackForward, Qt::Key_BackForward, XF86XK_ApplicationLeft, Qt::Key_ApplicationLeft, XF86XK_ApplicationRight, Qt::Key_ApplicationRight, XF86XK_Book, Qt::Key_Book, XF86XK_CD, Qt::Key_CD, XF86XK_Calculater, Qt::Key_Calculator, XF86XK_Clear, Qt::Key_Clear, XF86XK_ClearGrab, Qt::Key_ClearGrab, XF86XK_Close, Qt::Key_Close, XF86XK_Copy, Qt::Key_Copy, XF86XK_Cut, Qt::Key_Cut, XF86XK_Display, Qt::Key_Display, XF86XK_DOS, Qt::Key_DOS, XF86XK_Documents, Qt::Key_Documents, XF86XK_Excel, Qt::Key_Excel, XF86XK_Explorer, Qt::Key_Explorer, XF86XK_Game, Qt::Key_Game, XF86XK_Go, Qt::Key_Go, XF86XK_iTouch, Qt::Key_iTouch, XF86XK_LogOff, Qt::Key_LogOff, XF86XK_Market, Qt::Key_Market, XF86XK_Meeting, Qt::Key_Meeting, XF86XK_MenuKB, Qt::Key_MenuKB, XF86XK_MenuPB, Qt::Key_MenuPB, XF86XK_MySites, Qt::Key_MySites, XF86XK_News, Qt::Key_News, XF86XK_OfficeHome, Qt::Key_OfficeHome, XF86XK_Option, Qt::Key_Option, XF86XK_Paste, Qt::Key_Paste, XF86XK_Phone, Qt::Key_Phone, XF86XK_Reply, Qt::Key_Reply, XF86XK_Reload, Qt::Key_Reload, XF86XK_RotateWindows, Qt::Key_RotateWindows, XF86XK_RotationPB, Qt::Key_RotationPB, XF86XK_RotationKB, Qt::Key_RotationKB, XF86XK_Save, Qt::Key_Save, XF86XK_Send, Qt::Key_Send, XF86XK_Spell, Qt::Key_Spell, XF86XK_SplitScreen, Qt::Key_SplitScreen, XF86XK_Support, Qt::Key_Support, XF86XK_TaskPane, Qt::Key_TaskPane, XF86XK_Terminal, Qt::Key_Terminal, XF86XK_Tools, Qt::Key_Tools, XF86XK_Travel, Qt::Key_Travel, XF86XK_Video, Qt::Key_Video, XF86XK_Word, Qt::Key_Word, XF86XK_Xfer, Qt::Key_Xfer, XF86XK_ZoomIn, Qt::Key_ZoomIn, XF86XK_ZoomOut, Qt::Key_ZoomOut, XF86XK_Away, Qt::Key_Away, XF86XK_Messenger, Qt::Key_Messenger, XF86XK_WebCam, Qt::Key_WebCam, XF86XK_MailForward, Qt::Key_MailForward, XF86XK_Pictures, Qt::Key_Pictures, XF86XK_Music, Qt::Key_Music, XF86XK_Battery, Qt::Key_Battery, XF86XK_Bluetooth, Qt::Key_Bluetooth, XF86XK_WLAN, Qt::Key_WLAN, XF86XK_UWB, Qt::Key_UWB, XF86XK_AudioForward, Qt::Key_AudioForward, XF86XK_AudioRepeat, Qt::Key_AudioRepeat, XF86XK_AudioRandomPlay, Qt::Key_AudioRandomPlay, XF86XK_Subtitle, Qt::Key_Subtitle, XF86XK_AudioCycleTrack, Qt::Key_AudioCycleTrack, XF86XK_Time, Qt::Key_Time, XF86XK_Select, Qt::Key_Select, XF86XK_View, Qt::Key_View, XF86XK_TopMenu, Qt::Key_TopMenu, XF86XK_Bluetooth, Qt::Key_Bluetooth, XF86XK_Suspend, Qt::Key_Suspend, XF86XK_Hibernate, Qt::Key_Hibernate, XF86XK_Launch0, Qt::Key_Launch2, // ### Qt 5: remap properly XF86XK_Launch1, Qt::Key_Launch3, XF86XK_Launch2, Qt::Key_Launch4, XF86XK_Launch3, Qt::Key_Launch5, XF86XK_Launch4, Qt::Key_Launch6, XF86XK_Launch5, Qt::Key_Launch7, XF86XK_Launch6, Qt::Key_Launch8, XF86XK_Launch7, Qt::Key_Launch9, XF86XK_Launch8, Qt::Key_LaunchA, XF86XK_Launch9, Qt::Key_LaunchB, XF86XK_LaunchA, Qt::Key_LaunchC, XF86XK_LaunchB, Qt::Key_LaunchD, XF86XK_LaunchC, Qt::Key_LaunchE, XF86XK_LaunchD, Qt::Key_LaunchF, XF86XK_LaunchE, Qt::Key_LaunchG, XF86XK_LaunchF, Qt::Key_LaunchH, // Qtopia keys QTOPIAXK_Select, Qt::Key_Select, QTOPIAXK_Yes, Qt::Key_Yes, QTOPIAXK_No, Qt::Key_No, QTOPIAXK_Cancel, Qt::Key_Cancel, QTOPIAXK_Printer, Qt::Key_Printer, QTOPIAXK_Execute, Qt::Key_Execute, QTOPIAXK_Sleep, Qt::Key_Sleep, QTOPIAXK_Play, Qt::Key_Play, QTOPIAXK_Zoom, Qt::Key_Zoom, QTOPIAXK_Context1, Qt::Key_Context1, QTOPIAXK_Context2, Qt::Key_Context2, QTOPIAXK_Context3, Qt::Key_Context3, QTOPIAXK_Context4, Qt::Key_Context4, QTOPIAXK_Call, Qt::Key_Call, QTOPIAXK_Hangup, Qt::Key_Hangup, QTOPIAXK_Flip, Qt::Key_Flip, 0, 0 }; static int translateKeySym(uint key) { int code = -1; int i = 0; // any other keys while (KeyTbl[i]) { if (key == KeyTbl[i]) { code = (int)KeyTbl[i+1]; break; } i += 2; } if (qt_meta_mask) { // translate Super/Hyper keys to Meta if we're using them as the MetaModifier if (qt_meta_mask == qt_super_mask && (code == Qt::Key_Super_L || code == Qt::Key_Super_R)) { code = Qt::Key_Meta; } else if (qt_meta_mask == qt_hyper_mask && (code == Qt::Key_Hyper_L || code == Qt::Key_Hyper_R)) { code = Qt::Key_Meta; } } return code; } #if !defined(QT_NO_XIM) static const unsigned short katakanaKeysymsToUnicode[] = { 0x0000, 0x3002, 0x300C, 0x300D, 0x3001, 0x30FB, 0x30F2, 0x30A1, 0x30A3, 0x30A5, 0x30A7, 0x30A9, 0x30E3, 0x30E5, 0x30E7, 0x30C3, 0x30FC, 0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, 0x30AB, 0x30AD, 0x30AF, 0x30B1, 0x30B3, 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, 0x30BF, 0x30C1, 0x30C4, 0x30C6, 0x30C8, 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, 0x30CF, 0x30D2, 0x30D5, 0x30D8, 0x30DB, 0x30DE, 0x30DF, 0x30E0, 0x30E1, 0x30E2, 0x30E4, 0x30E6, 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F3, 0x309B, 0x309C }; static const unsigned short cyrillicKeysymsToUnicode[] = { 0x0000, 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x0000, 0x045e, 0x045f, 0x2116, 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x0000, 0x040e, 0x040f, 0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a, 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a }; static const unsigned short greekKeysymsToUnicode[] = { 0x0000, 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c, 0x038e, 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015, 0x0000, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, 0x03cd, 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 0x03a0, 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; static const unsigned short technicalKeysymsToUnicode[] = { 0x0000, 0x23B7, 0x250C, 0x2500, 0x2320, 0x2321, 0x2502, 0x23A1, 0x23A3, 0x23A4, 0x23A6, 0x239B, 0x239D, 0x239E, 0x23A0, 0x23A8, 0x23AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222B, 0x2234, 0x221D, 0x221E, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000, 0x223C, 0x2243, 0x0000, 0x0000, 0x0000, 0x21D4, 0x21D2, 0x2261, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221A, 0x0000, 0x0000, 0x0000, 0x2282, 0x2283, 0x2229, 0x222A, 0x2227, 0x2228, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2202, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000, 0x0000, 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193, 0x0000 }; static const unsigned short specialKeysymsToUnicode[] = { 0x25C6, 0x2592, 0x2409, 0x240C, 0x240D, 0x240A, 0x0000, 0x0000, 0x2424, 0x240B, 0x2518, 0x2510, 0x250C, 0x2514, 0x253C, 0x23BA, 0x23BB, 0x2500, 0x23BC, 0x23BD, 0x251C, 0x2524, 0x2534, 0x252C, 0x2502, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; static const unsigned short publishingKeysymsToUnicode[] = { 0x0000, 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009, 0x200a, 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, 0x2105, 0x0000, 0x0000, 0x2012, 0x2329, 0x0000, 0x232a, 0x0000, 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000, 0x0000, 0x2122, 0x2613, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25af, 0x2018, 0x2019, 0x201c, 0x201d, 0x211e, 0x0000, 0x2032, 0x2033, 0x0000, 0x271d, 0x0000, 0x25ac, 0x25c0, 0x25b6, 0x25cf, 0x25ae, 0x25e6, 0x25ab, 0x25ad, 0x25b3, 0x25bd, 0x2606, 0x2022, 0x25aa, 0x25b2, 0x25bc, 0x261c, 0x261e, 0x2663, 0x2666, 0x2665, 0x0000, 0x2720, 0x2020, 0x2021, 0x2713, 0x2717, 0x266f, 0x266d, 0x2642, 0x2640, 0x260e, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e, 0x0000 }; static const unsigned short aplKeysymsToUnicode[] = { 0x0000, 0x0000, 0x0000, 0x003c, 0x0000, 0x0000, 0x003e, 0x0000, 0x2228, 0x2227, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00af, 0x0000, 0x22a5, 0x2229, 0x230a, 0x0000, 0x005f, 0x0000, 0x0000, 0x0000, 0x2218, 0x0000, 0x2395, 0x0000, 0x22a4, 0x25cb, 0x0000, 0x0000, 0x0000, 0x2308, 0x0000, 0x0000, 0x222a, 0x0000, 0x2283, 0x0000, 0x2282, 0x0000, 0x22a2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x22a3, 0x0000, 0x0000, 0x0000 }; static const unsigned short koreanKeysymsToUnicode[] = { 0x0000, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f, 0x3140, 0x3141, 0x3142, 0x3143, 0x3144, 0x3145, 0x3146, 0x3147, 0x3148, 0x3149, 0x314a, 0x314b, 0x314c, 0x314d, 0x314e, 0x314f, 0x3150, 0x3151, 0x3152, 0x3153, 0x3154, 0x3155, 0x3156, 0x3157, 0x3158, 0x3159, 0x315a, 0x315b, 0x315c, 0x315d, 0x315e, 0x315f, 0x3160, 0x3161, 0x3162, 0x3163, 0x11a8, 0x11a9, 0x11aa, 0x11ab, 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3, 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb, 0x11bc, 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x316d, 0x3171, 0x3178, 0x317f, 0x3181, 0x3184, 0x3186, 0x318d, 0x318e, 0x11eb, 0x11f0, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9 }; static QChar keysymToUnicode(unsigned char byte3, unsigned char byte4) { switch (byte3) { case 0x04: // katakana if (byte4 > 0xa0 && byte4 < 0xe0) return QChar(katakanaKeysymsToUnicode[byte4 - 0xa0]); else if (byte4 == 0x7e) return QChar(0x203e); // Overline break; case 0x06: // russian, use lookup table if (byte4 > 0xa0) return QChar(cyrillicKeysymsToUnicode[byte4 - 0xa0]); break; case 0x07: // greek if (byte4 > 0xa0) return QChar(greekKeysymsToUnicode[byte4 - 0xa0]); break; case 0x08: // technical if (byte4 > 0xa0) return QChar(technicalKeysymsToUnicode[byte4 - 0xa0]); break; case 0x09: // special if (byte4 >= 0xe0) return QChar(specialKeysymsToUnicode[byte4 - 0xe0]); break; case 0x0a: // publishing if (byte4 > 0xa0) return QChar(publishingKeysymsToUnicode[byte4 - 0xa0]); break; case 0x0b: // APL if (byte4 > 0xa0) return QChar(aplKeysymsToUnicode[byte4 - 0xa0]); break; case 0x0e: // Korean if (byte4 > 0xa0) return QChar(koreanKeysymsToUnicode[byte4 - 0xa0]); break; default: break; } return QChar(0x0); } #endif static QString translateKeySym(KeySym keysym, uint xmodifiers, int &code, Qt::KeyboardModifiers &modifiers, QByteArray &chars, int &count) { // all keysyms smaller than 0xff00 are actally keys that can be mapped to unicode chars extern QTextCodec *qt_input_mapper; // from qapplication_x11.cpp QTextCodec *mapper = qt_input_mapper; QChar converted; if (count == 0 && keysym < 0xff00) { unsigned char byte3 = (unsigned char)(keysym >> 8); int mib = -1; switch(byte3) { case 0: // Latin 1 case 1: // Latin 2 case 2: //latin 3 case 3: // latin4 mib = byte3 + 4; break; case 5: // arabic mib = 82; break; case 12: // Hebrew mib = 85; break; case 13: // Thai mib = 2259; break; case 4: // kana case 6: // cyrillic case 7: // greek case 8: // technical, no mapping here at the moment case 9: // Special case 10: // Publishing case 11: // APL case 14: // Korean, no mapping mib = -1; // manual conversion mapper = 0; #if !defined(QT_NO_XIM) converted = keysymToUnicode(byte3, keysym & 0xff); #endif case 0x20: // currency symbols if (keysym >= 0x20a0 && keysym <= 0x20ac) { mib = -1; // manual conversion mapper = 0; converted = (uint)keysym; } break; default: break; } if (mib != -1) { mapper = QTextCodec::codecForMib(mib); if (chars.isEmpty()) chars.resize(1); chars[0] = (unsigned char) (keysym & 0xff); // get only the fourth bit for conversion later count++; } } else if (keysym >= 0x1000000 && keysym <= 0x100ffff) { converted = (ushort) (keysym - 0x1000000); mapper = 0; } if (count < (int)chars.size()-1) chars[count] = '\0'; QString text; if (!mapper && converted.unicode() != 0x0) { text = converted; } else if (!chars.isEmpty()) { // convert chars (8bit) to text (unicode). if (mapper) text = mapper->toUnicode(chars.data(), count, 0); if (text.isEmpty()) { // no mapper, or codec couldn't convert to unicode (this // can happen when running in the C locale or with no LANG // set). try converting from latin-1 text = QString::fromLatin1(chars); } } modifiers = X11->translateModifiers(xmodifiers); // Commentary in X11/keysymdef says that X codes match ASCII, so it // is safe to use the locale functions to process X codes in ISO8859-1. // // This is mainly for compatibility - applications should not use the // Qt keycodes between 128 and 255, but should rather use the // QKeyEvent::text(). // extern QTextCodec *qt_input_mapper; // from qapplication_x11.cpp if (keysym < 128 || (keysym < 256 && (!qt_input_mapper || qt_input_mapper->mibEnum()==4))) { // upper-case key, if known code = isprint((int)keysym) ? toupper((int)keysym) : 0; } else if (keysym >= XK_F1 && keysym <= XK_F35) { // function keys code = Qt::Key_F1 + ((int)keysym - XK_F1); } else if (keysym >= XK_KP_Space && keysym <= XK_KP_9) { if (keysym >= XK_KP_0) { // numeric keypad keys code = Qt::Key_0 + ((int)keysym - XK_KP_0); } else { code = translateKeySym(keysym); } modifiers |= Qt::KeypadModifier; } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f && text.unicode()->unicode() != 0x7f && !(keysym >= XK_dead_grave && keysym <= XK_dead_horn)) { code = text.unicode()->toUpper().unicode(); } else { // any other keys code = translateKeySym(keysym); if (code == Qt::Key_Tab && (modifiers & Qt::ShiftModifier)) { // map shift+tab to shift+backtab, QShortcutMap knows about it // and will handle it. code = Qt::Key_Backtab; text = QString(); } } return text; } extern bool qt_use_rtl_extensions; // from qapplication_x11.cpp bool QKeyMapperPrivate::translateKeyEventInternal(QWidget *keyWidget, const XEvent *event, KeySym &keysym, int& count, QString& text, Qt::KeyboardModifiers &modifiers, int& code, QEvent::Type &type, bool statefulTranslation) { XKeyEvent xkeyevent = event->xkey; int keycode = event->xkey.keycode; // save the modifier state, we will use the keystate uint later by passing // it to translateButtonState uint keystate = event->xkey.state; type = (event->type == XKeyPress) ? QEvent::KeyPress : QEvent::KeyRelease; static int directionKeyEvent = 0; static unsigned int lastWinId = 0; // translate pending direction change if (statefulTranslation && qt_use_rtl_extensions && type == QEvent::KeyRelease) { if (directionKeyEvent == Qt::Key_Direction_R || directionKeyEvent == Qt::Key_Direction_L) { type = QEvent::KeyPress; code = directionKeyEvent; text = QString(); directionKeyEvent = 0; lastWinId = 0; return true; } else { directionKeyEvent = 0; lastWinId = 0; } } // some XmbLookupString implementations don't return buffer overflow correctly, // so we increase the input buffer to allow for long strings... // 256 chars * 2 bytes + 1 null-term == 513 bytes QByteArray chars; chars.resize(513); count = XLookupString(&xkeyevent, chars.data(), chars.size(), &keysym, 0); if (count && !keycode) { extern int qt_ximComposingKeycode; // from qapplication_x11.cpp keycode = qt_ximComposingKeycode; qt_ximComposingKeycode = 0; } // translate the keysym + xmodifiers to Qt::Key_* + Qt::KeyboardModifiers text = translateKeySym(keysym, keystate, code, modifiers, chars, count); // Watch for keypresses and if its a key belonging to the Ctrl-Shift // direction-changing accel, remember it. // We keep track of those keys instead of using the event's state // (to figure out whether the Ctrl modifier is held while Shift is pressed, // or Shift is held while Ctrl is pressed) since the 'state' doesn't tell // us whether the modifier held is Left or Right. if (statefulTranslation && qt_use_rtl_extensions && type == QEvent::KeyPress) { if (keysym == XK_Control_L || keysym == XK_Control_R || keysym == XK_Shift_L || keysym == XK_Shift_R) { if (!directionKeyEvent) { directionKeyEvent = keysym; // This code exists in order to check that // the event is occurred in the same widget. lastWinId = keyWidget->internalWinId(); } } else { // this can no longer be a direction-changing accel. // if any other key was pressed. directionKeyEvent = Qt::Key_Space; } if (directionKeyEvent && lastWinId == keyWidget->internalWinId()) { if ((keysym == XK_Shift_L && directionKeyEvent == XK_Control_L) || (keysym == XK_Control_L && directionKeyEvent == XK_Shift_L)) { directionKeyEvent = Qt::Key_Direction_L; } else if ((keysym == XK_Shift_R && directionKeyEvent == XK_Control_R) || (keysym == XK_Control_R && directionKeyEvent == XK_Shift_R)) { directionKeyEvent = Qt::Key_Direction_R; } } else if (directionKeyEvent == Qt::Key_Direction_L || directionKeyEvent == Qt::Key_Direction_R) { directionKeyEvent = Qt::Key_Space; // invalid } } return true; } struct qt_auto_repeat_data { // match the window and keycode with timestamp delta of 10 ms Window window; KeyCode keycode; Time timestamp; // queue scanner state bool release; bool error; }; #if defined(Q_C_CALLBACKS) extern "C" { #endif static Bool qt_keypress_scanner(Display *, XEvent *event, XPointer arg) { if (event->type != XKeyPress && event->type != XKeyRelease) return false; qt_auto_repeat_data *data = (qt_auto_repeat_data *) arg; if (data->error) return false; if (event->xkey.window != data->window || event->xkey.keycode != data->keycode) { // deal breakers: key events in a different window or an event // with a different key code data->error = true; return false; } if (event->type == XKeyPress) { data->error = (! data->release || event->xkey.time - data->timestamp > 10); return (! data->error); } // must be XKeyRelease event if (data->release) { // found a second release data->error = true; return false; } // found a single release data->release = true; data->timestamp = event->xkey.time; return false; } static Bool qt_keyrelease_scanner(Display *, XEvent *event, XPointer arg) { const qt_auto_repeat_data *data = (const qt_auto_repeat_data *) arg; return (event->type == XKeyRelease && event->xkey.window == data->window && event->xkey.keycode == data->keycode); } #if defined(Q_C_CALLBACKS) } #endif bool QKeyMapperPrivate::translateKeyEvent(QWidget *keyWidget, const XEvent *event, bool grab) { int code = -1; int count = 0; Qt::KeyboardModifiers modifiers; if (qt_sm_blockUserInput) // block user interaction during session management return true; Display *dpy = X11->display; if (!keyWidget->isEnabled()) return true; QEvent::Type type; bool autor = false; QString text; KeySym keysym = 0; translateKeyEventInternal(keyWidget, event, keysym, count, text, modifiers, code, type); // was this the last auto-repeater? qt_auto_repeat_data auto_repeat_data; auto_repeat_data.window = event->xkey.window; auto_repeat_data.keycode = event->xkey.keycode; auto_repeat_data.timestamp = event->xkey.time; static uint curr_autorep = 0; if (event->type == XKeyPress) { if (curr_autorep == event->xkey.keycode) { autor = true; curr_autorep = 0; } } else { // look ahead for auto-repeat XEvent nextpress; auto_repeat_data.release = true; auto_repeat_data.error = false; if (XCheckIfEvent(dpy, &nextpress, &qt_keypress_scanner, (XPointer) &auto_repeat_data)) { autor = true; // Put it back... we COULD send the event now and not need // the static curr_autorep variable. XPutBackEvent(dpy,&nextpress); } curr_autorep = autor ? event->xkey.keycode : 0; } #if defined QT3_SUPPORT && !defined(QT_NO_SHORTCUT) // process accelerators before doing key compression if (type == QEvent::KeyPress && !grab && QApplicationPrivate::instance()->use_compat()) { // send accel events if the keyboard is not grabbed QKeyEventEx a(type, code, modifiers, text, autor, qMax(qMax(count,1), int(text.length())), event->xkey.keycode, keysym, event->xkey.state); if (QApplicationPrivate::instance()->qt_tryAccelEvent(keyWidget, &a)) return true; } #endif #ifndef QT_NO_IM QInputContext *qic = keyWidget->inputContext(); #endif // compress keys if (!text.isEmpty() && keyWidget->testAttribute(Qt::WA_KeyCompression) && #ifndef QT_NO_IM // Ordinary input methods require discrete key events to work // properly, so key compression has to be disabled when input // context exists. // // And further consideration, some complex input method // require all key press/release events discretely even if // the input method awares of key compression and compressed // keys are ordinary alphabets. For example, the uim project // is planning to implement "combinational shift" feature for // a Japanese input method, uim-skk. It will work as follows. // // 1. press "r" // 2. press "u" // 3. release both "r" and "u" in arbitrary order // 4. above key sequence generates "Ru" // // Of course further consideration about other participants // such as key repeat mechanism is required to implement such // feature. !qic && #endif // QT_NO_IM // do not compress keys if the key event we just got above matches // one of the key ranges used to compute stopCompression !((code >= Qt::Key_Escape && code <= Qt::Key_SysReq) || (code >= Qt::Key_Home && code <= Qt::Key_PageDown) || (code >= Qt::Key_Super_L && code <= Qt::Key_Direction_R) || (code == 0) || (text.length() == 1 && text.unicode()->unicode() == '\n'))) { // the widget wants key compression so it gets it // sync the event queue, this makes key compress work better XSync(dpy, false); for (;;) { XEvent evRelease; XEvent evPress; if (!XCheckTypedWindowEvent(dpy,event->xkey.window, XKeyRelease,&evRelease)) break; if (!XCheckTypedWindowEvent(dpy,event->xkey.window, XKeyPress,&evPress)) { XPutBackEvent(dpy, &evRelease); break; } QString textIntern; int codeIntern = -1; int countIntern = 0; Qt::KeyboardModifiers modifiersIntern; QEvent::Type t; KeySym keySymIntern; translateKeyEventInternal(keyWidget, &evPress, keySymIntern, countIntern, textIntern, modifiersIntern, codeIntern, t); // use stopCompression to stop key compression for the following // key event ranges: bool stopCompression = // 1) misc keys (codeIntern >= Qt::Key_Escape && codeIntern <= Qt::Key_SysReq) // 2) cursor movement || (codeIntern >= Qt::Key_Home && codeIntern <= Qt::Key_PageDown) // 3) extra keys || (codeIntern >= Qt::Key_Super_L && codeIntern <= Qt::Key_Direction_R) // 4) something that a) doesn't translate to text or b) translates // to newline text || (codeIntern == 0) || (textIntern.length() == 1 && textIntern.unicode()->unicode() == '\n') || (codeIntern == Qt::Key_unknown); if (modifiersIntern == modifiers && !textIntern.isEmpty() && !stopCompression) { text += textIntern; count += countIntern; } else { XPutBackEvent(dpy, &evPress); XPutBackEvent(dpy, &evRelease); break; } } } // autorepeat compression makes sense for all widgets (Windows // does it automatically ....) if (event->type == XKeyPress && text.length() <= 1 #ifndef QT_NO_IM // input methods need discrete key events && !qic #endif// QT_NO_IM ) { XEvent dummy; for (;;) { auto_repeat_data.release = false; auto_repeat_data.error = false; if (! XCheckIfEvent(dpy, &dummy, &qt_keypress_scanner, (XPointer) &auto_repeat_data)) break; if (! XCheckIfEvent(dpy, &dummy, &qt_keyrelease_scanner, (XPointer) &auto_repeat_data)) break; count++; if (!text.isEmpty()) text += text[0]; } } return QKeyMapper::sendKeyEvent(keyWidget, grab, type, code, modifiers, text, autor, qMax(qMax(count,1), int(text.length())), event->xkey.keycode, keysym, event->xkey.state); } bool QKeyMapper::sendKeyEvent(QWidget *keyWidget, bool grab, QEvent::Type type, int code, Qt::KeyboardModifiers modifiers, const QString &text, bool autorepeat, int count, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, bool *) { // try the menukey first if (type == QEvent::KeyPress && code == Qt::Key_Menu) { QVariant v = keyWidget->inputMethodQuery(Qt::ImMicroFocus); QPoint globalPos; QPoint pos; if (v.isNull()) { globalPos = QCursor::pos(); pos = keyWidget->mapFromGlobal(globalPos); } else { pos = v.toRect().center(); globalPos = keyWidget->mapToGlobal(pos); } QContextMenuEvent e(QContextMenuEvent::Keyboard, pos, globalPos); qt_sendSpontaneousEvent(keyWidget, &e); if(e.isAccepted()) return true; } Q_UNUSED(grab); QKeyEventEx e(type, code, modifiers, text, autorepeat, qMax(qMax(count,1), int(text.length())), nativeScanCode, nativeVirtualKey, nativeModifiers); return qt_sendSpontaneousEvent(keyWidget, &e); } QT_END_NAMESPACE