File indexing completed on 2024-05-26 04:30:15

0001 /*
0002  *  SPDX-FileCopyrightText: 2013 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_extended_modifiers_mapper.h"
0008 
0009 #include <QApplication>
0010 #include <QKeyEvent>
0011 #include "kis_debug.h"
0012 
0013 #ifdef Q_OS_MACOS
0014 
0015 #include "kis_extended_modifiers_mapper_osx.h"
0016 
0017 #endif /* Q_OS_MACOS */
0018 
0019 #ifdef Q_OS_WIN
0020 
0021 #include <windows.h>
0022 #include <commctrl.h>
0023 #include <winuser.h>
0024 
0025 #include "krita_container_utils.h"
0026 
0027 
0028 QVector<Qt::Key> queryPressedKeysWin()
0029 {
0030     QVector<Qt::Key> result;
0031     BYTE vkeys[256];
0032 
0033     if (GetKeyboardState(vkeys)) {
0034         for (int i = 0; i < 256; i++) {
0035             if (vkeys[i] & 0x80) {
0036                 if (i == VK_SHIFT) {
0037                     result << Qt::Key_Shift;
0038                 } else if (i == VK_CONTROL) {
0039                     result << Qt::Key_Control;
0040                 } else if (i == VK_MENU) {
0041                     result << Qt::Key_Alt;
0042                 } else if (i == VK_LWIN || i == VK_RWIN) {
0043                     result << Qt::Key_Meta;
0044                 } else if (i == VK_SPACE) {
0045                     result << Qt::Key_Space;
0046                 } else if (i >= 0x30 && i <= 0x39) {
0047                     result << static_cast<Qt::Key>(Qt::Key_0 + i - 0x30);
0048                 } else if (i >= 0x41 && i <= 0x5A) {
0049                     result << static_cast<Qt::Key>(Qt::Key_A + i - 0x41);
0050                 } else if (i >= 0x60 && i <= 0x69) {
0051                     result << static_cast<Qt::Key>(Qt::Key_0 + i - 0x60);
0052                 } else if (i >= 0x70 && i <= 0x87) {
0053                     result << static_cast<Qt::Key>(Qt::Key_F1 + i - 0x70);
0054                 }
0055             }
0056         }
0057     }
0058 
0059     KritaUtils::makeContainerUnique(result);
0060 
0061     return result;
0062 }
0063 
0064 #elif defined HAVE_X11
0065 
0066 #include <QX11Info>
0067 #include <X11/X.h>
0068 #include <X11/Xlib.h>
0069 #include <X11/keysym.h>
0070 #include <krita_container_utils.h>
0071 #include <X11/XKBlib.h>
0072 
0073 struct KeyMapping {
0074     KeyMapping() {}
0075     KeyMapping(KeySym sym, Qt::Key key) : x11KeySym(sym), qtKey(key) {}
0076     KeySym x11KeySym {0};
0077     Qt::Key qtKey {Qt::Key_unknown};
0078 };
0079 
0080 #endif /* HAVE_X11 */
0081 
0082 struct KisExtendedModifiersMapper::Private
0083 {
0084     Private();
0085 
0086 #ifdef HAVE_X11
0087 
0088     QVector<KeyMapping> mapping;
0089     char keysState[32];
0090     int minKeyCode = 0;
0091     int maxKeyCode = 0;
0092 
0093     bool checkKeyCodePressedX11(KeyCode key);
0094     bool checkKeySymPressedX11(KeySym sym);
0095 #endif /* HAVE_X11 */
0096 };
0097 
0098 #ifdef HAVE_X11
0099 
0100 KisExtendedModifiersMapper::Private::Private()
0101 {
0102     XDisplayKeycodes(QX11Info::display(), &minKeyCode, &maxKeyCode);
0103     XQueryKeymap(QX11Info::display(), keysState);
0104 
0105     mapping.append(KeyMapping(XK_Shift_L, Qt::Key_Shift));
0106     mapping.append(KeyMapping(XK_Shift_R, Qt::Key_Shift));
0107 
0108     mapping.append(KeyMapping(XK_Control_L, Qt::Key_Control));
0109     mapping.append(KeyMapping(XK_Control_R, Qt::Key_Control));
0110 
0111     mapping.append(KeyMapping(XK_Meta_L, Qt::Key_Alt));
0112     mapping.append(KeyMapping(XK_Meta_R, Qt::Key_Alt));
0113     mapping.append(KeyMapping(XK_Mode_switch, Qt::Key_AltGr));
0114     mapping.append(KeyMapping(XK_ISO_Level3_Shift, Qt::Key_AltGr));
0115 
0116     mapping.append(KeyMapping(XK_Alt_L, Qt::Key_Alt));
0117     mapping.append(KeyMapping(XK_Alt_R, Qt::Key_Alt));
0118 
0119     mapping.append(KeyMapping(XK_Super_L, Qt::Key_Meta));
0120     mapping.append(KeyMapping(XK_Super_R, Qt::Key_Meta));
0121 
0122     mapping.append(KeyMapping(XK_Hyper_L, Qt::Key_Hyper_L));
0123     mapping.append(KeyMapping(XK_Hyper_R, Qt::Key_Hyper_R));
0124 
0125 
0126     mapping.append(KeyMapping(XK_space, Qt::Key_Space));
0127 
0128     for (int qtKey = Qt::Key_0, x11Sym = XK_0;
0129          qtKey <= Qt::Key_9;
0130          qtKey++, x11Sym++) {
0131 
0132         mapping.append(KeyMapping(x11Sym, Qt::Key(qtKey)));
0133     }
0134 
0135     for (int qtKey = Qt::Key_A, x11Sym = XK_a;
0136          qtKey <= Qt::Key_Z;
0137          qtKey++, x11Sym++) {
0138 
0139         mapping.append(KeyMapping(x11Sym, Qt::Key(qtKey)));
0140     }
0141 }
0142 
0143 bool KisExtendedModifiersMapper::Private::checkKeyCodePressedX11(KeyCode key)
0144 {
0145     int byte = key / 8;
0146     char mask = 1 << (key % 8);
0147 
0148     return keysState[byte] & mask;
0149 }
0150 
0151 bool KisExtendedModifiersMapper::Private::checkKeySymPressedX11(KeySym sym)
0152 {
0153     KeyCode key = XKeysymToKeycode(QX11Info::display(), sym);
0154     return key != 0 ? checkKeyCodePressedX11(key) : false;
0155 }
0156 
0157 #else /* HAVE_X11 */
0158 
0159 KisExtendedModifiersMapper::Private::Private()
0160 {
0161 }
0162 
0163 #endif /* HAVE_X11 */
0164 
0165 
0166 KisExtendedModifiersMapper::KisExtendedModifiersMapper()
0167     : m_d(new Private)
0168 {
0169 }
0170 
0171 KisExtendedModifiersMapper::~KisExtendedModifiersMapper()
0172 {
0173 }
0174 
0175 #ifdef Q_OS_MACOS
0176 void KisExtendedModifiersMapper::setLocalMonitor(bool activate, KisShortcutMatcher *matcher)
0177 {
0178     Q_UNUSED(matcher);
0179     activateLocalMonitor(activate);
0180 }
0181 #endif
0182 
0183 KisExtendedModifiersMapper::ExtendedModifiers
0184 KisExtendedModifiersMapper::queryExtendedModifiers()
0185 {
0186     ExtendedModifiers modifiers;
0187 
0188 #ifdef HAVE_X11
0189 
0190     {
0191         for (int keyCode = m_d->minKeyCode; keyCode <= m_d->maxKeyCode; keyCode++) {
0192             if (m_d->checkKeyCodePressedX11(keyCode)) {
0193 
0194                 KeySym sym = XkbKeycodeToKeysym(QX11Info::display(), keyCode,
0195                                                 0, 0);
0196                 Q_FOREACH (const KeyMapping &map, m_d->mapping) {
0197                     if (map.x11KeySym == sym) {
0198                         modifiers << map.qtKey;
0199                         break;
0200                     }
0201                 }
0202             }
0203         }
0204     }
0205 
0206     // in X11 some keys may have multiple keysyms,
0207     // (Alt Key == XK_Meta_{L,R}, XK_Meta_{L,R})
0208     KritaUtils::makeContainerUnique(modifiers);
0209 
0210 #elif defined Q_OS_WIN
0211 
0212     modifiers = queryPressedKeysWin();
0213 
0214 #elif defined Q_OS_MACOS
0215     modifiers = queryPressedKeysMac();
0216 #else
0217 
0218     Qt::KeyboardModifiers standardModifiers = queryStandardModifiers();
0219 
0220     if (standardModifiers & Qt::ShiftModifier) {
0221         modifiers << Qt::Key_Shift;
0222     }
0223 
0224     if (standardModifiers & Qt::ControlModifier) {
0225         modifiers << Qt::Key_Control;
0226     }
0227 
0228     if (standardModifiers & Qt::AltModifier) {
0229         modifiers << Qt::Key_Alt;
0230     }
0231 
0232     if (standardModifiers & Qt::MetaModifier) {
0233         modifiers << Qt::Key_Meta;
0234     }
0235 
0236 #endif
0237 
0238     return modifiers;
0239 }
0240 
0241 Qt::KeyboardModifiers KisExtendedModifiersMapper::queryStandardModifiers()
0242 {
0243     return QApplication::queryKeyboardModifiers();
0244 }
0245 
0246 Qt::Key KisExtendedModifiersMapper::workaroundShiftAltMetaHell(const QKeyEvent *keyEvent)
0247 {
0248     Qt::Key key = (Qt::Key)keyEvent->key();
0249 
0250     if (keyEvent->key() == Qt::Key_Meta &&
0251         keyEvent->modifiers().testFlag(Qt::ShiftModifier)) {
0252 
0253         key = Qt::Key_Alt;
0254     }
0255 
0256     return key;
0257 }