📄 qkeymapper_x11.cpp
字号:
// 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;}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; extern bool qt_use_rtl_extensions; // from qapplication_x11.cpp // 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" {#endifstatic 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 || event->xkey.window != data->window || event->xkey.keycode != data->keycode) 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)}#endifbool 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'); 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){ // try the menukey first if (type == QEvent::KeyPress && code == Qt::Key_Menu) { QPoint pos = keyWidget->inputMethodQuery(Qt::ImMicroFocus).toRect().center(); QContextMenuEvent e(QContextMenuEvent::Keyboard, pos, keyWidget->mapToGlobal(pos)); 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -