blob: ce88f40d612f31c72834e58f8b78b87c64771272 [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 Yoo7dfac9f2019-01-15 10:14:59 -0800137 input->pointerReport[0] = buttonMask & 0xFF;
Eddie James21b177e2018-12-11 13:14:46 -0600138
139 if (x >= 0 && (unsigned int)x < video.getWidth())
140 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800141 uint16_t xx = x * ((SHRT_MAX + 1) / video.getWidth());
Eddie James21b177e2018-12-11 13:14:46 -0600142
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800143 memcpy(&input->pointerReport[1], &xx, 2);
Eddie James21b177e2018-12-11 13:14:46 -0600144 }
145
146 if (y >= 0 && (unsigned int)y < video.getHeight())
147 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800148 uint16_t yy = y * ((SHRT_MAX + 1) / video.getHeight());
Eddie James21b177e2018-12-11 13:14:46 -0600149
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800150 memcpy(&input->pointerReport[3], &yy, 2);
Eddie James21b177e2018-12-11 13:14:46 -0600151 }
152
153 input->sendPointer = true;
154 rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
155}
156
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800157void Input::sendWakeupPacket()
Eddie James21b177e2018-12-11 13:14:46 -0600158{
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800159 uint8_t wakeupReport[KEY_REPORT_LENGTH] = {0};
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800160
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800161 if (pointerFd >= 0)
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800162 {
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800163 uint16_t xy = SHRT_MAX / 2;
164
165 memcpy(&wakeupReport[1], &xy, 2);
166 memcpy(&wakeupReport[3], &xy, 2);
167
168 if (write(pointerFd, wakeupReport, PTR_REPORT_LENGTH) !=
169 PTR_REPORT_LENGTH)
170 {
171 log<level::ERR>("Failed to write pointer report",
172 entry("ERROR=%s", strerror(errno)));
173 }
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800174 }
175
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800176 if (keyboardFd >= 0)
Eddie James21b177e2018-12-11 13:14:46 -0600177 {
Jae Hyun Yooeaf5c5b2019-02-20 15:03:17 -0800178 memset(&wakeupReport[0], 0, KEY_REPORT_LENGTH);
179
180 wakeupReport[0] = keyToMod(XK_Shift_L);
181
182 if (write(keyboardFd, wakeupReport, KEY_REPORT_LENGTH) !=
183 KEY_REPORT_LENGTH)
184 {
185 log<level::ERR>("Failed to write keyboard report",
186 entry("ERROR=%s", strerror(errno)));
187 return;
188 }
189
190 wakeupReport[0] = 0;
191
192 if (write(keyboardFd, wakeupReport, KEY_REPORT_LENGTH) !=
193 KEY_REPORT_LENGTH)
194 {
195 log<level::ERR>("Failed to write keyboard report",
196 entry("ERROR=%s", strerror(errno)));
197 }
Eddie James21b177e2018-12-11 13:14:46 -0600198 }
199}
200
201void Input::sendReport()
202{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800203 if (sendKeyboard && keyboardFd >= 0)
Eddie James21b177e2018-12-11 13:14:46 -0600204 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800205 if (write(keyboardFd, keyboardReport, KEY_REPORT_LENGTH) !=
206 KEY_REPORT_LENGTH)
Eddie James21b177e2018-12-11 13:14:46 -0600207 {
208 log<level::ERR>("Failed to write keyboard report",
209 entry("ERROR=%s", strerror(errno)));
210 }
211
212 sendKeyboard = false;
213 }
214
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800215 if (sendPointer && pointerFd >= 0)
Eddie James21b177e2018-12-11 13:14:46 -0600216 {
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800217 if (write(pointerFd, pointerReport, PTR_REPORT_LENGTH) !=
218 PTR_REPORT_LENGTH)
Eddie James21b177e2018-12-11 13:14:46 -0600219 {
220 log<level::ERR>("Failed to write pointer report",
221 entry("ERROR=%s", strerror(errno)));
222 }
223
224 sendPointer = false;
225 }
226}
227
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800228uint8_t Input::keyToMod(rfbKeySym key)
Eddie James21b177e2018-12-11 13:14:46 -0600229{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800230 uint8_t mod = 0;
Eddie James21b177e2018-12-11 13:14:46 -0600231
232 if (key >= XK_Shift_L && key <= XK_Control_R)
233 {
234 mod = shiftCtrlMap[key - XK_Shift_L];
235 }
236 else if (key >= XK_Meta_L && key <= XK_Alt_R)
237 {
238 mod = metaAltMap[key - XK_Meta_L];
239 }
240
241 return mod;
242}
243
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800244uint8_t Input::keyToScancode(rfbKeySym key)
Eddie James21b177e2018-12-11 13:14:46 -0600245{
Jae Hyun Yoo7dfac9f2019-01-15 10:14:59 -0800246 uint8_t scancode = 0;
Eddie James21b177e2018-12-11 13:14:46 -0600247
248 if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'))
249 {
250 scancode = USBHID_KEY_A + ((key & 0x5F) - 'A');
251 }
252 else if (key >= '1' && key <= '9')
253 {
254 scancode = USBHID_KEY_1 + (key - '1');
255 }
256 else if (key >= XK_F1 && key <= XK_F12)
257 {
258 scancode = USBHID_KEY_F1 + (key - XK_F1);
259 }
260 else
261 {
262 switch (key)
263 {
264 case XK_exclam:
265 scancode = USBHID_KEY_1;
266 break;
267 case XK_at:
268 scancode = USBHID_KEY_2;
269 break;
270 case XK_numbersign:
271 scancode = USBHID_KEY_3;
272 break;
273 case XK_dollar:
274 scancode = USBHID_KEY_4;
275 break;
276 case XK_percent:
277 scancode = USBHID_KEY_5;
278 break;
279 case XK_asciicircum:
280 scancode = USBHID_KEY_6;
281 break;
282 case XK_ampersand:
283 scancode = USBHID_KEY_7;
284 break;
285 case XK_asterisk:
286 scancode = USBHID_KEY_8;
287 break;
288 case XK_parenleft:
289 scancode = USBHID_KEY_9;
290 break;
291 case XK_0:
292 case XK_parenright:
293 scancode = USBHID_KEY_0;
294 break;
295 case XK_Return:
296 scancode = USBHID_KEY_RETURN;
297 break;
298 case XK_Escape:
299 scancode = USBHID_KEY_ESC;
300 break;
301 case XK_BackSpace:
302 scancode = USBHID_KEY_BACKSPACE;
303 break;
304 case XK_Tab:
305 scancode = USBHID_KEY_TAB;
306 break;
307 case XK_space:
308 scancode = USBHID_KEY_SPACE;
309 break;
310 case XK_minus:
311 case XK_underscore:
312 scancode = USBHID_KEY_MINUS;
313 break;
314 case XK_plus:
315 case XK_equal:
316 scancode = USBHID_KEY_EQUAL;
317 break;
318 case XK_bracketleft:
319 case XK_braceleft:
320 scancode = USBHID_KEY_LEFTBRACE;
321 break;
322 case XK_bracketright:
323 case XK_braceright:
324 scancode = USBHID_KEY_RIGHTBRACE;
325 break;
326 case XK_backslash:
327 case XK_bar:
328 scancode = USBHID_KEY_BACKSLASH;
329 break;
330 case XK_colon:
331 case XK_semicolon:
332 scancode = USBHID_KEY_SEMICOLON;
333 break;
334 case XK_quotedbl:
335 case XK_apostrophe:
336 scancode = USBHID_KEY_APOSTROPHE;
337 break;
338 case XK_grave:
339 case XK_asciitilde:
340 scancode = USBHID_KEY_GRAVE;
341 break;
342 case XK_comma:
343 case XK_less:
344 scancode = USBHID_KEY_COMMA;
345 break;
346 case XK_period:
347 case XK_greater:
348 scancode = USBHID_KEY_DOT;
349 break;
350 case XK_slash:
351 case XK_question:
352 scancode = USBHID_KEY_SLASH;
353 break;
354 case XK_Caps_Lock:
355 scancode = USBHID_KEY_CAPSLOCK;
356 break;
357 case XK_Print:
358 scancode = USBHID_KEY_PRINT;
359 break;
360 case XK_Scroll_Lock:
361 scancode = USBHID_KEY_SCROLLLOCK;
362 break;
363 case XK_Pause:
364 scancode = USBHID_KEY_PAUSE;
365 break;
366 case XK_Insert:
367 scancode = USBHID_KEY_INSERT;
368 break;
369 case XK_Home:
370 scancode = USBHID_KEY_HOME;
371 break;
372 case XK_Page_Up:
373 scancode = USBHID_KEY_PAGEUP;
374 break;
375 case XK_Delete:
376 scancode = USBHID_KEY_DELETE;
377 break;
378 case XK_End:
379 scancode = USBHID_KEY_END;
380 break;
381 case XK_Page_Down:
382 scancode = USBHID_KEY_PAGEDOWN;
383 break;
384 case XK_Right:
385 scancode = USBHID_KEY_RIGHT;
386 break;
387 case XK_Left:
388 scancode = USBHID_KEY_LEFT;
389 break;
390 case XK_Down:
391 scancode = USBHID_KEY_DOWN;
392 break;
393 case XK_Up:
394 scancode = USBHID_KEY_UP;
395 break;
396 case XK_Num_Lock:
397 scancode = USBHID_KEY_NUMLOCK;
398 break;
399 }
400 }
401
402 return scancode;
403}
404
405} // namespace ikvm