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