Skip to content

Commit 8df26c2

Browse files
author
aigilea
committed
Add the missing wayland autotype plugin
1 parent 1ade5c2 commit 8df26c2

File tree

3 files changed

+375
-0
lines changed

3 files changed

+375
-0
lines changed
Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
/*
2+
* Copyright (C) 2024 KeePassXC Team <[email protected]>
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 2 or (at your option)
7+
* version 3 of the License.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#include "AutoTypeWayland.h"
19+
20+
#include <QDBusInterface>
21+
#include <QDBusMessage>
22+
#include <QDebug>
23+
24+
#include <QJsonObject>
25+
#include <QJsonArray>
26+
#include <QJsonDocument>
27+
28+
#include "autotype/AutoTypeAction.h"
29+
#include "core/Tools.h"
30+
#include "gui/osutils/nixutils/X11Funcs.h"
31+
32+
#include <fcntl.h>
33+
#include <unistd.h>
34+
35+
#include <linux/uinput.h>
36+
37+
// taken from ydotool
38+
#define FLAG_UPPERCASE 0x00010000
39+
40+
static const int _enable_keys[] = {KEY_ESC, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_TAB, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_ENTER, KEY_LEFTCTRL, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_LEFTSHIFT, KEY_BACKSLASH, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, KEY_COMMA, KEY_DOT, KEY_SLASH, KEY_RIGHTSHIFT, KEY_KPASTERISK, KEY_LEFTALT, KEY_SPACE, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_NUMLOCK, KEY_SCROLLLOCK, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KPMINUS, KEY_KP4, KEY_KP5, KEY_KP6, KEY_KPPLUS, KEY_KP1, KEY_KP2, KEY_KP3, KEY_KP0, KEY_KPDOT, KEY_ZENKAKUHANKAKU, KEY_102ND, KEY_F11, KEY_F12, KEY_RO, KEY_KATAKANA, KEY_HIRAGANA, KEY_HENKAN, KEY_KATAKANAHIRAGANA, KEY_MUHENKAN, KEY_KPJPCOMMA, KEY_KPENTER, KEY_RIGHTCTRL, KEY_KPSLASH, KEY_SYSRQ, KEY_RIGHTALT, KEY_LINEFEED, KEY_HOME, KEY_UP, KEY_PAGEUP, KEY_LEFT, KEY_RIGHT, KEY_END, KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, KEY_MACRO, KEY_MUTE, KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_POWER, KEY_KPEQUAL, KEY_KPPLUSMINUS, KEY_PAUSE, KEY_SCALE, KEY_KPCOMMA, KEY_HANGEUL, KEY_HANGUEL, KEY_HANJA, KEY_YEN, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, KEY_STOP, KEY_AGAIN, KEY_PROPS, KEY_UNDO, KEY_FRONT, KEY_COPY, KEY_OPEN, KEY_PASTE, KEY_FIND, KEY_CUT, KEY_HELP, KEY_MENU, KEY_CALC, KEY_SETUP, KEY_SLEEP, KEY_WAKEUP, KEY_FILE, KEY_SENDFILE, KEY_DELETEFILE, KEY_XFER, KEY_PROG1, KEY_PROG2, KEY_WWW, KEY_MSDOS, KEY_COFFEE, KEY_SCREENLOCK, KEY_ROTATE_DISPLAY, KEY_DIRECTION, KEY_CYCLEWINDOWS, KEY_MAIL, KEY_BOOKMARKS, KEY_COMPUTER, KEY_BACK, KEY_FORWARD, KEY_CLOSECD, KEY_EJECTCD, KEY_EJECTCLOSECD, KEY_NEXTSONG, KEY_PLAYPAUSE, KEY_PREVIOUSSONG, KEY_STOPCD, KEY_RECORD, KEY_REWIND, KEY_PHONE, KEY_ISO, KEY_CONFIG, KEY_HOMEPAGE, KEY_REFRESH, KEY_EXIT, KEY_MOVE, KEY_EDIT, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_KPLEFTPAREN, KEY_KPRIGHTPAREN, KEY_NEW, KEY_REDO, KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_PLAYCD, KEY_PAUSECD, KEY_PROG3, KEY_PROG4, KEY_DASHBOARD, KEY_SUSPEND, KEY_CLOSE, KEY_PLAY, KEY_FASTFORWARD, KEY_BASSBOOST, KEY_PRINT, KEY_HP, KEY_CAMERA, KEY_SOUND, KEY_QUESTION, KEY_EMAIL, KEY_CHAT, KEY_SEARCH, KEY_CONNECT, KEY_FINANCE, KEY_SPORT, KEY_SHOP, KEY_ALTERASE, KEY_CANCEL, KEY_BRIGHTNESSDOWN, KEY_BRIGHTNESSUP, KEY_MEDIA, KEY_SWITCHVIDEOMODE, KEY_KBDILLUMTOGGLE, KEY_KBDILLUMDOWN, KEY_KBDILLUMUP, KEY_SEND, KEY_REPLY, KEY_FORWARDMAIL, KEY_SAVE, KEY_DOCUMENTS, KEY_BATTERY, KEY_BLUETOOTH, KEY_WLAN, KEY_UWB, KEY_UNKNOWN, KEY_VIDEO_NEXT, KEY_VIDEO_PREV, KEY_BRIGHTNESS_CYCLE, KEY_BRIGHTNESS_AUTO, KEY_BRIGHTNESS_ZERO, KEY_DISPLAY_OFF, KEY_WWAN, KEY_WIMAX, KEY_RFKILL, KEY_MICMUTE, KEY_OK, KEY_SELECT, KEY_GOTO, KEY_CLEAR, KEY_POWER2, KEY_OPTION, KEY_INFO, KEY_TIME, KEY_VENDOR, KEY_ARCHIVE, KEY_PROGRAM, KEY_CHANNEL, KEY_FAVORITES, KEY_EPG, KEY_PVR, KEY_MHP, KEY_LANGUAGE, KEY_TITLE, KEY_SUBTITLE, KEY_ANGLE, KEY_ZOOM, KEY_MODE, KEY_KEYBOARD, KEY_SCREEN, KEY_PC, KEY_TV, KEY_TV2, KEY_VCR, KEY_VCR2, KEY_SAT, KEY_SAT2, KEY_CD, KEY_TAPE, KEY_RADIO, KEY_TUNER, KEY_PLAYER, KEY_TEXT, KEY_DVD, KEY_AUX, KEY_MP3, KEY_AUDIO, KEY_VIDEO, KEY_DIRECTORY, KEY_LIST, KEY_MEMO, KEY_CALENDAR, KEY_RED, KEY_GREEN, KEY_YELLOW, KEY_BLUE, KEY_CHANNELUP, KEY_CHANNELDOWN, KEY_FIRST, KEY_LAST, KEY_AB, KEY_NEXT, KEY_RESTART, KEY_SLOW, KEY_SHUFFLE, KEY_BREAK, KEY_PREVIOUS, KEY_DIGITS, KEY_TEEN, KEY_TWEN, KEY_VIDEOPHONE, KEY_GAMES, KEY_ZOOMIN, KEY_ZOOMOUT, KEY_ZOOMRESET, KEY_WORDPROCESSOR, KEY_EDITOR, KEY_SPREADSHEET, KEY_GRAPHICSEDITOR, KEY_PRESENTATION, KEY_DATABASE, KEY_NEWS, KEY_VOICEMAIL, KEY_ADDRESSBOOK, KEY_MESSENGER, KEY_DISPLAYTOGGLE, KEY_BRIGHTNESS_TOGGLE, KEY_SPELLCHECK, KEY_LOGOFF, KEY_DOLLAR, KEY_EURO, KEY_FRAMEBACK, KEY_FRAMEFORWARD, KEY_CONTEXT_MENU, KEY_MEDIA_REPEAT, KEY_10CHANNELSUP, KEY_10CHANNELSDOWN, KEY_IMAGES, KEY_DEL_EOL, KEY_DEL_EOS, KEY_INS_LINE, KEY_DEL_LINE, KEY_FN, KEY_FN_ESC, KEY_FN_F1, KEY_FN_F2, KEY_FN_F3, KEY_FN_F4, KEY_FN_F5, KEY_FN_F6, KEY_FN_F7, KEY_FN_F8, KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_FN_F12, KEY_FN_1, KEY_FN_2, KEY_FN_D, KEY_FN_E, KEY_FN_F, KEY_FN_S, KEY_FN_B, KEY_BRL_DOT1, KEY_BRL_DOT2, KEY_BRL_DOT3, KEY_BRL_DOT4, KEY_BRL_DOT5, KEY_BRL_DOT6, KEY_BRL_DOT7, KEY_BRL_DOT8, KEY_BRL_DOT9, KEY_BRL_DOT10, KEY_NUMERIC_0, KEY_NUMERIC_1, KEY_NUMERIC_2, KEY_NUMERIC_3, KEY_NUMERIC_4, KEY_NUMERIC_5, KEY_NUMERIC_6, KEY_NUMERIC_7, KEY_NUMERIC_8, KEY_NUMERIC_9, KEY_NUMERIC_STAR, KEY_NUMERIC_POUND, KEY_NUMERIC_A, KEY_NUMERIC_B, KEY_NUMERIC_C, KEY_NUMERIC_D, KEY_CAMERA_FOCUS, KEY_WPS_BUTTON, KEY_TOUCHPAD_TOGGLE, KEY_TOUCHPAD_ON, KEY_TOUCHPAD_OFF, KEY_CAMERA_ZOOMIN, KEY_CAMERA_ZOOMOUT, KEY_CAMERA_UP, KEY_CAMERA_DOWN, KEY_CAMERA_LEFT, KEY_CAMERA_RIGHT, KEY_ATTENDANT_ON, KEY_ATTENDANT_OFF, KEY_ATTENDANT_TOGGLE, KEY_LIGHTS_TOGGLE, KEY_ALS_TOGGLE, KEY_BUTTONCONFIG, KEY_TASKMANAGER, KEY_JOURNAL, KEY_CONTROLPANEL, KEY_APPSELECT, KEY_SCREENSAVER, KEY_VOICECOMMAND, KEY_BRIGHTNESS_MIN, KEY_BRIGHTNESS_MAX, KEY_KBDINPUTASSIST_PREV, KEY_KBDINPUTASSIST_NEXT, KEY_KBDINPUTASSIST_PREVGROUP, KEY_KBDINPUTASSIST_NEXTGROUP, KEY_KBDINPUTASSIST_ACCEPT, KEY_KBDINPUTASSIST_CANCEL, KEY_RIGHT_UP, KEY_RIGHT_DOWN, KEY_LEFT_UP, KEY_LEFT_DOWN, KEY_ROOT_MENU, KEY_MEDIA_TOP_MENU, KEY_NUMERIC_11, KEY_NUMERIC_12, KEY_AUDIO_DESC, KEY_3D_MODE, KEY_NEXT_FAVORITE, KEY_STOP_RECORD, KEY_PAUSE_RECORD, KEY_VOD, KEY_UNMUTE, KEY_FASTREVERSE, KEY_SLOWREVERSE, KEY_DATA, KEY_MIN_INTERESTING, BTN_MISC, BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8, BTN_9, BTN_MOUSE, BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, BTN_SIDE, BTN_EXTRA, BTN_FORWARD, BTN_BACK, BTN_TASK, BTN_JOYSTICK, BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_PINKIE, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_BASE6, BTN_DEAD, BTN_GAMEPAD, BTN_SOUTH, BTN_A, BTN_EAST, BTN_B, BTN_C, BTN_NORTH, BTN_X, BTN_WEST, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_THUMBL, BTN_THUMBR, BTN_DIGI, BTN_TOOL_PEN, BTN_TOOL_RUBBER, BTN_TOOL_BRUSH, BTN_TOOL_PENCIL, BTN_TOOL_AIRBRUSH, BTN_TOOL_FINGER, BTN_TOOL_MOUSE, BTN_TOOL_LENS, BTN_TOOL_QUINTTAP, BTN_TOUCH, BTN_STYLUS, BTN_STYLUS2, BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP, BTN_TOOL_QUADTAP, BTN_WHEEL, BTN_GEAR_DOWN, BTN_GEAR_UP, BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT, BTN_TRIGGER_HAPPY, BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY2, BTN_TRIGGER_HAPPY3, BTN_TRIGGER_HAPPY4, BTN_TRIGGER_HAPPY5, BTN_TRIGGER_HAPPY6, BTN_TRIGGER_HAPPY7, BTN_TRIGGER_HAPPY8, BTN_TRIGGER_HAPPY9, BTN_TRIGGER_HAPPY10, BTN_TRIGGER_HAPPY11, BTN_TRIGGER_HAPPY12, BTN_TRIGGER_HAPPY13, BTN_TRIGGER_HAPPY14, BTN_TRIGGER_HAPPY15, BTN_TRIGGER_HAPPY16, BTN_TRIGGER_HAPPY17, BTN_TRIGGER_HAPPY18, BTN_TRIGGER_HAPPY19, BTN_TRIGGER_HAPPY20, BTN_TRIGGER_HAPPY21, BTN_TRIGGER_HAPPY22, BTN_TRIGGER_HAPPY23, BTN_TRIGGER_HAPPY24, BTN_TRIGGER_HAPPY25, BTN_TRIGGER_HAPPY26, BTN_TRIGGER_HAPPY27, BTN_TRIGGER_HAPPY28, BTN_TRIGGER_HAPPY29, BTN_TRIGGER_HAPPY30, BTN_TRIGGER_HAPPY31, BTN_TRIGGER_HAPPY32, BTN_TRIGGER_HAPPY33, BTN_TRIGGER_HAPPY34, BTN_TRIGGER_HAPPY35, BTN_TRIGGER_HAPPY36, BTN_TRIGGER_HAPPY37, BTN_TRIGGER_HAPPY38, BTN_TRIGGER_HAPPY39, BTN_TRIGGER_HAPPY40};
41+
static const struct uinput_setup _usetup = {.id = {.bustype = BUS_VIRTUAL, .vendor = 0xDEAD, .product = 0xBEEF, .version = 1}, .name = "keepassxc virtual device"};
42+
static const int _ascii2keycode_map[128] = {
43+
-1,-1,-1,-1,-1,-1,-1,-1,
44+
-1,KEY_TAB,KEY_ENTER,-1,-1,-1,-1,-1,
45+
-1,-1,-1,-1,-1,-1,-1,-1,
46+
-1,-1,-1,-1,-1,-1,-1,-1,
47+
KEY_SPACE,KEY_1|FLAG_UPPERCASE,KEY_APOSTROPHE|FLAG_UPPERCASE,KEY_3|FLAG_UPPERCASE,KEY_4|FLAG_UPPERCASE,KEY_5|FLAG_UPPERCASE,KEY_7|FLAG_UPPERCASE,KEY_APOSTROPHE,
48+
KEY_9|FLAG_UPPERCASE,KEY_0|FLAG_UPPERCASE,KEY_8|FLAG_UPPERCASE,KEY_EQUAL|FLAG_UPPERCASE,KEY_COMMA,KEY_MINUS,KEY_DOT,KEY_SLASH,
49+
KEY_0,KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,
50+
KEY_8,KEY_9,KEY_SEMICOLON|FLAG_UPPERCASE,KEY_SEMICOLON,KEY_COMMA|FLAG_UPPERCASE,KEY_EQUAL,KEY_DOT|FLAG_UPPERCASE,KEY_SLASH|FLAG_UPPERCASE,
51+
KEY_2|FLAG_UPPERCASE,KEY_A|FLAG_UPPERCASE,KEY_B|FLAG_UPPERCASE,KEY_C|FLAG_UPPERCASE,KEY_D|FLAG_UPPERCASE,KEY_E|FLAG_UPPERCASE,KEY_F|FLAG_UPPERCASE,KEY_G|FLAG_UPPERCASE,
52+
KEY_H|FLAG_UPPERCASE,KEY_I|FLAG_UPPERCASE,KEY_J|FLAG_UPPERCASE,KEY_K|FLAG_UPPERCASE,KEY_L|FLAG_UPPERCASE,KEY_M|FLAG_UPPERCASE,KEY_N|FLAG_UPPERCASE,KEY_O|FLAG_UPPERCASE,
53+
KEY_P|FLAG_UPPERCASE,KEY_Q|FLAG_UPPERCASE,KEY_R|FLAG_UPPERCASE,KEY_S|FLAG_UPPERCASE,KEY_T|FLAG_UPPERCASE,KEY_U|FLAG_UPPERCASE,KEY_V|FLAG_UPPERCASE,KEY_W|FLAG_UPPERCASE,
54+
KEY_X|FLAG_UPPERCASE,KEY_Y|FLAG_UPPERCASE,KEY_Z|FLAG_UPPERCASE,KEY_LEFTBRACE,KEY_BACKSLASH,KEY_RIGHTBRACE,KEY_6|FLAG_UPPERCASE,KEY_MINUS|FLAG_UPPERCASE,
55+
KEY_GRAVE,KEY_A,KEY_B,KEY_C,KEY_D,KEY_E,KEY_F,KEY_G,
56+
KEY_H,KEY_I,KEY_J,KEY_K,KEY_L,KEY_M,KEY_N,KEY_O,
57+
KEY_P,KEY_Q,KEY_R,KEY_S,KEY_T,KEY_U,KEY_V,KEY_W,
58+
KEY_X,KEY_Y,KEY_Z,KEY_LEFTBRACE|FLAG_UPPERCASE,KEY_BACKSLASH|FLAG_UPPERCASE,KEY_RIGHTBRACE|FLAG_UPPERCASE,KEY_GRAVE|FLAG_UPPERCASE,-1
59+
};
60+
61+
62+
AutoTypePlatformWayland::AutoTypePlatformWayland()
63+
{
64+
uifd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
65+
ioctl(uifd, UI_SET_EVBIT, EV_KEY);
66+
for (size_t i = 0; i < sizeof(_enable_keys) / sizeof(int); i++)
67+
{
68+
ioctl(uifd, UI_SET_KEYBIT, _enable_keys[i]);
69+
}
70+
ioctl(uifd, UI_DEV_SETUP, &_usetup);
71+
ioctl(uifd, UI_DEV_CREATE);
72+
}
73+
74+
void AutoTypePlatformWayland::sendUiKey(uint16_t code, int32_t value)
75+
{
76+
input_event ie {};
77+
ie.type = EV_KEY;
78+
ie.code = code;
79+
ie.value = value;
80+
write(uifd, &ie, sizeof(ie));
81+
ie.type = EV_SYN;
82+
ie.code = SYN_REPORT;
83+
ie.value = 0;
84+
write(uifd, &ie, sizeof(ie));
85+
}
86+
87+
bool AutoTypePlatformWayland::isAvailable()
88+
{
89+
return true;
90+
}
91+
92+
void AutoTypePlatformWayland::unload()
93+
{
94+
ioctl(uifd, UI_DEV_DESTROY);
95+
close(uifd);
96+
}
97+
98+
QString AutoTypePlatformWayland::activeWindowTitle()
99+
{
100+
// Ask focused-window-dbus extension nicely
101+
// https://extensions.gnome.org/extension/5592/focused-window-d-bus/
102+
// https://github.com/flexagoon/focused-window-dbus
103+
QDBusMessage reply = QDBusConnection::sessionBus().call(QDBusMessage::createMethodCall("org.gnome.Shell", "/org/gnome/shell/extensions/FocusedWindow", "org.gnome.shell.extensions.FocusedWindow", "Get"));
104+
if (reply.type() == QDBusMessage::ReplyMessage)
105+
{
106+
QString strReply = reply.arguments().at(0).toString();
107+
QJsonParseError parseError;
108+
QJsonDocument jsonReply = QJsonDocument::fromJson(strReply.toUtf8(), &parseError);
109+
if (parseError.error == QJsonParseError::NoError)
110+
{
111+
QJsonObject jsonData = jsonReply.object();
112+
if (jsonData.contains("title"))
113+
{
114+
return jsonData["title"].toString();
115+
}
116+
else
117+
{
118+
qWarning() << "AutoTypePlatformWayland::activeWindowTitle() no title in reply " << strReply;
119+
}
120+
}
121+
else
122+
{
123+
qWarning() << "AutoTypePlatformWayland::activeWindowTitle() got error " << parseError.errorString() << " parsing reply " << strReply;
124+
}
125+
}
126+
else
127+
{
128+
qWarning() << "AutoTypePlatformWayland::activeWindowTitle() got unexpected reply (no FocusedWindow extension present?): " << reply;
129+
}
130+
131+
return {};
132+
}
133+
134+
WId AutoTypePlatformWayland::activeWindow()
135+
{
136+
return 0;
137+
}
138+
139+
AutoTypeExecutor* AutoTypePlatformWayland::createExecutor()
140+
{
141+
return new AutoTypeExecutorWayland(this);
142+
}
143+
144+
bool AutoTypePlatformWayland::raiseWindow(WId window)
145+
{
146+
Q_UNUSED(window)
147+
return false;
148+
}
149+
150+
QStringList AutoTypePlatformWayland::windowTitles()
151+
{
152+
return {};
153+
}
154+
155+
AutoTypeExecutorWayland::AutoTypeExecutorWayland(AutoTypePlatformWayland* platform)
156+
: m_platform(platform)
157+
{
158+
}
159+
160+
AutoTypeAction::Result AutoTypeExecutorWayland::execBegin(const AutoTypeBegin* action)
161+
{
162+
Q_UNUSED(action)
163+
return AutoTypeAction::Result::Ok();
164+
}
165+
166+
AutoTypeAction::Result AutoTypeExecutorWayland::execType(const AutoTypeKey* action)
167+
{
168+
int kdef = -1;
169+
170+
switch(action->key)
171+
{
172+
case Qt::Key_Tab:
173+
kdef = KEY_TAB;
174+
break;
175+
case Qt::Key_Enter:
176+
kdef = KEY_ENTER;
177+
break;
178+
case Qt::Key_Space:
179+
kdef = KEY_SPACE;
180+
break;
181+
case Qt::Key_Up:
182+
kdef = KEY_UP;
183+
break;
184+
case Qt::Key_Down:
185+
kdef = KEY_DOWN;
186+
break;
187+
case Qt::Key_Left:
188+
kdef = KEY_LEFT;
189+
break;
190+
case Qt::Key_Right:
191+
kdef = KEY_RIGHT;
192+
break;
193+
case Qt::Key_Insert:
194+
kdef = KEY_INSERT;
195+
break;
196+
case Qt::Key_Delete:
197+
kdef = KEY_DELETE;
198+
break;
199+
case Qt::Key_Home:
200+
kdef = KEY_HOME;
201+
break;
202+
case Qt::Key_End:
203+
kdef = KEY_END;
204+
break;
205+
case Qt::Key_PageUp:
206+
kdef = KEY_PAGEUP;
207+
break;
208+
case Qt::Key_PageDown:
209+
kdef = KEY_PAGEDOWN;
210+
break;
211+
case Qt::Key_Backspace:
212+
kdef = KEY_BACKSPACE;
213+
break;
214+
case Qt::Key_Pause:
215+
kdef = KEY_PAUSE;
216+
break;
217+
case Qt::Key_CapsLock:
218+
kdef = KEY_CAPSLOCK;
219+
break;
220+
case Qt::Key_Escape:
221+
kdef = KEY_ESC;
222+
break;
223+
case Qt::Key_Help:
224+
kdef = KEY_HELP;
225+
break;
226+
case Qt::Key_NumLock:
227+
kdef = KEY_NUMLOCK;
228+
break;
229+
case Qt::Key_Print:
230+
kdef = KEY_PRINT;
231+
break;
232+
case Qt::Key_ScrollLock:
233+
kdef = KEY_SCROLLLOCK;
234+
break;
235+
case Qt::Key_Shift:
236+
kdef = KEY_LEFTSHIFT;
237+
break;
238+
case Qt::Key_Control:
239+
kdef = KEY_LEFTCTRL;
240+
break;
241+
case Qt::Key_Alt:
242+
kdef = KEY_LEFTALT;
243+
break;
244+
default:
245+
if (action->key >= Qt::Key_F1 && action->key <= Qt::Key_F16)
246+
{
247+
kdef = KEY_F1 + (action->key - Qt::Key_F1);
248+
}
249+
else if (action->key >= Qt::Key_Space && action->key <= Qt::Key_AsciiTilde)
250+
{
251+
kdef = _ascii2keycode_map[action->key];
252+
}
253+
else
254+
{
255+
char c = action->character.toLatin1();
256+
kdef = (c >= 0) ? _ascii2keycode_map[c] : -1;
257+
}
258+
}
259+
260+
if (kdef > 0)
261+
{
262+
uint16_t kc = kdef & 0xffff;
263+
264+
if (action->modifiers.testFlag(Qt::ShiftModifier) || (kdef & FLAG_UPPERCASE))
265+
{
266+
m_platform->sendUiKey(KEY_LEFTSHIFT, 1);
267+
}
268+
if (action->modifiers.testFlag(Qt::ControlModifier)) {
269+
m_platform->sendUiKey(KEY_LEFTCTRL, 1);
270+
}
271+
if (action->modifiers.testFlag(Qt::AltModifier)) {
272+
m_platform->sendUiKey(KEY_LEFTALT, 1);
273+
}
274+
if (action->modifiers.testFlag(Qt::MetaModifier)) {
275+
m_platform->sendUiKey(KEY_LEFTMETA, 1);
276+
}
277+
278+
m_platform->sendUiKey(kc, 1);
279+
Tools::sleep(20);
280+
m_platform->sendUiKey(kc, 0);
281+
282+
if (action->modifiers.testFlag(Qt::MetaModifier)) {
283+
m_platform->sendUiKey(KEY_LEFTMETA, 0);
284+
}
285+
if (action->modifiers.testFlag(Qt::AltModifier)) {
286+
m_platform->sendUiKey(KEY_LEFTALT, 0);
287+
}
288+
if (action->modifiers.testFlag(Qt::ControlModifier)) {
289+
m_platform->sendUiKey(KEY_LEFTCTRL, 0);
290+
}
291+
if (action->modifiers.testFlag(Qt::ShiftModifier) || (kdef & FLAG_UPPERCASE)) {
292+
m_platform->sendUiKey(KEY_LEFTSHIFT, 0);
293+
}
294+
295+
Tools::sleep(execDelayMs);
296+
}
297+
else
298+
{
299+
qWarning() << "ExecType unknown: key " << action->key << " knkc " << qtToNativeKeyCode(action->key) << " char " << action->character << " cnkc " << qcharToNativeKeyCode(action->character);
300+
}
301+
302+
return AutoTypeAction::Result::Ok();
303+
}
304+
305+
AutoTypeAction::Result AutoTypeExecutorWayland::execClearField(const AutoTypeClearField* action)
306+
{
307+
Q_UNUSED(action)
308+
execType(new AutoTypeKey(Qt::Key_Home));
309+
execType(new AutoTypeKey(Qt::Key_End, Qt::ShiftModifier));
310+
execType(new AutoTypeKey(Qt::Key_Backspace));
311+
312+
return AutoTypeAction::Result::Ok();
313+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (C) 2024 KeePassXC Team <[email protected]>
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 2 or (at your option)
7+
* version 3 of the License.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#pragma once
19+
20+
#include "autotype/AutoTypePlatformPlugin.h"
21+
22+
class AutoTypePlatformWayland : public QObject, public AutoTypePlatformInterface
23+
{
24+
Q_OBJECT
25+
Q_PLUGIN_METADATA(IID "org.keepassx.AutoTypePlatformWaylnd")
26+
Q_INTERFACES(AutoTypePlatformInterface)
27+
28+
public:
29+
AutoTypePlatformWayland();
30+
bool isAvailable() override;
31+
void unload() override;
32+
QStringList windowTitles() override;
33+
WId activeWindow() override;
34+
QString activeWindowTitle() override;
35+
bool raiseWindow(WId window) override;
36+
AutoTypeExecutor* createExecutor() override;
37+
38+
void sendUiKey(uint16_t code, int32_t value);
39+
40+
private:
41+
int uifd;
42+
};
43+
44+
class AutoTypeExecutorWayland : public AutoTypeExecutor
45+
{
46+
public:
47+
explicit AutoTypeExecutorWayland(AutoTypePlatformWayland* platform);
48+
49+
AutoTypeAction::Result execBegin(const AutoTypeBegin* action) override;
50+
AutoTypeAction::Result execType(const AutoTypeKey* action) override;
51+
AutoTypeAction::Result execClearField(const AutoTypeClearField* action) override;
52+
53+
private:
54+
AutoTypePlatformWayland* const m_platform;
55+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
set(autotype_WAYLAND_SOURCES AutoTypeWayland.cpp)
2+
3+
add_library(keepassxc-autotype-wayland MODULE ${autotype_WAYLAND_SOURCES})
4+
target_link_libraries(keepassxc-autotype-wayland keepassxc_gui Qt5::Core Qt5::Widgets Qt5::DBus ${Xkbcommon_LIBRARIES})
5+
install(TARGETS keepassxc-autotype-wayland
6+
BUNDLE DESTINATION . COMPONENT Runtime
7+
LIBRARY DESTINATION ${PLUGIN_INSTALL_DIR} COMPONENT Runtime)

0 commit comments

Comments
 (0)