6 #include <X11/XKBlib.h>
7 #include <X11/keysym.h>
9 #include <linux/input.h>
13 #include <QSocketNotifier>
18 using namespace swift::misc::input;
20 namespace swift::input
60 { XK_Shift_L, Key_ShiftLeft },
61 { XK_Shift_R, Key_ShiftRight },
62 { XK_Control_L, Key_ControlLeft },
63 { XK_Control_R, Key_ControlRight },
64 { XK_Alt_L, Key_AltLeft },
65 { XK_Alt_R, Key_AltRight },
66 { XK_KP_Add, Key_Plus },
67 { XK_plus, Key_Plus },
68 { XK_KP_Subtract, Key_Minus },
69 { XK_minus, Key_Minus },
70 { XK_period, Key_Period },
71 { XK_KP_Divide, Key_Divide },
72 { XK_KP_Multiply, Key_Multiply },
73 { XK_KP_Subtract, Key_NumpadMinus },
74 { XK_KP_Add, Key_NumpadPlus },
75 { XK_KP_Delete, Key_NumpadDelete },
76 { XK_BackSpace, Key_Back },
78 { XK_Escape, Key_Esc },
79 { XK_space, Key_Space },
80 { XK_dead_grave, Key_DeadGrave },
81 { XK_comma, Key_Comma },
82 { XK_Delete, Key_Delete },
83 { XK_Insert, Key_Insert },
84 { XK_Home, Key_Home },
86 { XK_Page_Up, Key_PageUp },
87 { XK_Page_Down, Key_PageDown },
88 { XK_Caps_Lock, Key_CapsLock },
89 { XK_Return, Key_Enter },
90 { XK_F1, Key_Function1 },
91 { XK_F2, Key_Function2 },
92 { XK_F3, Key_Function3 },
93 { XK_F4, Key_Function4 },
94 { XK_F5, Key_Function5 },
95 { XK_F6, Key_Function6 },
96 { XK_F7, Key_Function7 },
97 { XK_F8, Key_Function8 },
98 { XK_F9, Key_Function9 },
99 { XK_F10, Key_Function10 },
100 { XK_F11, Key_Function11 },
101 { XK_F12, Key_Function12 },
102 { XK_F13, Key_Function13 },
103 { XK_F14, Key_Function14 },
104 { XK_F15, Key_Function15 },
105 { XK_F16, Key_Function16 },
106 { XK_F17, Key_Function17 },
107 { XK_F18, Key_Function18 },
108 { XK_F19, Key_Function19 },
109 { XK_F20, Key_Function20 },
110 { XK_F21, Key_Function21 },
111 { XK_F22, Key_Function22 },
112 { XK_F23, Key_Function23 },
113 { XK_F24, Key_Function24 },
129 CKeyboardLinux::CKeyboardLinux(QObject *parent) : IKeyboard(parent) { m_display = XOpenDisplay(
nullptr); }
131 CKeyboardLinux::~CKeyboardLinux()
133 if (m_display) XCloseDisplay(m_display);
136 bool CKeyboardLinux::init()
138 QString dir = QLatin1String(
"/dev/input");
139 m_devInputWatcher =
new QFileSystemWatcher(QStringList(dir),
this);
140 connect(m_devInputWatcher, &QFileSystemWatcher::directoryChanged,
this,
141 &CKeyboardLinux::deviceDirectoryChanged);
142 deviceDirectoryChanged(dir);
147 void CKeyboardLinux::deviceDirectoryChanged(
const QString &dir)
149 QDir eventFiles(dir, QLatin1String(
"event*"), QDir::Name, QDir::System);
151 foreach (QFileInfo fileInfo, eventFiles.entryInfoList())
153 QString path = fileInfo.absoluteFilePath();
154 if (!m_keyboardDevices.contains(path)) addRawInputDevice(path);
158 void CKeyboardLinux::inputReadyRead(
int)
160 struct input_event eventInput;
162 QFile *fileInput = qobject_cast<QFile *>(sender()->parent());
163 if (!fileInput)
return;
167 while (fileInput->read(
reinterpret_cast<char *
>(&eventInput),
sizeof(eventInput)) ==
sizeof(eventInput))
170 if (eventInput.type != EV_KEY)
continue;
171 bool isPressed =
false;
172 switch (eventInput.value)
174 case 0: isPressed =
false;
break;
175 case 1: isPressed =
true;
break;
180 int keyCode = eventInput.code + 8;
181 keyEvent(keyCode, isPressed);
186 int fd = fileInput->handle();
188 if ((ioctl(fd, EVIOCGVERSION, &version) < 0) || (((version >> 16) & 0xFF) < 1))
190 qWarning(
"CKeyboardLinux: Removing dead input device %s", qPrintable(fileInput->fileName()));
191 m_keyboardDevices.remove(fileInput->fileName());
196 void CKeyboardLinux::addRawInputDevice(
const QString &filePath)
198 QSharedPointer<QFile> inputFile(
new QFile(filePath));
199 if (inputFile->open(QIODevice::ReadOnly))
201 int fd = inputFile->handle();
202 if (fd < 0) {
return; }
205 if (ioctl(fd, EVIOCGVERSION, &version) < 0) {
return; }
207 char deviceName[255];
208 if (ioctl(fd, EVIOCGNAME(
sizeof(deviceName)), deviceName) < 0) {
return; }
210 uint8_t bitmask[EV_MAX / 8 + 1];
211 memset(bitmask, 0,
sizeof(bitmask));
212 if (ioctl(fd, EVIOCGBIT(0,
sizeof(bitmask)), &bitmask) < 0) {
return; }
216 if (!(bitmask[EV_SYN / 8] & (1 << (EV_SYN % 8))) && !(bitmask[EV_KEY / 8] & (1 << (EV_KEY % 8))) &&
217 (bitmask[EV_REL / 8] & (1 << (EV_REL % 8))) && (bitmask[EV_ABS / 8] & (1 << (EV_ABS % 8))))
223 if ((ioctl(fd, EVIOCGRAB, 1) < 0))
226 u
"Device exclusively grabbed by someone else (X11 using exclusive-mode evdev?)")
231 ioctl(fd, EVIOCGRAB, 0);
232 uint8_t keys[KEY_MAX / 8 + 1];
233 if ((ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keys)), &keys) >= 0) &&
234 (keys[KEY_SPACE / 8] & (1 << (KEY_SPACE % 8))))
238 fcntl(inputFile->handle(), F_SETFL, O_NONBLOCK);
239 connect(
new QSocketNotifier(inputFile->handle(), QSocketNotifier::Read, inputFile.data()),
240 &QSocketNotifier::activated,
this, &CKeyboardLinux::inputReadyRead);
242 m_keyboardDevices.insert(filePath, inputFile);
249 << inputFile->fileName() << inputFile->errorString();
253 void CKeyboardLinux::keyEvent(
int keyCode,
bool isPressed)
255 if (isMouseButton(keyCode)) {
return; }
260 auto key = convertToKey(keyCode);
261 if (key == Key_Unknown) {
return; }
263 m_keyCombination.addKeyboardKey(key);
267 auto key = convertToKey(keyCode);
268 if (key == Key_Unknown) {
return; }
270 m_keyCombination.removeKeyboardKey(key);
273 if (oldCombination != m_keyCombination) { emit keyCombinationChanged(m_keyCombination); }
285 auto keySym = XkbKeycodeToKeysym(m_display, keyCode, 0, 0);
286 return keyMapping.value(keySym, Key_Unknown);
289 bool CKeyboardLinux::isModifier(
int keyCode)
291 auto keySym = XkbKeycodeToKeysym(m_display, keyCode, 0, 0);
299 case XK_Alt_R:
return true;
300 default:
return false;
306 bool CKeyboardLinux::isMouseButton(
int keyCode)
312 case BTN_MIDDLE:
return true;
313 default:
return false;
Class for emitting a log message.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
Derived & error(const char16_t(&format)[N])
Set the severity to error, providing a format string.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
KeyCode
Key code http://www.kbdlayout.info/.
Free functions in swift::misc.