diff -r 000000000000 -r 1918ee327afb src/gui/kernel/qkeymapper_x11.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gui/kernel/qkeymapper_x11.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,1678 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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 + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_XKB + +// bring in the auto-generated xkbLayoutData +#include "qkeymapper_x11_p.cpp" + +#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 + +static void getLocaleAndDirection(QLocale *locale, + Qt::LayoutDirection *direction, + const QByteArray &layoutName, + const QByteArray &variantName) +{ + int i = 0; + while (xkbLayoutData[i].layout != 0) { + if (layoutName == xkbLayoutData[i].layout && variantName == xkbLayoutData[i].variant) { + *locale = QLocale(xkbLayoutData[i].language, xkbLayoutData[i].country); + *direction = xkbLayoutData[i].direction; + return; + } + ++i; + } + *locale = QLocale::c(); + *direction = Qt::LeftToRight; +} +#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), useXKB(false) +{ + memset(&coreDesc, 0, sizeof(coreDesc)); + +#ifndef QT_NO_XKB + int opcode = -1; + int xkbEventBase = -1; + int xkbErrorBase = -1; + int xkblibMajor = XkbMajorVersion; + int xkblibMinor = XkbMinorVersion; + if (XkbQueryExtension(X11->display, &opcode, &xkbEventBase, &xkbErrorBase, &xkblibMajor, &xkblibMinor)) + useXKB = true; +#endif + +#if 0 + qDebug() << "useXKB =" << useXKB; +#endif +} + +QKeyMapperPrivate::~QKeyMapperPrivate() +{ + if (coreDesc.keysyms) + XFree(coreDesc.keysyms); +} + +QList QKeyMapperPrivate::possibleKeys(QKeyEvent *event) +{ +#ifndef QT_NO_XKB + if (useXKB) + 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 == 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 == 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 (useXKB) { + // 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); + + layoutName = QByteArray::fromRawData(names[2], qstrlen(names[2])); + variantName = QByteArray::fromRawData(names[3], qstrlen(names[3])); + } + + // ### ??? + // if (keyboardLayoutName.isEmpty()) + // qWarning("Qt: unable to determine keyboard layout, please talk to qt-bugs@trolltech.com"); ? + + getLocaleAndDirection(&keyboardInputLocale, + &keyboardInputDirection, + layoutName, + variantName); + +#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 (useXKB) { + 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 from XFree > 4.0 (X11/XF86keysyms.h), defining some special +// multimedia keys. They are included here as not every system has them. +#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_Calculator 0x1008FF1D +#define XF86XK_Mail 0x1008FF19 +#define XF86XK_Start 0x1008FF1A +#define XF86XK_Search 0x1008FF1B +#define XF86XK_AudioRecord 0x1008FF1C +#define XF86XK_Back 0x1008FF26 +#define XF86XK_Forward 0x1008FF27 +#define XF86XK_Stop 0x1008FF28 +#define XF86XK_Refresh 0x1008FF29 +#define XF86XK_Favorites 0x1008FF30 +#define XF86XK_AudioPause 0x1008FF31 +#define XF86XK_AudioMedia 0x1008FF32 +#define XF86XK_MyComputer 0x1008FF33 +#define XF86XK_OpenURL 0x1008FF38 +#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 +// 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 multimedia keys + // currently only tested with MS internet keyboard + + // browsing keys + 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, + + // media keys + 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, + + // launch keys + XF86XK_Mail, Qt::Key_LaunchMail, + XF86XK_MyComputer, Qt::Key_Launch0, + XF86XK_Calculator, Qt::Key_Launch1, + XF86XK_Standby, Qt::Key_Standby, + + XF86XK_Launch0, Qt::Key_Launch2, + 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, + + // 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