File indexing completed on 2024-05-05 05:00:43

0001 /*
0002    This file is part of the KDE project
0003 
0004    Copyright (C) 2016 by Oleg Chernovskiy <kanedias@xaker.ru>
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This program is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    General Public License for more details.
0015 
0016    You should have received a copy of the GNU General Public License
0017    along with this program; see the file COPYING.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019    Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "x11events.h"
0023 
0024 #include <QApplication>
0025 #include <QGlobalStatic>
0026 #include <QtGui/private/qtx11extras_p.h>
0027 
0028 #include <X11/Xutil.h>
0029 #include <X11/keysym.h>
0030 #include <X11/extensions/XTest.h>
0031 
0032 enum {
0033     LEFTSHIFT = 1,
0034     RIGHTSHIFT = 2,
0035     ALTGR = 4
0036 };
0037 
0038 class EventData
0039 {
0040 public:
0041     EventData();
0042 
0043     //keyboard
0044     Display *dpy = nullptr;
0045     signed char modifiers[0x100] = {};
0046     KeyCode keycodes[0x100] = {};
0047     KeyCode leftShiftCode = 0;
0048     KeyCode rightShiftCode = 0;
0049     KeyCode altGrCode = 0;
0050     char modifierState = 0;
0051 
0052     //mouse
0053     int buttonMask = 0;
0054     int x = 0;
0055     int y = 0;
0056 
0057 private:
0058     void init();
0059 };
0060 
0061 Q_GLOBAL_STATIC(EventData, data)
0062 
0063 EventData::EventData()
0064 {
0065     init();
0066 }
0067 
0068 void EventData::init()
0069 {
0070     buttonMask = 0;
0071 
0072     dpy = QX11Info::display();
0073     //initialize keycodes
0074     KeySym key, *keymap;
0075     int i, j, minkey, maxkey, syms_per_keycode;
0076 
0077     memset(modifiers, -1, sizeof(modifiers));
0078 
0079     XDisplayKeycodes(dpy, &minkey, &maxkey);
0080     Q_ASSERT(minkey >= 8);
0081     Q_ASSERT(maxkey < 256);
0082     keymap = (KeySym *) XGetKeyboardMapping(dpy, minkey,
0083                                             (maxkey - minkey + 1),
0084                                             &syms_per_keycode);
0085     Q_ASSERT(keymap);
0086 
0087     for (i = minkey; i <= maxkey; i++) {
0088         for (j = 0; j < syms_per_keycode; j++) {
0089             key = keymap[(i-minkey)*syms_per_keycode+j];
0090 
0091             if (key >= ' ' && key < 0x100 && i == XKeysymToKeycode(dpy, key)) {
0092                 keycodes[key] = i;
0093                 modifiers[key] = j;
0094             }
0095         }
0096     }
0097 
0098     leftShiftCode = XKeysymToKeycode(dpy, XK_Shift_L);
0099     rightShiftCode = XKeysymToKeycode(dpy, XK_Shift_R);
0100     altGrCode = XKeysymToKeycode(dpy, XK_Mode_switch);
0101 
0102     XFree((char *)keymap);
0103 }
0104 
0105 /* this function adjusts the modifiers according to mod (as from modifiers) and data->modifierState */
0106 static void tweakModifiers(signed char mod, bool down)
0107 {
0108     bool isShift = data->modifierState & (LEFTSHIFT | RIGHTSHIFT);
0109 
0110     if (mod < 0) {
0111         return;
0112     }
0113 
0114     if (isShift && mod != 1) {
0115         if (data->modifierState & LEFTSHIFT) {
0116             XTestFakeKeyEvent(data->dpy, data->leftShiftCode,
0117                               down, CurrentTime);
0118         }
0119 
0120         if (data->modifierState & RIGHTSHIFT) {
0121             XTestFakeKeyEvent(data->dpy, data->rightShiftCode,
0122                               down, CurrentTime);
0123         }
0124     }
0125 
0126     if (!isShift && mod == 1) {
0127         XTestFakeKeyEvent(data->dpy, data->leftShiftCode,
0128                           down, CurrentTime);
0129     }
0130 
0131     if ((data->modifierState & ALTGR) && mod != 2) {
0132         XTestFakeKeyEvent(data->dpy, data->altGrCode,
0133                           !down, CurrentTime);
0134     }
0135 
0136     if (!(data->modifierState & ALTGR) && mod == 2) {
0137         XTestFakeKeyEvent(data->dpy, data->altGrCode,
0138                           down, CurrentTime);
0139     }
0140 }
0141 
0142 void X11EventHandler::handleKeyboard(bool down, rfbKeySym keySym)
0143 {
0144 #define ADJUSTMOD(sym,state) \
0145     if(keySym==sym) { if(down) data->modifierState|=state; else data->modifierState&=~state; }
0146 
0147     if (QX11Info::isPlatformX11()) {
0148         ADJUSTMOD(XK_Shift_L, LEFTSHIFT);
0149         ADJUSTMOD(XK_Shift_R, RIGHTSHIFT);
0150         ADJUSTMOD(XK_Mode_switch, ALTGR);
0151 
0152         if (keySym >= ' ' && keySym < 0x100) {
0153             KeyCode k;
0154 
0155             if (down) {
0156                 tweakModifiers(data->modifiers[keySym], True);
0157             }
0158 
0159             k = data->keycodes[keySym];
0160 
0161             if (k != NoSymbol) {
0162                 XTestFakeKeyEvent(data->dpy, k, down, CurrentTime);
0163             }
0164 
0165             if (down) {
0166                 tweakModifiers(data->modifiers[keySym], False);
0167             }
0168         } else {
0169             KeyCode k = XKeysymToKeycode(data->dpy, keySym);
0170 
0171             if (k != NoSymbol) {
0172                 XTestFakeKeyEvent(data->dpy, k, down, CurrentTime);
0173             }
0174         }
0175     }
0176 /*
0177     // Wayland platform and pipweire plugin in use
0178     if (KrfbConfig::preferredFrameBufferPlugin() == QStringLiteral("pw")) {
0179 
0180     }*/
0181 }
0182 
0183 void X11EventHandler::handlePointer(int buttonMask, int x, int y)
0184 {
0185     if (QX11Info::isPlatformX11()) {
0186         XTestFakeMotionEvent(data->dpy, 0, x, y, CurrentTime);
0187 
0188         for (int i = 0; i < 5; i++) {
0189             if ((data->buttonMask&(1 << i)) != (buttonMask&(1 << i))) {
0190                 XTestFakeButtonEvent(data->dpy,
0191                                         i + 1,
0192                                         (buttonMask&(1 << i)) ? True : False,
0193                                         CurrentTime);
0194             }
0195         }
0196 
0197         data->buttonMask = buttonMask;
0198     }
0199 }