Rabbit Remote Control 0.0.30
Loading...
Searching...
No Matches
InputDeviceXLib.cpp
1// Author: Kang Lin <kl222@126.com>
2
3// 参考: https://github.com/KangLin/Documents/blob/master/os/Keyboard.md
4
5#include <QLoggingCategory>
6#include <X11/X.h>
7#include <X11/Xlib.h>
8#include <X11/Xutil.h>
9#ifdef HAVE_XTEST
10#include <X11/extensions/XTest.h>
11#endif
12#include "InputDeviceXLib.h"
13
14Q_LOGGING_CATEGORY(LogInput, "Device.Input")
15
16QSharedPointer<CInputDevice> CInputDevice::GenerateObject()
17{
18 return QSharedPointer<CInputDevice>(new CInputDeviceXLib());
19}
20
21CInputDeviceXLib::CInputDeviceXLib() : CInputDevice(),
22 rawKeyboard(false)
23{
24}
25
26CInputDeviceXLib::~CInputDeviceXLib()
27{
28 qDebug(LogInput) << "CInputDeviceXLib::~CInputDeviceXLib()";
29}
30
31#ifdef HAVE_XTEST
32KeyCode CInputDeviceXLib::XkbKeysymToKeycode(Display* dpy, KeySym keysym) {
33 XkbDescPtr xkb;
34 XkbStateRec state;
35 unsigned int mods;
36 unsigned keycode;
37
38 xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
39 if (!xkb)
40 return 0;
41
42 XkbGetState(dpy, XkbUseCoreKbd, &state);
43 // XkbStateFieldFromRec() doesn't work properly because
44 // state.lookup_mods isn't properly updated, so we do this manually
45 mods = XkbBuildCoreState(XkbStateMods(&state), state.group);
46
47 for (keycode = xkb->min_key_code;
48 keycode <= xkb->max_key_code;
49 keycode++) {
50 KeySym cursym;
51 unsigned int out_mods;
52 XkbTranslateKeyCode(xkb, keycode, mods, &out_mods, &cursym);
53 if (cursym == keysym)
54 break;
55 }
56
57 if (keycode > xkb->max_key_code)
58 keycode = 0;
59
60 XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);
61
62 // Shift+Tab is usually ISO_Left_Tab, but RFB hides this fact. Do
63 // another attempt if we failed the initial lookup
64 if ((keycode == 0) && (keysym == XK_Tab) && (mods & ShiftMask))
65 return XkbKeysymToKeycode(dpy, XK_ISO_Left_Tab);
66
67 return keycode;
68}
69#endif
70
71int CInputDeviceXLib::KeyEvent(quint32 keysym, quint32 xtcode, bool down)
72{
73 int nRet = 0;
74
75 int keycode = 0;
76
77#ifdef HAVE_XTEST
78 Display *display = XOpenDisplay(NULL);
79 do {
80 // Use scan code if provided and mapping exists
81 if (codeMap && rawKeyboard && xtcode < codeMapLen)
82 keycode = codeMap[xtcode];
83
84 if (!keycode) {
85 if (pressedKeys.find(keysym) != pressedKeys.end())
86 keycode = pressedKeys[keysym];
87 else {
88 // XKeysymToKeycode() doesn't respect state, so we have to use
89 // something slightly more complex
90 keycode = XkbKeysymToKeycode(display, keysym);
91 }
92 }
93
94 if (!keycode) {
95 qCritical(LogInput) << "Could not map key event to X11 key code";
96 nRet = -2;
97 break;
98 }
99
100 if (down)
101 pressedKeys[keysym] = keycode;
102 else
103 pressedKeys.erase(keysym);
104
105 qDebug(LogInput, "%d %s", keycode, down ? "down" : "up");
106
107 XTestFakeKeyEvent(display, keycode, down, CurrentTime);
108 } while(0);
109 XCloseDisplay(display);
110#endif
111
112 return 0;
113}
114
115// Simulate mouse click
116void click(Display *display, int button, bool press)
117{
118#ifdef HAVE_XTEST
119 XTestFakeButtonEvent(display, button, press, CurrentTime);
120#else
121 // Create and setting up the event
122 XEvent event;
123 memset (&event, 0, sizeof (event));
124 event.xbutton.button = button;
125 event.xbutton.same_screen = True;
126 event.xbutton.subwindow = DefaultRootWindow (display);
127 while (event.xbutton.subwindow)
128 {
129 event.xbutton.window = event.xbutton.subwindow;
130 XQueryPointer (display, event.xbutton.window,
131 &event.xbutton.root, &event.xbutton.subwindow,
132 &event.xbutton.x_root, &event.xbutton.y_root,
133 &event.xbutton.x, &event.xbutton.y,
134 &event.xbutton.state);
135 }
136 // Press
137 if(press)
138 {
139 event.type = ButtonPress;
140 if (XSendEvent (display, PointerWindow, True, ButtonPressMask, &event) == 0)
141 fprintf (stderr, "Error to send the event!\n");
142 } else {
143 if (XSendEvent (display, PointerWindow, True, ButtonReleaseMask, &event) == 0)
144 fprintf (stderr, "Error to send the event!\n");
145 XFlush (display);
146 }
147 XFlush (display);
148#endif
149}
150
151// Get mouse coordinates
152void coords (Display *display, int *x, int *y)
153{
154 XEvent event;
155 XQueryPointer (display, DefaultRootWindow (display),
156 &event.xbutton.root, &event.xbutton.window,
157 &event.xbutton.x_root, &event.xbutton.y_root,
158 &event.xbutton.x, &event.xbutton.y,
159 &event.xbutton.state);
160 *x = event.xbutton.x;
161 *y = event.xbutton.y;
162}
163
164// Move mouse pointer (relative)
165void move (Display *display, int x, int y)
166{
167 XWarpPointer (display, None, None, 0,0,0,0, x, y);
168 XFlush (display);
169
170}
171
172// Move mouse pointer (absolute)
173void move_to (Display *display, int x, int y)
174{
175 int cur_x, cur_y;
176 coords (display, &cur_x, &cur_y);
177 XWarpPointer (display, None, None, 0,0,0,0, -cur_x, -cur_y);
178 XWarpPointer (display, None, None, 0,0,0,0, x, y);
179}
180
181// Get pixel color at coordinates x,y
182//void
183//pixel_color (Display *display, int x, int y, XColor *color)
184//{
185// XImage *image;
186// image = XGetImage (display, DefaultRootWindow (display), x, y, 1, 1, AllPlanes, XYPixmap);
187// color->pixel = XGetPixel (image, 0, 0);
188// XDestroyImage (image);
189// XQueryColor (display, DefaultColormap(display, DefaultScreen (display)), color);
190//}
191
192int CInputDeviceXLib::MouseEvent(MouseButtons buttons, QPoint pos)
193{
194 Display *display = XOpenDisplay(NULL);
195 if(display == NULL)
196 {
197 qCritical(LogInput) << "Open display fail";
198 return -1;
199 }
200 Window root = DefaultRootWindow(display);
201
202 // - Has the pointer moved since the last event?
203 if (m_LastPostion != pos)
204#ifdef HAVE_XTEST
205 XTestFakeMotionEvent(display, DefaultScreen(display),
206 pos.x(),
207 pos.y(),
208 CurrentTime);
209#else
210 XWarpPointer (display, root, root, 0, 0, 0, 0, pos.x(), pos.y());
211#endif
212
213 // Check the left button on change state
214 if((m_LastButtons & LeftButton) != (LeftButton & buttons))
215 {
216 if(buttons & LeftButton)
217 click(display, Button1, true);
218 else
219 click(display, Button1, false);
220 }
221
222 // Check the middle button on change state
223 if((m_LastButtons & MiddleButton) != (MiddleButton & buttons))
224 {
225 if(buttons & MiddleButton)
226 click(display, Button2, true);
227 else
228 click(display, Button2, false);
229 }
230
231 // Check the right button on change state
232 if((m_LastButtons & RightButton) != (RightButton & buttons))
233 {
234 if(buttons & RightButton)
235 click(display, Button3, true);
236 else
237 click(display, Button3, false);
238 }
239 m_LastButtons = buttons;
240 XCloseDisplay(display);
241 return 0;
242}
243
244int CInputDeviceXLib::MouseEvent(MouseButtons buttons, int x, int y)
245{
246 return MouseEvent(buttons, QPoint(x, y));
247}