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 ikvm 20 { 21 22 using namespace phosphor::logging; 23 using namespace sdbusplus::xyz::openbmc_project::Common::File::Error; 24 25 Input::Input(const std::string& kbdPath, const std::string& ptrPath) : 26 keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0}, 27 keyboardPath(kbdPath), pointerPath(ptrPath) 28 { 29 if (!keyboardPath.empty()) 30 { 31 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 } 41 } 42 43 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 } 56 } 57 58 Input::~Input() 59 { 60 if (keyboardFd >= 0) 61 { 62 close(keyboardFd); 63 } 64 65 if (pointerFd >= 0) 66 { 67 close(pointerFd); 68 } 69 } 70 71 void 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 { 78 uint8_t sc = keyToScancode(key); 79 80 if (sc) 81 { 82 if (input->keysDown.find(key) == input->keysDown.end()) 83 { 84 for (unsigned int i = 2; i < KEY_REPORT_LENGTH; ++i) 85 { 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 { 98 uint8_t mod = keyToMod(key); 99 100 if (mod) 101 { 102 input->keyboardReport[0] |= mod; 103 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 { 119 uint8_t mod = keyToMod(key); 120 121 if (mod) 122 { 123 input->keyboardReport[0] &= ~mod; 124 input->sendKeyboard = true; 125 } 126 } 127 } 128 } 129 130 void 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 137 input->pointerReport[0] = buttonMask & 0xFF; 138 139 if (x >= 0 && (unsigned int)x < video.getWidth()) 140 { 141 uint16_t xx = x * ((SHRT_MAX + 1) / video.getWidth()); 142 143 memcpy(&input->pointerReport[1], &xx, 2); 144 } 145 146 if (y >= 0 && (unsigned int)y < video.getHeight()) 147 { 148 uint16_t yy = y * ((SHRT_MAX + 1) / video.getHeight()); 149 150 memcpy(&input->pointerReport[3], &yy, 2); 151 } 152 153 input->sendPointer = true; 154 rfbDefaultPtrAddEvent(buttonMask, x, y, cl); 155 } 156 157 void Input::sendWakeupPacket() 158 { 159 uint8_t wakeupReport[PTR_REPORT_LENGTH] = {0}; 160 uint16_t xy = SHRT_MAX / 2; 161 162 if (pointerFd < 0) 163 { 164 return; 165 } 166 167 memcpy(&wakeupReport[1], &xy, 2); 168 memcpy(&wakeupReport[3], &xy, 2); 169 170 if (write(pointerFd, wakeupReport, PTR_REPORT_LENGTH) != PTR_REPORT_LENGTH) 171 { 172 log<level::ERR>("Failed to write report", 173 entry("ERROR=%s", strerror(errno))); 174 } 175 } 176 177 void Input::sendReport() 178 { 179 if (sendKeyboard && keyboardFd >= 0) 180 { 181 if (write(keyboardFd, keyboardReport, KEY_REPORT_LENGTH) != 182 KEY_REPORT_LENGTH) 183 { 184 log<level::ERR>("Failed to write keyboard report", 185 entry("ERROR=%s", strerror(errno))); 186 } 187 188 sendKeyboard = false; 189 } 190 191 if (sendPointer && pointerFd >= 0) 192 { 193 if (write(pointerFd, pointerReport, PTR_REPORT_LENGTH) != 194 PTR_REPORT_LENGTH) 195 { 196 log<level::ERR>("Failed to write pointer report", 197 entry("ERROR=%s", strerror(errno))); 198 } 199 200 sendPointer = false; 201 } 202 } 203 204 uint8_t Input::keyToMod(rfbKeySym key) 205 { 206 uint8_t mod = 0; 207 208 if (key >= XK_Shift_L && key <= XK_Control_R) 209 { 210 mod = shiftCtrlMap[key - XK_Shift_L]; 211 } 212 else if (key >= XK_Meta_L && key <= XK_Alt_R) 213 { 214 mod = metaAltMap[key - XK_Meta_L]; 215 } 216 217 return mod; 218 } 219 220 uint8_t Input::keyToScancode(rfbKeySym key) 221 { 222 uint8_t scancode = 0; 223 224 if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z')) 225 { 226 scancode = USBHID_KEY_A + ((key & 0x5F) - 'A'); 227 } 228 else if (key >= '1' && key <= '9') 229 { 230 scancode = USBHID_KEY_1 + (key - '1'); 231 } 232 else if (key >= XK_F1 && key <= XK_F12) 233 { 234 scancode = USBHID_KEY_F1 + (key - XK_F1); 235 } 236 else 237 { 238 switch (key) 239 { 240 case XK_exclam: 241 scancode = USBHID_KEY_1; 242 break; 243 case XK_at: 244 scancode = USBHID_KEY_2; 245 break; 246 case XK_numbersign: 247 scancode = USBHID_KEY_3; 248 break; 249 case XK_dollar: 250 scancode = USBHID_KEY_4; 251 break; 252 case XK_percent: 253 scancode = USBHID_KEY_5; 254 break; 255 case XK_asciicircum: 256 scancode = USBHID_KEY_6; 257 break; 258 case XK_ampersand: 259 scancode = USBHID_KEY_7; 260 break; 261 case XK_asterisk: 262 scancode = USBHID_KEY_8; 263 break; 264 case XK_parenleft: 265 scancode = USBHID_KEY_9; 266 break; 267 case XK_0: 268 case XK_parenright: 269 scancode = USBHID_KEY_0; 270 break; 271 case XK_Return: 272 scancode = USBHID_KEY_RETURN; 273 break; 274 case XK_Escape: 275 scancode = USBHID_KEY_ESC; 276 break; 277 case XK_BackSpace: 278 scancode = USBHID_KEY_BACKSPACE; 279 break; 280 case XK_Tab: 281 scancode = USBHID_KEY_TAB; 282 break; 283 case XK_space: 284 scancode = USBHID_KEY_SPACE; 285 break; 286 case XK_minus: 287 case XK_underscore: 288 scancode = USBHID_KEY_MINUS; 289 break; 290 case XK_plus: 291 case XK_equal: 292 scancode = USBHID_KEY_EQUAL; 293 break; 294 case XK_bracketleft: 295 case XK_braceleft: 296 scancode = USBHID_KEY_LEFTBRACE; 297 break; 298 case XK_bracketright: 299 case XK_braceright: 300 scancode = USBHID_KEY_RIGHTBRACE; 301 break; 302 case XK_backslash: 303 case XK_bar: 304 scancode = USBHID_KEY_BACKSLASH; 305 break; 306 case XK_colon: 307 case XK_semicolon: 308 scancode = USBHID_KEY_SEMICOLON; 309 break; 310 case XK_quotedbl: 311 case XK_apostrophe: 312 scancode = USBHID_KEY_APOSTROPHE; 313 break; 314 case XK_grave: 315 case XK_asciitilde: 316 scancode = USBHID_KEY_GRAVE; 317 break; 318 case XK_comma: 319 case XK_less: 320 scancode = USBHID_KEY_COMMA; 321 break; 322 case XK_period: 323 case XK_greater: 324 scancode = USBHID_KEY_DOT; 325 break; 326 case XK_slash: 327 case XK_question: 328 scancode = USBHID_KEY_SLASH; 329 break; 330 case XK_Caps_Lock: 331 scancode = USBHID_KEY_CAPSLOCK; 332 break; 333 case XK_Print: 334 scancode = USBHID_KEY_PRINT; 335 break; 336 case XK_Scroll_Lock: 337 scancode = USBHID_KEY_SCROLLLOCK; 338 break; 339 case XK_Pause: 340 scancode = USBHID_KEY_PAUSE; 341 break; 342 case XK_Insert: 343 scancode = USBHID_KEY_INSERT; 344 break; 345 case XK_Home: 346 scancode = USBHID_KEY_HOME; 347 break; 348 case XK_Page_Up: 349 scancode = USBHID_KEY_PAGEUP; 350 break; 351 case XK_Delete: 352 scancode = USBHID_KEY_DELETE; 353 break; 354 case XK_End: 355 scancode = USBHID_KEY_END; 356 break; 357 case XK_Page_Down: 358 scancode = USBHID_KEY_PAGEDOWN; 359 break; 360 case XK_Right: 361 scancode = USBHID_KEY_RIGHT; 362 break; 363 case XK_Left: 364 scancode = USBHID_KEY_LEFT; 365 break; 366 case XK_Down: 367 scancode = USBHID_KEY_DOWN; 368 break; 369 case XK_Up: 370 scancode = USBHID_KEY_UP; 371 break; 372 case XK_Num_Lock: 373 scancode = USBHID_KEY_NUMLOCK; 374 break; 375 } 376 } 377 378 return scancode; 379 } 380 381 } // namespace ikvm 382