blob: fbe917beee6abc2749728aaceb60413bc3ea53b0 [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) :
26 keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0},
27 keyboardPath(kbdPath), pointerPath(ptrPath)
Eddie James21b177e2018-12-11 13:14:46 -060028{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080029 if (!keyboardPath.empty())
Eddie James21b177e2018-12-11 13:14:46 -060030 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080031 keyboardFd = open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC);
32 if (keyboardFd < 0)
33 {
34 log<level::ERR>("Failed to open input device",
35 entry("PATH=%s", keyboardPath.c_str()),
36 entry("ERROR=%s", strerror(errno)));
37 elog<Open>(xyz::openbmc_project::Common::File::Open::ERRNO(errno),
38 xyz::openbmc_project::Common::File::Open::PATH(
39 keyboardPath.c_str()));
40 }
Eddie James21b177e2018-12-11 13:14:46 -060041 }
42
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080043 if (!pointerPath.empty())
44 {
45 pointerFd = open(pointerPath.c_str(), O_RDWR | O_CLOEXEC);
46 if (pointerFd < 0)
47 {
48 log<level::ERR>("Failed to open input device",
49 entry("PATH=%s", pointerPath.c_str()),
50 entry("ERROR=%s", strerror(errno)));
51 elog<Open>(xyz::openbmc_project::Common::File::Open::ERRNO(errno),
52 xyz::openbmc_project::Common::File::Open::PATH(
53 pointerPath.c_str()));
54 }
55 }
Eddie James21b177e2018-12-11 13:14:46 -060056}
57
58Input::~Input()
59{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080060 if (keyboardFd >= 0)
61 {
62 close(keyboardFd);
63 }
64
65 if (pointerFd >= 0)
66 {
67 close(pointerFd);
68 }
Eddie James21b177e2018-12-11 13:14:46 -060069}
70
71void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl)
72{
73 Server::ClientData* cd = (Server::ClientData*)cl->clientData;
74 Input* input = cd->input;
75
76 if (down)
77 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080078 uint8_t sc = keyToScancode(key);
Eddie James21b177e2018-12-11 13:14:46 -060079
80 if (sc)
81 {
82 if (input->keysDown.find(key) == input->keysDown.end())
83 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080084 for (unsigned int i = 2; i < KEY_REPORT_LENGTH; ++i)
Eddie James21b177e2018-12-11 13:14:46 -060085 {
86 if (!input->keyboardReport[i])
87 {
88 input->keyboardReport[i] = sc;
89 input->keysDown.insert(std::make_pair(key, i));
90 input->sendKeyboard = true;
91 break;
92 }
93 }
94 }
95 }
96 else
97 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -080098 uint8_t mod = keyToMod(key);
Eddie James21b177e2018-12-11 13:14:46 -060099
100 if (mod)
101 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800102 input->keyboardReport[0] |= mod;
Eddie James21b177e2018-12-11 13:14:46 -0600103 input->sendKeyboard = true;
104 }
105 }
106 }
107 else
108 {
109 auto it = input->keysDown.find(key);
110
111 if (it != input->keysDown.end())
112 {
113 input->keyboardReport[it->second] = 0;
114 input->keysDown.erase(it);
115 input->sendKeyboard = true;
116 }
117 else
118 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800119 uint8_t mod = keyToMod(key);
Eddie James21b177e2018-12-11 13:14:46 -0600120
121 if (mod)
122 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800123 input->keyboardReport[0] &= ~mod;
Eddie James21b177e2018-12-11 13:14:46 -0600124 input->sendKeyboard = true;
125 }
126 }
127 }
128}
129
130void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl)
131{
132 Server::ClientData* cd = (Server::ClientData*)cl->clientData;
133 Input* input = cd->input;
134 Server* server = (Server*)cl->screen->screenData;
135 const Video& video = server->getVideo();
136
Jae Hyun Yoo33890982019-03-19 10:20:27 -0700137 input->pointerReport[0] = ((buttonMask & 0x4) >> 1) |
138 ((buttonMask & 0x2) << 1) | (buttonMask & 0x1);
Eddie James21b177e2018-12-11 13:14:46 -0600139
140 if (x >= 0 && (unsigned int)x < video.getWidth())
141 {
Jae Hyun Yoo2bc661d2019-02-25 13:52:47 -0800142 uint16_t xx = (uint16_t)(x * (SHRT_MAX + 1) / video.getWidth());
Eddie James21b177e2018-12-11 13:14:46 -0600143
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800144 memcpy(&input->pointerReport[1], &xx, 2);
Eddie James21b177e2018-12-11 13:14:46 -0600145 }
146
147 if (y >= 0 && (unsigned int)y < video.getHeight())
148 {
Jae Hyun Yoo2bc661d2019-02-25 13:52:47 -0800149 uint16_t yy = (uint16_t)(y * (SHRT_MAX + 1) / video.getHeight());
Eddie James21b177e2018-12-11 13:14:46 -0600150
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800151 memcpy(&input->pointerReport[3], &yy, 2);
Eddie James21b177e2018-12-11 13:14:46 -0600152 }
153
154 input->sendPointer = true;
155 rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
156}
157
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800158void Input::sendWakeupPacket()
Eddie James21b177e2018-12-11 13:14:46 -0600159{
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800160 uint8_t wakeupReport[KEY_REPORT_LENGTH] = {0};
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800161
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800162 if (pointerFd >= 0)
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800163 {
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800164 uint16_t xy = SHRT_MAX / 2;
165
166 memcpy(&wakeupReport[1], &xy, 2);
167 memcpy(&wakeupReport[3], &xy, 2);
168
169 if (write(pointerFd, wakeupReport, PTR_REPORT_LENGTH) !=
170 PTR_REPORT_LENGTH)
171 {
172 log<level::ERR>("Failed to write pointer report",
173 entry("ERROR=%s", strerror(errno)));
174 }
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800175 }
176
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800177 if (keyboardFd >= 0)
Eddie James21b177e2018-12-11 13:14:46 -0600178 {
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800179 memset(&wakeupReport[0], 0, KEY_REPORT_LENGTH);
180
181 wakeupReport[0] = keyToMod(XK_Shift_L);
182
183 if (write(keyboardFd, wakeupReport, KEY_REPORT_LENGTH) !=
184 KEY_REPORT_LENGTH)
185 {
186 log<level::ERR>("Failed to write keyboard report",
187 entry("ERROR=%s", strerror(errno)));
188 return;
189 }
190
191 wakeupReport[0] = 0;
192
193 if (write(keyboardFd, wakeupReport, KEY_REPORT_LENGTH) !=
194 KEY_REPORT_LENGTH)
195 {
196 log<level::ERR>("Failed to write keyboard report",
197 entry("ERROR=%s", strerror(errno)));
198 }
Eddie James21b177e2018-12-11 13:14:46 -0600199 }
200}
201
202void Input::sendReport()
203{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800204 if (sendKeyboard && keyboardFd >= 0)
Eddie James21b177e2018-12-11 13:14:46 -0600205 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800206 if (write(keyboardFd, keyboardReport, KEY_REPORT_LENGTH) !=
207 KEY_REPORT_LENGTH)
Eddie James21b177e2018-12-11 13:14:46 -0600208 {
209 log<level::ERR>("Failed to write keyboard report",
210 entry("ERROR=%s", strerror(errno)));
211 }
212
213 sendKeyboard = false;
214 }
215
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800216 if (sendPointer && pointerFd >= 0)
Eddie James21b177e2018-12-11 13:14:46 -0600217 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800218 if (write(pointerFd, pointerReport, PTR_REPORT_LENGTH) !=
219 PTR_REPORT_LENGTH)
Eddie James21b177e2018-12-11 13:14:46 -0600220 {
221 log<level::ERR>("Failed to write pointer report",
222 entry("ERROR=%s", strerror(errno)));
223 }
224
225 sendPointer = false;
226 }
227}
228
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800229uint8_t Input::keyToMod(rfbKeySym key)
Eddie James21b177e2018-12-11 13:14:46 -0600230{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800231 uint8_t mod = 0;
Eddie James21b177e2018-12-11 13:14:46 -0600232
233 if (key >= XK_Shift_L && key <= XK_Control_R)
234 {
235 mod = shiftCtrlMap[key - XK_Shift_L];
236 }
237 else if (key >= XK_Meta_L && key <= XK_Alt_R)
238 {
239 mod = metaAltMap[key - XK_Meta_L];
240 }
241
242 return mod;
243}
244
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800245uint8_t Input::keyToScancode(rfbKeySym key)
Eddie James21b177e2018-12-11 13:14:46 -0600246{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800247 uint8_t scancode = 0;
Eddie James21b177e2018-12-11 13:14:46 -0600248
249 if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'))
250 {
251 scancode = USBHID_KEY_A + ((key & 0x5F) - 'A');
252 }
253 else if (key >= '1' && key <= '9')
254 {
255 scancode = USBHID_KEY_1 + (key - '1');
256 }
257 else if (key >= XK_F1 && key <= XK_F12)
258 {
259 scancode = USBHID_KEY_F1 + (key - XK_F1);
260 }
261 else
262 {
263 switch (key)
264 {
265 case XK_exclam:
266 scancode = USBHID_KEY_1;
267 break;
268 case XK_at:
269 scancode = USBHID_KEY_2;
270 break;
271 case XK_numbersign:
272 scancode = USBHID_KEY_3;
273 break;
274 case XK_dollar:
275 scancode = USBHID_KEY_4;
276 break;
277 case XK_percent:
278 scancode = USBHID_KEY_5;
279 break;
280 case XK_asciicircum:
281 scancode = USBHID_KEY_6;
282 break;
283 case XK_ampersand:
284 scancode = USBHID_KEY_7;
285 break;
286 case XK_asterisk:
287 scancode = USBHID_KEY_8;
288 break;
289 case XK_parenleft:
290 scancode = USBHID_KEY_9;
291 break;
292 case XK_0:
293 case XK_parenright:
294 scancode = USBHID_KEY_0;
295 break;
296 case XK_Return:
297 scancode = USBHID_KEY_RETURN;
298 break;
299 case XK_Escape:
300 scancode = USBHID_KEY_ESC;
301 break;
302 case XK_BackSpace:
303 scancode = USBHID_KEY_BACKSPACE;
304 break;
305 case XK_Tab:
306 scancode = USBHID_KEY_TAB;
307 break;
308 case XK_space:
309 scancode = USBHID_KEY_SPACE;
310 break;
311 case XK_minus:
312 case XK_underscore:
313 scancode = USBHID_KEY_MINUS;
314 break;
315 case XK_plus:
316 case XK_equal:
317 scancode = USBHID_KEY_EQUAL;
318 break;
319 case XK_bracketleft:
320 case XK_braceleft:
321 scancode = USBHID_KEY_LEFTBRACE;
322 break;
323 case XK_bracketright:
324 case XK_braceright:
325 scancode = USBHID_KEY_RIGHTBRACE;
326 break;
327 case XK_backslash:
328 case XK_bar:
329 scancode = USBHID_KEY_BACKSLASH;
330 break;
331 case XK_colon:
332 case XK_semicolon:
333 scancode = USBHID_KEY_SEMICOLON;
334 break;
335 case XK_quotedbl:
336 case XK_apostrophe:
337 scancode = USBHID_KEY_APOSTROPHE;
338 break;
339 case XK_grave:
340 case XK_asciitilde:
341 scancode = USBHID_KEY_GRAVE;
342 break;
343 case XK_comma:
344 case XK_less:
345 scancode = USBHID_KEY_COMMA;
346 break;
347 case XK_period:
348 case XK_greater:
349 scancode = USBHID_KEY_DOT;
350 break;
351 case XK_slash:
352 case XK_question:
353 scancode = USBHID_KEY_SLASH;
354 break;
355 case XK_Caps_Lock:
356 scancode = USBHID_KEY_CAPSLOCK;
357 break;
358 case XK_Print:
359 scancode = USBHID_KEY_PRINT;
360 break;
361 case XK_Scroll_Lock:
362 scancode = USBHID_KEY_SCROLLLOCK;
363 break;
364 case XK_Pause:
365 scancode = USBHID_KEY_PAUSE;
366 break;
367 case XK_Insert:
368 scancode = USBHID_KEY_INSERT;
369 break;
370 case XK_Home:
371 scancode = USBHID_KEY_HOME;
372 break;
373 case XK_Page_Up:
374 scancode = USBHID_KEY_PAGEUP;
375 break;
376 case XK_Delete:
377 scancode = USBHID_KEY_DELETE;
378 break;
379 case XK_End:
380 scancode = USBHID_KEY_END;
381 break;
382 case XK_Page_Down:
383 scancode = USBHID_KEY_PAGEDOWN;
384 break;
385 case XK_Right:
386 scancode = USBHID_KEY_RIGHT;
387 break;
388 case XK_Left:
389 scancode = USBHID_KEY_LEFT;
390 break;
391 case XK_Down:
392 scancode = USBHID_KEY_DOWN;
393 break;
394 case XK_Up:
395 scancode = USBHID_KEY_UP;
396 break;
397 case XK_Num_Lock:
398 scancode = USBHID_KEY_NUMLOCK;
399 break;
400 }
401 }
402
403 return scancode;
404}
405
406} // namespace ikvm