blob: 30deea6019dccc0ecfa661457dec002d36690522 [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) :
Eddie James4749f932019-04-18 11:06:39 -050026 pointerError(false), sendKeyboard(false), sendPointer(false),
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080027 keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0},
28 keyboardPath(kbdPath), 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
Eddie James23135dd2019-08-09 15:41:37 -0500159void Input::restart()
160{
161 if (!keyboardPath.empty() && keyboardFd < 0)
162 {
163 keyboardFd = open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC);
164 if (keyboardFd < 0)
165 {
166 log<level::ERR>("Failed to open input device",
167 entry("PATH=%s", keyboardPath.c_str()),
168 entry("ERROR=%s", strerror(errno)));
169 }
170
171 sendKeyboard = false;
172 }
173
174 if (!pointerPath.empty() && pointerFd < 0)
175 {
176 pointerFd = open(pointerPath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
177 if (pointerFd < 0)
178 {
179 log<level::ERR>("Failed to open input device",
180 entry("PATH=%s", pointerPath.c_str()),
181 entry("ERROR=%s", strerror(errno)));
182 }
183
184 pointerError = false;
185 sendPointer = false;
186 }
187}
188
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800189void Input::sendWakeupPacket()
Eddie James21b177e2018-12-11 13:14:46 -0600190{
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800191 uint8_t wakeupReport[KEY_REPORT_LENGTH] = {0};
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800192
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800193 if (pointerFd >= 0)
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800194 {
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800195 uint16_t xy = SHRT_MAX / 2;
196
197 memcpy(&wakeupReport[1], &xy, 2);
198 memcpy(&wakeupReport[3], &xy, 2);
199
200 if (write(pointerFd, wakeupReport, PTR_REPORT_LENGTH) !=
201 PTR_REPORT_LENGTH)
202 {
203 log<level::ERR>("Failed to write pointer report",
204 entry("ERROR=%s", strerror(errno)));
205 }
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800206 }
207
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800208 if (keyboardFd >= 0)
Eddie James21b177e2018-12-11 13:14:46 -0600209 {
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800210 memset(&wakeupReport[0], 0, KEY_REPORT_LENGTH);
211
212 wakeupReport[0] = keyToMod(XK_Shift_L);
213
214 if (write(keyboardFd, wakeupReport, KEY_REPORT_LENGTH) !=
215 KEY_REPORT_LENGTH)
216 {
217 log<level::ERR>("Failed to write keyboard report",
218 entry("ERROR=%s", strerror(errno)));
219 return;
220 }
221
222 wakeupReport[0] = 0;
223
224 if (write(keyboardFd, wakeupReport, KEY_REPORT_LENGTH) !=
225 KEY_REPORT_LENGTH)
226 {
227 log<level::ERR>("Failed to write keyboard report",
228 entry("ERROR=%s", strerror(errno)));
229 }
Eddie James21b177e2018-12-11 13:14:46 -0600230 }
231}
232
233void Input::sendReport()
234{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800235 if (sendKeyboard && keyboardFd >= 0)
Eddie James21b177e2018-12-11 13:14:46 -0600236 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800237 if (write(keyboardFd, keyboardReport, KEY_REPORT_LENGTH) !=
238 KEY_REPORT_LENGTH)
Eddie James21b177e2018-12-11 13:14:46 -0600239 {
240 log<level::ERR>("Failed to write keyboard report",
241 entry("ERROR=%s", strerror(errno)));
Eddie James23135dd2019-08-09 15:41:37 -0500242
243 if (errno == ESHUTDOWN)
244 {
245 close(keyboardFd);
246 keyboardFd = -1;
247 }
Eddie James21b177e2018-12-11 13:14:46 -0600248 }
249
250 sendKeyboard = false;
251 }
252
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800253 if (sendPointer && pointerFd >= 0)
Eddie James21b177e2018-12-11 13:14:46 -0600254 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800255 if (write(pointerFd, pointerReport, PTR_REPORT_LENGTH) !=
256 PTR_REPORT_LENGTH)
Eddie James21b177e2018-12-11 13:14:46 -0600257 {
Eddie James4749f932019-04-18 11:06:39 -0500258 if (!pointerError)
259 {
260 log<level::ERR>("Failed to write pointer report",
261 entry("ERROR=%s", strerror(errno)));
262 pointerError = true;
263 }
Eddie James23135dd2019-08-09 15:41:37 -0500264
265 if (errno == ESHUTDOWN)
266 {
267 close(pointerFd);
268 pointerFd = -1;
269 }
270 }
271 else
272 {
273 pointerError = false;
Eddie James21b177e2018-12-11 13:14:46 -0600274 }
275
276 sendPointer = false;
277 }
278}
279
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800280uint8_t Input::keyToMod(rfbKeySym key)
Eddie James21b177e2018-12-11 13:14:46 -0600281{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800282 uint8_t mod = 0;
Eddie James21b177e2018-12-11 13:14:46 -0600283
284 if (key >= XK_Shift_L && key <= XK_Control_R)
285 {
286 mod = shiftCtrlMap[key - XK_Shift_L];
287 }
288 else if (key >= XK_Meta_L && key <= XK_Alt_R)
289 {
290 mod = metaAltMap[key - XK_Meta_L];
291 }
292
293 return mod;
294}
295
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800296uint8_t Input::keyToScancode(rfbKeySym key)
Eddie James21b177e2018-12-11 13:14:46 -0600297{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800298 uint8_t scancode = 0;
Eddie James21b177e2018-12-11 13:14:46 -0600299
300 if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'))
301 {
302 scancode = USBHID_KEY_A + ((key & 0x5F) - 'A');
303 }
304 else if (key >= '1' && key <= '9')
305 {
306 scancode = USBHID_KEY_1 + (key - '1');
307 }
308 else if (key >= XK_F1 && key <= XK_F12)
309 {
310 scancode = USBHID_KEY_F1 + (key - XK_F1);
311 }
312 else
313 {
314 switch (key)
315 {
316 case XK_exclam:
317 scancode = USBHID_KEY_1;
318 break;
319 case XK_at:
320 scancode = USBHID_KEY_2;
321 break;
322 case XK_numbersign:
323 scancode = USBHID_KEY_3;
324 break;
325 case XK_dollar:
326 scancode = USBHID_KEY_4;
327 break;
328 case XK_percent:
329 scancode = USBHID_KEY_5;
330 break;
331 case XK_asciicircum:
332 scancode = USBHID_KEY_6;
333 break;
334 case XK_ampersand:
335 scancode = USBHID_KEY_7;
336 break;
337 case XK_asterisk:
338 scancode = USBHID_KEY_8;
339 break;
340 case XK_parenleft:
341 scancode = USBHID_KEY_9;
342 break;
343 case XK_0:
344 case XK_parenright:
345 scancode = USBHID_KEY_0;
346 break;
347 case XK_Return:
348 scancode = USBHID_KEY_RETURN;
349 break;
350 case XK_Escape:
351 scancode = USBHID_KEY_ESC;
352 break;
353 case XK_BackSpace:
354 scancode = USBHID_KEY_BACKSPACE;
355 break;
356 case XK_Tab:
357 scancode = USBHID_KEY_TAB;
358 break;
359 case XK_space:
360 scancode = USBHID_KEY_SPACE;
361 break;
362 case XK_minus:
363 case XK_underscore:
364 scancode = USBHID_KEY_MINUS;
365 break;
366 case XK_plus:
367 case XK_equal:
368 scancode = USBHID_KEY_EQUAL;
369 break;
370 case XK_bracketleft:
371 case XK_braceleft:
372 scancode = USBHID_KEY_LEFTBRACE;
373 break;
374 case XK_bracketright:
375 case XK_braceright:
376 scancode = USBHID_KEY_RIGHTBRACE;
377 break;
378 case XK_backslash:
379 case XK_bar:
380 scancode = USBHID_KEY_BACKSLASH;
381 break;
382 case XK_colon:
383 case XK_semicolon:
384 scancode = USBHID_KEY_SEMICOLON;
385 break;
386 case XK_quotedbl:
387 case XK_apostrophe:
388 scancode = USBHID_KEY_APOSTROPHE;
389 break;
390 case XK_grave:
391 case XK_asciitilde:
392 scancode = USBHID_KEY_GRAVE;
393 break;
394 case XK_comma:
395 case XK_less:
396 scancode = USBHID_KEY_COMMA;
397 break;
398 case XK_period:
399 case XK_greater:
400 scancode = USBHID_KEY_DOT;
401 break;
402 case XK_slash:
403 case XK_question:
404 scancode = USBHID_KEY_SLASH;
405 break;
406 case XK_Caps_Lock:
407 scancode = USBHID_KEY_CAPSLOCK;
408 break;
409 case XK_Print:
410 scancode = USBHID_KEY_PRINT;
411 break;
412 case XK_Scroll_Lock:
413 scancode = USBHID_KEY_SCROLLLOCK;
414 break;
415 case XK_Pause:
416 scancode = USBHID_KEY_PAUSE;
417 break;
418 case XK_Insert:
419 scancode = USBHID_KEY_INSERT;
420 break;
421 case XK_Home:
422 scancode = USBHID_KEY_HOME;
423 break;
424 case XK_Page_Up:
425 scancode = USBHID_KEY_PAGEUP;
426 break;
427 case XK_Delete:
428 scancode = USBHID_KEY_DELETE;
429 break;
430 case XK_End:
431 scancode = USBHID_KEY_END;
432 break;
433 case XK_Page_Down:
434 scancode = USBHID_KEY_PAGEDOWN;
435 break;
436 case XK_Right:
437 scancode = USBHID_KEY_RIGHT;
438 break;
439 case XK_Left:
440 scancode = USBHID_KEY_LEFT;
441 break;
442 case XK_Down:
443 scancode = USBHID_KEY_DOWN;
444 break;
445 case XK_Up:
446 scancode = USBHID_KEY_UP;
447 break;
448 case XK_Num_Lock:
449 scancode = USBHID_KEY_NUMLOCK;
450 break;
451 }
452 }
453
454 return scancode;
455}
456
457} // namespace ikvm