blob: df12f27155857dbcd26e08bf7a144d175ea29b06 [file] [log] [blame]
Eddie James21b177e2018-12-11 13:14:46 -06001#include "ikvm_input.hpp"
2
3#include "ikvm_server.hpp"
4
5#include <err.h>
6#include <errno.h>
7#include <fcntl.h>
8#include <rfb/keysym.h>
9#include <sys/stat.h>
10#include <sys/types.h>
11
12#include <phosphor-logging/elog-errors.hpp>
13#include <phosphor-logging/elog.hpp>
14#include <phosphor-logging/log.hpp>
15#include <xyz/openbmc_project/Common/File/error.hpp>
16
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080017#include "scancodes.hpp"
Eddie James21b177e2018-12-11 13:14:46 -060018
19namespace ikvm
20{
21
22using namespace phosphor::logging;
23using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
24
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080025Input::Input(const std::string& kbdPath, const std::string& ptrPath) :
Jae Hyun Yoo7a89cd22019-08-21 16:52:30 -070026 sendKeyboard(false), sendPointer(false), keyboardFd(-1), pointerFd(-1),
27 keyboardReport{0}, pointerReport{0}, keyboardPath(kbdPath),
28 pointerPath(ptrPath)
Eddie James21b177e2018-12-11 13:14:46 -060029{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080030 if (!keyboardPath.empty())
Eddie James21b177e2018-12-11 13:14:46 -060031 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080032 keyboardFd = open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC);
33 if (keyboardFd < 0)
34 {
35 log<level::ERR>("Failed to open input device",
36 entry("PATH=%s", keyboardPath.c_str()),
37 entry("ERROR=%s", strerror(errno)));
38 elog<Open>(xyz::openbmc_project::Common::File::Open::ERRNO(errno),
39 xyz::openbmc_project::Common::File::Open::PATH(
40 keyboardPath.c_str()));
41 }
Eddie James21b177e2018-12-11 13:14:46 -060042 }
43
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080044 if (!pointerPath.empty())
45 {
Eddie James4749f932019-04-18 11:06:39 -050046 pointerFd = open(pointerPath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080047 if (pointerFd < 0)
48 {
49 log<level::ERR>("Failed to open input device",
50 entry("PATH=%s", pointerPath.c_str()),
51 entry("ERROR=%s", strerror(errno)));
52 elog<Open>(xyz::openbmc_project::Common::File::Open::ERRNO(errno),
53 xyz::openbmc_project::Common::File::Open::PATH(
54 pointerPath.c_str()));
55 }
56 }
Eddie James21b177e2018-12-11 13:14:46 -060057}
58
59Input::~Input()
60{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080061 if (keyboardFd >= 0)
62 {
63 close(keyboardFd);
64 }
65
66 if (pointerFd >= 0)
67 {
68 close(pointerFd);
69 }
Eddie James21b177e2018-12-11 13:14:46 -060070}
71
72void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl)
73{
74 Server::ClientData* cd = (Server::ClientData*)cl->clientData;
75 Input* input = cd->input;
76
77 if (down)
78 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080079 uint8_t sc = keyToScancode(key);
Eddie James21b177e2018-12-11 13:14:46 -060080
81 if (sc)
82 {
83 if (input->keysDown.find(key) == input->keysDown.end())
84 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080085 for (unsigned int i = 2; i < KEY_REPORT_LENGTH; ++i)
Eddie James21b177e2018-12-11 13:14:46 -060086 {
87 if (!input->keyboardReport[i])
88 {
89 input->keyboardReport[i] = sc;
90 input->keysDown.insert(std::make_pair(key, i));
91 input->sendKeyboard = true;
92 break;
93 }
94 }
95 }
96 }
97 else
98 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080099 uint8_t mod = keyToMod(key);
Eddie James21b177e2018-12-11 13:14:46 -0600100
101 if (mod)
102 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800103 input->keyboardReport[0] |= mod;
Eddie James21b177e2018-12-11 13:14:46 -0600104 input->sendKeyboard = true;
105 }
106 }
107 }
108 else
109 {
110 auto it = input->keysDown.find(key);
111
112 if (it != input->keysDown.end())
113 {
114 input->keyboardReport[it->second] = 0;
115 input->keysDown.erase(it);
116 input->sendKeyboard = true;
117 }
118 else
119 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800120 uint8_t mod = keyToMod(key);
Eddie James21b177e2018-12-11 13:14:46 -0600121
122 if (mod)
123 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800124 input->keyboardReport[0] &= ~mod;
Eddie James21b177e2018-12-11 13:14:46 -0600125 input->sendKeyboard = true;
126 }
127 }
128 }
129}
130
131void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl)
132{
133 Server::ClientData* cd = (Server::ClientData*)cl->clientData;
134 Input* input = cd->input;
135 Server* server = (Server*)cl->screen->screenData;
136 const Video& video = server->getVideo();
137
Jae Hyun Yoo33890982019-03-19 10:20:27 -0700138 input->pointerReport[0] = ((buttonMask & 0x4) >> 1) |
139 ((buttonMask & 0x2) << 1) | (buttonMask & 0x1);
Eddie James21b177e2018-12-11 13:14:46 -0600140
141 if (x >= 0 && (unsigned int)x < video.getWidth())
142 {
Jae Hyun Yoo2bc661d2019-02-25 13:52:47 -0800143 uint16_t xx = (uint16_t)(x * (SHRT_MAX + 1) / video.getWidth());
Eddie James21b177e2018-12-11 13:14:46 -0600144
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800145 memcpy(&input->pointerReport[1], &xx, 2);
Eddie James21b177e2018-12-11 13:14:46 -0600146 }
147
148 if (y >= 0 && (unsigned int)y < video.getHeight())
149 {
Jae Hyun Yoo2bc661d2019-02-25 13:52:47 -0800150 uint16_t yy = (uint16_t)(y * (SHRT_MAX + 1) / video.getHeight());
Eddie James21b177e2018-12-11 13:14:46 -0600151
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800152 memcpy(&input->pointerReport[3], &yy, 2);
Eddie James21b177e2018-12-11 13:14:46 -0600153 }
154
155 input->sendPointer = true;
156 rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
157}
158
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800159void Input::sendWakeupPacket()
Eddie James21b177e2018-12-11 13:14:46 -0600160{
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800161 uint8_t wakeupReport[KEY_REPORT_LENGTH] = {0};
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800162
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800163 if (pointerFd >= 0)
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800164 {
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800165 uint16_t xy = SHRT_MAX / 2;
166
167 memcpy(&wakeupReport[1], &xy, 2);
168 memcpy(&wakeupReport[3], &xy, 2);
169
Eddie James7cf1f1d2019-09-30 15:05:16 -0500170 writePointer(wakeupReport);
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800171 }
172
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800173 if (keyboardFd >= 0)
Eddie James21b177e2018-12-11 13:14:46 -0600174 {
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800175 memset(&wakeupReport[0], 0, KEY_REPORT_LENGTH);
176
177 wakeupReport[0] = keyToMod(XK_Shift_L);
178
Eddie James7cf1f1d2019-09-30 15:05:16 -0500179 if (!writeKeyboard(wakeupReport))
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800180 {
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800181 return;
182 }
183
184 wakeupReport[0] = 0;
185
Eddie James7cf1f1d2019-09-30 15:05:16 -0500186 writeKeyboard(wakeupReport);
Eddie James21b177e2018-12-11 13:14:46 -0600187 }
188}
189
190void Input::sendReport()
191{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800192 if (sendKeyboard && keyboardFd >= 0)
Eddie James21b177e2018-12-11 13:14:46 -0600193 {
Eddie James7cf1f1d2019-09-30 15:05:16 -0500194 writeKeyboard(keyboardReport);
Eddie James21b177e2018-12-11 13:14:46 -0600195
196 sendKeyboard = false;
197 }
198
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800199 if (sendPointer && pointerFd >= 0)
Eddie James21b177e2018-12-11 13:14:46 -0600200 {
Eddie James7cf1f1d2019-09-30 15:05:16 -0500201 writePointer(pointerReport);
Eddie James21b177e2018-12-11 13:14:46 -0600202
203 sendPointer = false;
204 }
205}
206
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800207uint8_t Input::keyToMod(rfbKeySym key)
Eddie James21b177e2018-12-11 13:14:46 -0600208{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800209 uint8_t mod = 0;
Eddie James21b177e2018-12-11 13:14:46 -0600210
211 if (key >= XK_Shift_L && key <= XK_Control_R)
212 {
213 mod = shiftCtrlMap[key - XK_Shift_L];
214 }
215 else if (key >= XK_Meta_L && key <= XK_Alt_R)
216 {
217 mod = metaAltMap[key - XK_Meta_L];
218 }
219
220 return mod;
221}
222
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800223uint8_t Input::keyToScancode(rfbKeySym key)
Eddie James21b177e2018-12-11 13:14:46 -0600224{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800225 uint8_t scancode = 0;
Eddie James21b177e2018-12-11 13:14:46 -0600226
227 if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'))
228 {
229 scancode = USBHID_KEY_A + ((key & 0x5F) - 'A');
230 }
231 else if (key >= '1' && key <= '9')
232 {
233 scancode = USBHID_KEY_1 + (key - '1');
234 }
235 else if (key >= XK_F1 && key <= XK_F12)
236 {
237 scancode = USBHID_KEY_F1 + (key - XK_F1);
238 }
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700239 else if (key >= XK_KP_F1 && key <= XK_KP_F4)
240 {
241 scancode = USBHID_KEY_F1 + (key - XK_KP_F1);
242 }
243 else if (key >= XK_KP_1 && key <= XK_KP_9)
244 {
245 scancode = USBHID_KEY_KP_1 + (key - XK_KP_1);
246 }
Eddie James21b177e2018-12-11 13:14:46 -0600247 else
248 {
249 switch (key)
250 {
251 case XK_exclam:
252 scancode = USBHID_KEY_1;
253 break;
254 case XK_at:
255 scancode = USBHID_KEY_2;
256 break;
257 case XK_numbersign:
258 scancode = USBHID_KEY_3;
259 break;
260 case XK_dollar:
261 scancode = USBHID_KEY_4;
262 break;
263 case XK_percent:
264 scancode = USBHID_KEY_5;
265 break;
266 case XK_asciicircum:
267 scancode = USBHID_KEY_6;
268 break;
269 case XK_ampersand:
270 scancode = USBHID_KEY_7;
271 break;
272 case XK_asterisk:
273 scancode = USBHID_KEY_8;
274 break;
275 case XK_parenleft:
276 scancode = USBHID_KEY_9;
277 break;
278 case XK_0:
279 case XK_parenright:
280 scancode = USBHID_KEY_0;
281 break;
282 case XK_Return:
283 scancode = USBHID_KEY_RETURN;
284 break;
285 case XK_Escape:
286 scancode = USBHID_KEY_ESC;
287 break;
288 case XK_BackSpace:
289 scancode = USBHID_KEY_BACKSPACE;
290 break;
291 case XK_Tab:
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700292 case XK_KP_Tab:
Eddie James21b177e2018-12-11 13:14:46 -0600293 scancode = USBHID_KEY_TAB;
294 break;
295 case XK_space:
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700296 case XK_KP_Space:
Eddie James21b177e2018-12-11 13:14:46 -0600297 scancode = USBHID_KEY_SPACE;
298 break;
299 case XK_minus:
300 case XK_underscore:
301 scancode = USBHID_KEY_MINUS;
302 break;
303 case XK_plus:
304 case XK_equal:
305 scancode = USBHID_KEY_EQUAL;
306 break;
307 case XK_bracketleft:
308 case XK_braceleft:
309 scancode = USBHID_KEY_LEFTBRACE;
310 break;
311 case XK_bracketright:
312 case XK_braceright:
313 scancode = USBHID_KEY_RIGHTBRACE;
314 break;
315 case XK_backslash:
316 case XK_bar:
317 scancode = USBHID_KEY_BACKSLASH;
318 break;
319 case XK_colon:
320 case XK_semicolon:
321 scancode = USBHID_KEY_SEMICOLON;
322 break;
323 case XK_quotedbl:
324 case XK_apostrophe:
325 scancode = USBHID_KEY_APOSTROPHE;
326 break;
327 case XK_grave:
328 case XK_asciitilde:
329 scancode = USBHID_KEY_GRAVE;
330 break;
331 case XK_comma:
332 case XK_less:
333 scancode = USBHID_KEY_COMMA;
334 break;
335 case XK_period:
336 case XK_greater:
337 scancode = USBHID_KEY_DOT;
338 break;
339 case XK_slash:
340 case XK_question:
341 scancode = USBHID_KEY_SLASH;
342 break;
343 case XK_Caps_Lock:
344 scancode = USBHID_KEY_CAPSLOCK;
345 break;
346 case XK_Print:
347 scancode = USBHID_KEY_PRINT;
348 break;
349 case XK_Scroll_Lock:
350 scancode = USBHID_KEY_SCROLLLOCK;
351 break;
352 case XK_Pause:
353 scancode = USBHID_KEY_PAUSE;
354 break;
355 case XK_Insert:
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700356 case XK_KP_Insert:
Eddie James21b177e2018-12-11 13:14:46 -0600357 scancode = USBHID_KEY_INSERT;
358 break;
359 case XK_Home:
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700360 case XK_KP_Home:
Eddie James21b177e2018-12-11 13:14:46 -0600361 scancode = USBHID_KEY_HOME;
362 break;
363 case XK_Page_Up:
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700364 case XK_KP_Page_Up:
Eddie James21b177e2018-12-11 13:14:46 -0600365 scancode = USBHID_KEY_PAGEUP;
366 break;
367 case XK_Delete:
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700368 case XK_KP_Delete:
Eddie James21b177e2018-12-11 13:14:46 -0600369 scancode = USBHID_KEY_DELETE;
370 break;
371 case XK_End:
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700372 case XK_KP_End:
Eddie James21b177e2018-12-11 13:14:46 -0600373 scancode = USBHID_KEY_END;
374 break;
375 case XK_Page_Down:
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700376 case XK_KP_Page_Down:
Eddie James21b177e2018-12-11 13:14:46 -0600377 scancode = USBHID_KEY_PAGEDOWN;
378 break;
379 case XK_Right:
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700380 case XK_KP_Right:
Eddie James21b177e2018-12-11 13:14:46 -0600381 scancode = USBHID_KEY_RIGHT;
382 break;
383 case XK_Left:
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700384 case XK_KP_Left:
Eddie James21b177e2018-12-11 13:14:46 -0600385 scancode = USBHID_KEY_LEFT;
386 break;
387 case XK_Down:
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700388 case XK_KP_Down:
Eddie James21b177e2018-12-11 13:14:46 -0600389 scancode = USBHID_KEY_DOWN;
390 break;
391 case XK_Up:
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700392 case XK_KP_Up:
Eddie James21b177e2018-12-11 13:14:46 -0600393 scancode = USBHID_KEY_UP;
394 break;
395 case XK_Num_Lock:
396 scancode = USBHID_KEY_NUMLOCK;
397 break;
Jae Hyun Yoo513d95e2019-08-20 11:26:53 -0700398 case XK_KP_Enter:
399 scancode = USBHID_KEY_KP_ENTER;
400 break;
401 case XK_KP_Equal:
402 scancode = USBHID_KEY_KP_EQUAL;
403 break;
404 case XK_KP_Multiply:
405 scancode = USBHID_KEY_KP_MULTIPLY;
406 break;
407 case XK_KP_Add:
408 scancode = USBHID_KEY_KP_ADD;
409 break;
410 case XK_KP_Subtract:
411 scancode = USBHID_KEY_KP_SUBTRACT;
412 break;
413 case XK_KP_Decimal:
414 scancode = USBHID_KEY_KP_DECIMAL;
415 break;
416 case XK_KP_Divide:
417 scancode = USBHID_KEY_KP_DIVIDE;
418 break;
419 case XK_KP_0:
420 scancode = USBHID_KEY_KP_0;
421 break;
Eddie James21b177e2018-12-11 13:14:46 -0600422 }
423 }
424
425 return scancode;
426}
427
Eddie James7cf1f1d2019-09-30 15:05:16 -0500428bool Input::writeKeyboard(const uint8_t *report)
429{
430 if (write(keyboardFd, report, KEY_REPORT_LENGTH) != KEY_REPORT_LENGTH)
431 {
Jae Hyun Yoo7a89cd22019-08-21 16:52:30 -0700432 if (errno != ESHUTDOWN && errno != EAGAIN)
Eddie James7cf1f1d2019-09-30 15:05:16 -0500433 {
Jae Hyun Yoo7a89cd22019-08-21 16:52:30 -0700434 log<level::ERR>("Failed to write keyboard report",
435 entry("ERROR=%s", strerror(errno)));
Eddie James7cf1f1d2019-09-30 15:05:16 -0500436 }
437
438 return false;
439 }
440
441 return true;
442}
443
444void Input::writePointer(const uint8_t *report)
445{
446 if (write(pointerFd, report, PTR_REPORT_LENGTH) != PTR_REPORT_LENGTH)
447 {
Jae Hyun Yoo7a89cd22019-08-21 16:52:30 -0700448 if (errno != ESHUTDOWN && errno != EAGAIN)
Eddie James7cf1f1d2019-09-30 15:05:16 -0500449 {
450 log<level::ERR>("Failed to write pointer report",
451 entry("ERROR=%s", strerror(errno)));
Eddie James7cf1f1d2019-09-30 15:05:16 -0500452 }
Eddie James7cf1f1d2019-09-30 15:05:16 -0500453 }
454}
455
Eddie James21b177e2018-12-11 13:14:46 -0600456} // namespace ikvm