1 #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 17 #include "scancodes.hpp" 18 19 namespace fs = std::filesystem; 20 21 namespace ikvm 22 { 23 24 using namespace phosphor::logging; 25 using namespace sdbusplus::xyz::openbmc_project::Common::File::Error; 26 27 Input::Input(const std::string& kbdPath, const std::string& ptrPath) : 28 keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0}, 29 keyboardPath(kbdPath), pointerPath(ptrPath) 30 { 31 hidUdcStream.exceptions(std::ofstream::failbit | std::ofstream::badbit); 32 hidUdcStream.open(hidUdcPath, std::ios::out | std::ios::app); 33 } 34 35 Input::~Input() 36 { 37 if (keyboardFd >= 0) 38 { 39 close(keyboardFd); 40 } 41 42 if (pointerFd >= 0) 43 { 44 close(pointerFd); 45 } 46 47 disconnect(); 48 hidUdcStream.close(); 49 } 50 51 void Input::connect() 52 { 53 try 54 { 55 for (const auto& port : fs::directory_iterator(usbVirtualHubPath)) 56 { 57 if (fs::is_directory(port) && !fs::is_symlink(port) && 58 !fs::exists(port.path() / "gadget/suspended")) 59 { 60 const std::string portId = port.path().filename(); 61 hidUdcStream << portId << std::endl; 62 break; 63 } 64 } 65 } 66 catch (fs::filesystem_error& e) 67 { 68 log<level::ERR>("Failed to search USB virtual hub port", 69 entry("ERROR=%s", e.what())); 70 return; 71 } 72 catch (std::ofstream::failure& e) 73 { 74 log<level::ERR>("Failed to connect HID gadget", 75 entry("ERROR=%s", e.what())); 76 return; 77 } 78 79 if (!keyboardPath.empty()) 80 { 81 keyboardFd = open(keyboardPath.c_str(), 82 O_RDWR | O_CLOEXEC | O_NONBLOCK); 83 if (keyboardFd < 0) 84 { 85 log<level::ERR>("Failed to open input device", 86 entry("PATH=%s", keyboardPath.c_str()), 87 entry("ERROR=%s", strerror(errno))); 88 elog<Open>(xyz::openbmc_project::Common::File::Open::ERRNO(errno), 89 xyz::openbmc_project::Common::File::Open::PATH( 90 keyboardPath.c_str())); 91 } 92 } 93 94 if (!pointerPath.empty()) 95 { 96 pointerFd = open(pointerPath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK); 97 if (pointerFd < 0) 98 { 99 log<level::ERR>("Failed to open input device", 100 entry("PATH=%s", pointerPath.c_str()), 101 entry("ERROR=%s", strerror(errno))); 102 elog<Open>(xyz::openbmc_project::Common::File::Open::ERRNO(errno), 103 xyz::openbmc_project::Common::File::Open::PATH( 104 pointerPath.c_str())); 105 } 106 } 107 } 108 109 void Input::disconnect() 110 { 111 if (keyboardFd >= 0) 112 { 113 close(keyboardFd); 114 keyboardFd = -1; 115 } 116 117 if (pointerFd >= 0) 118 { 119 close(pointerFd); 120 pointerFd = -1; 121 } 122 123 try 124 { 125 hidUdcStream << "" << std::endl; 126 } 127 catch (std::ofstream::failure& e) 128 { 129 log<level::ERR>("Failed to disconnect HID gadget", 130 entry("ERROR=%s", e.what())); 131 } 132 } 133 134 void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl) 135 { 136 Server::ClientData* cd = (Server::ClientData*)cl->clientData; 137 Input* input = cd->input; 138 bool sendKeyboard = false; 139 140 if (input->keyboardFd < 0) 141 { 142 return; 143 } 144 145 if (down) 146 { 147 uint8_t sc = keyToScancode(key); 148 149 if (sc) 150 { 151 if (input->keysDown.find(key) == input->keysDown.end()) 152 { 153 for (unsigned int i = 2; i < KEY_REPORT_LENGTH; ++i) 154 { 155 if (!input->keyboardReport[i]) 156 { 157 input->keyboardReport[i] = sc; 158 input->keysDown.insert(std::make_pair(key, i)); 159 sendKeyboard = true; 160 break; 161 } 162 } 163 } 164 } 165 else 166 { 167 uint8_t mod = keyToMod(key); 168 169 if (mod) 170 { 171 input->keyboardReport[0] |= mod; 172 sendKeyboard = true; 173 } 174 } 175 } 176 else 177 { 178 auto it = input->keysDown.find(key); 179 180 if (it != input->keysDown.end()) 181 { 182 input->keyboardReport[it->second] = 0; 183 input->keysDown.erase(it); 184 sendKeyboard = true; 185 } 186 else 187 { 188 uint8_t mod = keyToMod(key); 189 190 if (mod) 191 { 192 input->keyboardReport[0] &= ~mod; 193 sendKeyboard = true; 194 } 195 } 196 } 197 198 if (sendKeyboard) 199 { 200 input->writeKeyboard(input->keyboardReport); 201 } 202 } 203 204 void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl) 205 { 206 Server::ClientData* cd = (Server::ClientData*)cl->clientData; 207 Input* input = cd->input; 208 Server* server = (Server*)cl->screen->screenData; 209 const Video& video = server->getVideo(); 210 211 if (input->pointerFd < 0) 212 { 213 return; 214 } 215 216 input->pointerReport[0] = ((buttonMask & 0x4) >> 1) | 217 ((buttonMask & 0x2) << 1) | (buttonMask & 0x1); 218 219 if (x >= 0 && (unsigned int)x < video.getWidth()) 220 { 221 uint16_t xx = (uint16_t)(x * (SHRT_MAX + 1) / video.getWidth()); 222 223 memcpy(&input->pointerReport[1], &xx, 2); 224 } 225 226 if (y >= 0 && (unsigned int)y < video.getHeight()) 227 { 228 uint16_t yy = (uint16_t)(y * (SHRT_MAX + 1) / video.getHeight()); 229 230 memcpy(&input->pointerReport[3], &yy, 2); 231 } 232 233 rfbDefaultPtrAddEvent(buttonMask, x, y, cl); 234 input->writePointer(input->pointerReport); 235 } 236 237 void Input::sendWakeupPacket() 238 { 239 uint8_t wakeupReport[KEY_REPORT_LENGTH] = {0}; 240 241 if (pointerFd >= 0) 242 { 243 uint16_t xy = SHRT_MAX / 2; 244 245 memcpy(&wakeupReport[1], &xy, 2); 246 memcpy(&wakeupReport[3], &xy, 2); 247 248 writePointer(wakeupReport); 249 } 250 251 if (keyboardFd >= 0) 252 { 253 memset(&wakeupReport[0], 0, KEY_REPORT_LENGTH); 254 255 wakeupReport[0] = keyToMod(XK_Shift_L); 256 257 if (!writeKeyboard(wakeupReport)) 258 { 259 return; 260 } 261 262 wakeupReport[0] = 0; 263 264 writeKeyboard(wakeupReport); 265 } 266 } 267 268 uint8_t Input::keyToMod(rfbKeySym key) 269 { 270 uint8_t mod = 0; 271 272 if (key >= XK_Shift_L && key <= XK_Control_R) 273 { 274 mod = shiftCtrlMap[key - XK_Shift_L]; 275 } 276 else if (key >= XK_Meta_L && key <= XK_Alt_R) 277 { 278 mod = metaAltMap[key - XK_Meta_L]; 279 } 280 281 return mod; 282 } 283 284 uint8_t Input::keyToScancode(rfbKeySym key) 285 { 286 uint8_t scancode = 0; 287 288 if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z')) 289 { 290 scancode = USBHID_KEY_A + ((key & 0x5F) - 'A'); 291 } 292 else if (key >= '1' && key <= '9') 293 { 294 scancode = USBHID_KEY_1 + (key - '1'); 295 } 296 else if (key >= XK_F1 && key <= XK_F12) 297 { 298 scancode = USBHID_KEY_F1 + (key - XK_F1); 299 } 300 else if (key >= XK_KP_F1 && key <= XK_KP_F4) 301 { 302 scancode = USBHID_KEY_F1 + (key - XK_KP_F1); 303 } 304 else if (key >= XK_KP_1 && key <= XK_KP_9) 305 { 306 scancode = USBHID_KEY_KP_1 + (key - XK_KP_1); 307 } 308 else 309 { 310 switch (key) 311 { 312 case XK_exclam: 313 scancode = USBHID_KEY_1; 314 break; 315 case XK_at: 316 scancode = USBHID_KEY_2; 317 break; 318 case XK_numbersign: 319 scancode = USBHID_KEY_3; 320 break; 321 case XK_dollar: 322 scancode = USBHID_KEY_4; 323 break; 324 case XK_percent: 325 scancode = USBHID_KEY_5; 326 break; 327 case XK_asciicircum: 328 scancode = USBHID_KEY_6; 329 break; 330 case XK_ampersand: 331 scancode = USBHID_KEY_7; 332 break; 333 case XK_asterisk: 334 scancode = USBHID_KEY_8; 335 break; 336 case XK_parenleft: 337 scancode = USBHID_KEY_9; 338 break; 339 case XK_0: 340 case XK_parenright: 341 scancode = USBHID_KEY_0; 342 break; 343 case XK_Return: 344 scancode = USBHID_KEY_RETURN; 345 break; 346 case XK_Escape: 347 scancode = USBHID_KEY_ESC; 348 break; 349 case XK_BackSpace: 350 scancode = USBHID_KEY_BACKSPACE; 351 break; 352 case XK_Tab: 353 case XK_KP_Tab: 354 scancode = USBHID_KEY_TAB; 355 break; 356 case XK_space: 357 case XK_KP_Space: 358 scancode = USBHID_KEY_SPACE; 359 break; 360 case XK_minus: 361 case XK_underscore: 362 scancode = USBHID_KEY_MINUS; 363 break; 364 case XK_plus: 365 case XK_equal: 366 scancode = USBHID_KEY_EQUAL; 367 break; 368 case XK_bracketleft: 369 case XK_braceleft: 370 scancode = USBHID_KEY_LEFTBRACE; 371 break; 372 case XK_bracketright: 373 case XK_braceright: 374 scancode = USBHID_KEY_RIGHTBRACE; 375 break; 376 case XK_backslash: 377 case XK_bar: 378 scancode = USBHID_KEY_BACKSLASH; 379 break; 380 case XK_colon: 381 case XK_semicolon: 382 scancode = USBHID_KEY_SEMICOLON; 383 break; 384 case XK_quotedbl: 385 case XK_apostrophe: 386 scancode = USBHID_KEY_APOSTROPHE; 387 break; 388 case XK_grave: 389 case XK_asciitilde: 390 scancode = USBHID_KEY_GRAVE; 391 break; 392 case XK_comma: 393 case XK_less: 394 scancode = USBHID_KEY_COMMA; 395 break; 396 case XK_period: 397 case XK_greater: 398 scancode = USBHID_KEY_DOT; 399 break; 400 case XK_slash: 401 case XK_question: 402 scancode = USBHID_KEY_SLASH; 403 break; 404 case XK_Caps_Lock: 405 scancode = USBHID_KEY_CAPSLOCK; 406 break; 407 case XK_Print: 408 scancode = USBHID_KEY_PRINT; 409 break; 410 case XK_Scroll_Lock: 411 scancode = USBHID_KEY_SCROLLLOCK; 412 break; 413 case XK_Pause: 414 scancode = USBHID_KEY_PAUSE; 415 break; 416 case XK_Insert: 417 case XK_KP_Insert: 418 scancode = USBHID_KEY_INSERT; 419 break; 420 case XK_Home: 421 case XK_KP_Home: 422 scancode = USBHID_KEY_HOME; 423 break; 424 case XK_Page_Up: 425 case XK_KP_Page_Up: 426 scancode = USBHID_KEY_PAGEUP; 427 break; 428 case XK_Delete: 429 case XK_KP_Delete: 430 scancode = USBHID_KEY_DELETE; 431 break; 432 case XK_End: 433 case XK_KP_End: 434 scancode = USBHID_KEY_END; 435 break; 436 case XK_Page_Down: 437 case XK_KP_Page_Down: 438 scancode = USBHID_KEY_PAGEDOWN; 439 break; 440 case XK_Right: 441 case XK_KP_Right: 442 scancode = USBHID_KEY_RIGHT; 443 break; 444 case XK_Left: 445 case XK_KP_Left: 446 scancode = USBHID_KEY_LEFT; 447 break; 448 case XK_Down: 449 case XK_KP_Down: 450 scancode = USBHID_KEY_DOWN; 451 break; 452 case XK_Up: 453 case XK_KP_Up: 454 scancode = USBHID_KEY_UP; 455 break; 456 case XK_Num_Lock: 457 scancode = USBHID_KEY_NUMLOCK; 458 break; 459 case XK_KP_Enter: 460 scancode = USBHID_KEY_KP_ENTER; 461 break; 462 case XK_KP_Equal: 463 scancode = USBHID_KEY_KP_EQUAL; 464 break; 465 case XK_KP_Multiply: 466 scancode = USBHID_KEY_KP_MULTIPLY; 467 break; 468 case XK_KP_Add: 469 scancode = USBHID_KEY_KP_ADD; 470 break; 471 case XK_KP_Subtract: 472 scancode = USBHID_KEY_KP_SUBTRACT; 473 break; 474 case XK_KP_Decimal: 475 scancode = USBHID_KEY_KP_DECIMAL; 476 break; 477 case XK_KP_Divide: 478 scancode = USBHID_KEY_KP_DIVIDE; 479 break; 480 case XK_KP_0: 481 scancode = USBHID_KEY_KP_0; 482 break; 483 } 484 } 485 486 return scancode; 487 } 488 489 bool Input::writeKeyboard(const uint8_t *report) 490 { 491 std::unique_lock<std::mutex> lk(keyMutex); 492 uint retryCount = HID_REPORT_RETRY_MAX; 493 494 while (retryCount > 0) 495 { 496 if (write(keyboardFd, report, KEY_REPORT_LENGTH) == KEY_REPORT_LENGTH) 497 { 498 break; 499 } 500 501 if (errno != EAGAIN) 502 { 503 if (errno != ESHUTDOWN) 504 { 505 log<level::ERR>("Failed to write keyboard report", 506 entry("ERROR=%s", strerror(errno))); 507 } 508 509 break; 510 } 511 512 lk.unlock(); 513 std::this_thread::sleep_for(std::chrono::milliseconds(10)); 514 lk.lock(); 515 retryCount--; 516 } 517 518 if (!retryCount || errno) 519 { 520 return false; 521 } 522 523 return true; 524 } 525 526 void Input::writePointer(const uint8_t *report) 527 { 528 std::unique_lock<std::mutex> lk(ptrMutex); 529 uint retryCount = HID_REPORT_RETRY_MAX; 530 531 while (retryCount > 0) 532 { 533 if (write(pointerFd, report, PTR_REPORT_LENGTH) == PTR_REPORT_LENGTH) 534 { 535 break; 536 } 537 538 if (errno != EAGAIN) 539 { 540 if (errno != ESHUTDOWN) 541 { 542 log<level::ERR>("Failed to write pointer report", 543 entry("ERROR=%s", strerror(errno))); 544 } 545 546 break; 547 } 548 549 lk.unlock(); 550 std::this_thread::sleep_for(std::chrono::milliseconds(10)); 551 lk.lock(); 552 retryCount--; 553 } 554 } 555 556 } // namespace ikvm 557