xref: /openbmc/obmc-ikvm/ikvm_input.cpp (revision 94f5f422b6b862606ca96108c2538ed32c5ec104)
121b177e0SEddie James #include "ikvm_input.hpp"
221b177e0SEddie James 
321b177e0SEddie James #include "ikvm_server.hpp"
4f79f6f54SGeorge Liu #include "scancodes.hpp"
521b177e0SEddie James 
621b177e0SEddie James #include <err.h>
721b177e0SEddie James #include <errno.h>
821b177e0SEddie James #include <fcntl.h>
921b177e0SEddie James #include <rfb/keysym.h>
1021b177e0SEddie James #include <sys/stat.h>
1121b177e0SEddie James #include <sys/types.h>
1221b177e0SEddie James 
1321b177e0SEddie James #include <phosphor-logging/elog-errors.hpp>
1421b177e0SEddie James #include <phosphor-logging/elog.hpp>
1521b177e0SEddie James #include <phosphor-logging/log.hpp>
1621b177e0SEddie James #include <xyz/openbmc_project/Common/File/error.hpp>
1721b177e0SEddie James 
18c11257d8SJae Hyun Yoo namespace fs = std::filesystem;
19c11257d8SJae Hyun Yoo 
2021b177e0SEddie James namespace ikvm
2121b177e0SEddie James {
2221b177e0SEddie James using namespace phosphor::logging;
2321b177e0SEddie James using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
2421b177e0SEddie James 
Input(const std::string & kbdPath,const std::string & ptrPath,const std::string & udc)25fe685fb4SMarvin Lin Input::Input(const std::string& kbdPath, const std::string& ptrPath,
26fe685fb4SMarvin Lin              const std::string& udc) :
27*94f5f422SPatrick Williams     keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0},
28*94f5f422SPatrick Williams     keyboardPath(kbdPath), pointerPath(ptrPath), udcName(udc)
2921b177e0SEddie James {
30c11257d8SJae Hyun Yoo     hidUdcStream.exceptions(std::ofstream::failbit | std::ofstream::badbit);
31c11257d8SJae Hyun Yoo     hidUdcStream.open(hidUdcPath, std::ios::out | std::ios::app);
32c11257d8SJae Hyun Yoo }
33c11257d8SJae Hyun Yoo 
~Input()34c11257d8SJae Hyun Yoo Input::~Input()
35c11257d8SJae Hyun Yoo {
36c11257d8SJae Hyun Yoo     if (keyboardFd >= 0)
37c11257d8SJae Hyun Yoo     {
38c11257d8SJae Hyun Yoo         close(keyboardFd);
39c11257d8SJae Hyun Yoo     }
40c11257d8SJae Hyun Yoo 
41c11257d8SJae Hyun Yoo     if (pointerFd >= 0)
42c11257d8SJae Hyun Yoo     {
43c11257d8SJae Hyun Yoo         close(pointerFd);
44c11257d8SJae Hyun Yoo     }
45c11257d8SJae Hyun Yoo 
46c11257d8SJae Hyun Yoo     disconnect();
47c11257d8SJae Hyun Yoo     hidUdcStream.close();
48c11257d8SJae Hyun Yoo }
49c11257d8SJae Hyun Yoo 
connect()50c11257d8SJae Hyun Yoo void Input::connect()
51c11257d8SJae Hyun Yoo {
52c11257d8SJae Hyun Yoo     try
53c11257d8SJae Hyun Yoo     {
54fe685fb4SMarvin Lin         if (udcName.empty())
55fe685fb4SMarvin Lin         {
5620de859fSTroy Lee             bool found = false;
57c11257d8SJae Hyun Yoo             for (const auto& port : fs::directory_iterator(usbVirtualHubPath))
58c11257d8SJae Hyun Yoo             {
5920de859fSTroy Lee                 // /sys/bus/platform/devices/1e6a0000.usb-vhub/1e6a0000.usb-vhub:pX
6020de859fSTroy Lee                 if (fs::is_directory(port) && !fs::is_symlink(port))
61c11257d8SJae Hyun Yoo                 {
6220de859fSTroy Lee                     for (const auto& gadget :
6320de859fSTroy Lee                          fs::directory_iterator(port.path()))
6420de859fSTroy Lee                     {
6520de859fSTroy Lee                         // Kernel 6.0:
6620de859fSTroy Lee                         // /sys/.../1e6a0000.usb-vhub:pX/gadget.Y/suspended
6720de859fSTroy Lee                         // Kernel 5.15:
6820de859fSTroy Lee                         // /sys/.../1e6a0000.usb-vhub:pX/gadget/suspended
6920de859fSTroy Lee                         if (fs::is_directory(gadget) &&
7020de859fSTroy Lee                             gadget.path().string().find("gadget") !=
7120de859fSTroy Lee                                 std::string::npos &&
7220de859fSTroy Lee                             !fs::exists(gadget.path() / "suspended"))
7320de859fSTroy Lee                         {
744148d0c6STroy Lee                             const std::string portId = port.path().filename();
75c11257d8SJae Hyun Yoo                             hidUdcStream << portId << std::endl;
7620de859fSTroy Lee                             found = true;
7720de859fSTroy Lee                             break;
7820de859fSTroy Lee                         }
7920de859fSTroy Lee                     }
8020de859fSTroy Lee                 }
8120de859fSTroy Lee                 if (found)
8220de859fSTroy Lee                 {
83c11257d8SJae Hyun Yoo                     break;
84c11257d8SJae Hyun Yoo                 }
85c11257d8SJae Hyun Yoo             }
86c11257d8SJae Hyun Yoo         }
87fe685fb4SMarvin Lin         else // If UDC has been specified by '-u' parameter, connect to it.
88fe685fb4SMarvin Lin         {
89fe685fb4SMarvin Lin             hidUdcStream << udcName << std::endl;
90fe685fb4SMarvin Lin         }
91fe685fb4SMarvin Lin     }
92c11257d8SJae Hyun Yoo     catch (fs::filesystem_error& e)
93c11257d8SJae Hyun Yoo     {
94c11257d8SJae Hyun Yoo         log<level::ERR>("Failed to search USB virtual hub port",
95c11257d8SJae Hyun Yoo                         entry("ERROR=%s", e.what()));
96c11257d8SJae Hyun Yoo         return;
97c11257d8SJae Hyun Yoo     }
98c11257d8SJae Hyun Yoo     catch (std::ofstream::failure& e)
99c11257d8SJae Hyun Yoo     {
100c11257d8SJae Hyun Yoo         log<level::ERR>("Failed to connect HID gadget",
101c11257d8SJae Hyun Yoo                         entry("ERROR=%s", e.what()));
102c11257d8SJae Hyun Yoo         return;
103c11257d8SJae Hyun Yoo     }
104c11257d8SJae Hyun Yoo 
1057dfac9ffSJae Hyun Yoo     if (!keyboardPath.empty())
1067dfac9ffSJae Hyun Yoo     {
107*94f5f422SPatrick Williams         keyboardFd =
108*94f5f422SPatrick Williams             open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
1097dfac9ffSJae Hyun Yoo         if (keyboardFd < 0)
11021b177e0SEddie James         {
11121b177e0SEddie James             log<level::ERR>("Failed to open input device",
1127dfac9ffSJae Hyun Yoo                             entry("PATH=%s", keyboardPath.c_str()),
11321b177e0SEddie James                             entry("ERROR=%s", strerror(errno)));
1147dfac9ffSJae Hyun Yoo             elog<Open>(xyz::openbmc_project::Common::File::Open::ERRNO(errno),
1157dfac9ffSJae Hyun Yoo                        xyz::openbmc_project::Common::File::Open::PATH(
1167dfac9ffSJae Hyun Yoo                            keyboardPath.c_str()));
1177dfac9ffSJae Hyun Yoo         }
11821b177e0SEddie James     }
11921b177e0SEddie James 
1207dfac9ffSJae Hyun Yoo     if (!pointerPath.empty())
1217dfac9ffSJae Hyun Yoo     {
1224749f934SEddie James         pointerFd = open(pointerPath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
1237dfac9ffSJae Hyun Yoo         if (pointerFd < 0)
1247dfac9ffSJae Hyun Yoo         {
1257dfac9ffSJae Hyun Yoo             log<level::ERR>("Failed to open input device",
1267dfac9ffSJae Hyun Yoo                             entry("PATH=%s", pointerPath.c_str()),
1277dfac9ffSJae Hyun Yoo                             entry("ERROR=%s", strerror(errno)));
1287dfac9ffSJae Hyun Yoo             elog<Open>(xyz::openbmc_project::Common::File::Open::ERRNO(errno),
1297dfac9ffSJae Hyun Yoo                        xyz::openbmc_project::Common::File::Open::PATH(
1307dfac9ffSJae Hyun Yoo                            pointerPath.c_str()));
1317dfac9ffSJae Hyun Yoo         }
1327dfac9ffSJae Hyun Yoo     }
13321b177e0SEddie James }
13421b177e0SEddie James 
disconnect()135c11257d8SJae Hyun Yoo void Input::disconnect()
13621b177e0SEddie James {
1377dfac9ffSJae Hyun Yoo     if (keyboardFd >= 0)
1387dfac9ffSJae Hyun Yoo     {
1397dfac9ffSJae Hyun Yoo         close(keyboardFd);
140c11257d8SJae Hyun Yoo         keyboardFd = -1;
1417dfac9ffSJae Hyun Yoo     }
1427dfac9ffSJae Hyun Yoo 
1437dfac9ffSJae Hyun Yoo     if (pointerFd >= 0)
1447dfac9ffSJae Hyun Yoo     {
1457dfac9ffSJae Hyun Yoo         close(pointerFd);
146c11257d8SJae Hyun Yoo         pointerFd = -1;
147c11257d8SJae Hyun Yoo     }
148c11257d8SJae Hyun Yoo 
149c11257d8SJae Hyun Yoo     try
150c11257d8SJae Hyun Yoo     {
151c11257d8SJae Hyun Yoo         hidUdcStream << "" << std::endl;
152c11257d8SJae Hyun Yoo     }
153c11257d8SJae Hyun Yoo     catch (std::ofstream::failure& e)
154c11257d8SJae Hyun Yoo     {
155c11257d8SJae Hyun Yoo         log<level::ERR>("Failed to disconnect HID gadget",
156c11257d8SJae Hyun Yoo                         entry("ERROR=%s", e.what()));
1577dfac9ffSJae Hyun Yoo     }
15821b177e0SEddie James }
15921b177e0SEddie James 
keyEvent(rfbBool down,rfbKeySym key,rfbClientPtr cl)16021b177e0SEddie James void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl)
16121b177e0SEddie James {
16221b177e0SEddie James     Server::ClientData* cd = (Server::ClientData*)cl->clientData;
16321b177e0SEddie James     Input* input = cd->input;
164673ac2ebSJae Hyun Yoo     bool sendKeyboard = false;
165673ac2ebSJae Hyun Yoo 
166673ac2ebSJae Hyun Yoo     if (input->keyboardFd < 0)
167673ac2ebSJae Hyun Yoo     {
168673ac2ebSJae Hyun Yoo         return;
169673ac2ebSJae Hyun Yoo     }
17021b177e0SEddie James 
17121b177e0SEddie James     if (down)
17221b177e0SEddie James     {
1737dfac9ffSJae Hyun Yoo         uint8_t sc = keyToScancode(key);
17421b177e0SEddie James 
17521b177e0SEddie James         if (sc)
17621b177e0SEddie James         {
17721b177e0SEddie James             if (input->keysDown.find(key) == input->keysDown.end())
17821b177e0SEddie James             {
1797dfac9ffSJae Hyun Yoo                 for (unsigned int i = 2; i < KEY_REPORT_LENGTH; ++i)
18021b177e0SEddie James                 {
18121b177e0SEddie James                     if (!input->keyboardReport[i])
18221b177e0SEddie James                     {
18321b177e0SEddie James                         input->keyboardReport[i] = sc;
18421b177e0SEddie James                         input->keysDown.insert(std::make_pair(key, i));
185673ac2ebSJae Hyun Yoo                         sendKeyboard = true;
18621b177e0SEddie James                         break;
18721b177e0SEddie James                     }
18821b177e0SEddie James                 }
18921b177e0SEddie James             }
19021b177e0SEddie James         }
19121b177e0SEddie James         else
19221b177e0SEddie James         {
1937dfac9ffSJae Hyun Yoo             uint8_t mod = keyToMod(key);
19421b177e0SEddie James 
19521b177e0SEddie James             if (mod)
19621b177e0SEddie James             {
1977dfac9ffSJae Hyun Yoo                 input->keyboardReport[0] |= mod;
198673ac2ebSJae Hyun Yoo                 sendKeyboard = true;
19921b177e0SEddie James             }
20021b177e0SEddie James         }
20121b177e0SEddie James     }
20221b177e0SEddie James     else
20321b177e0SEddie James     {
20421b177e0SEddie James         auto it = input->keysDown.find(key);
20521b177e0SEddie James 
20621b177e0SEddie James         if (it != input->keysDown.end())
20721b177e0SEddie James         {
20821b177e0SEddie James             input->keyboardReport[it->second] = 0;
20921b177e0SEddie James             input->keysDown.erase(it);
210673ac2ebSJae Hyun Yoo             sendKeyboard = true;
21121b177e0SEddie James         }
21221b177e0SEddie James         else
21321b177e0SEddie James         {
2147dfac9ffSJae Hyun Yoo             uint8_t mod = keyToMod(key);
21521b177e0SEddie James 
21621b177e0SEddie James             if (mod)
21721b177e0SEddie James             {
2187dfac9ffSJae Hyun Yoo                 input->keyboardReport[0] &= ~mod;
219673ac2ebSJae Hyun Yoo                 sendKeyboard = true;
22021b177e0SEddie James             }
22121b177e0SEddie James         }
22221b177e0SEddie James     }
223673ac2ebSJae Hyun Yoo 
224673ac2ebSJae Hyun Yoo     if (sendKeyboard)
225673ac2ebSJae Hyun Yoo     {
226673ac2ebSJae Hyun Yoo         input->writeKeyboard(input->keyboardReport);
227673ac2ebSJae Hyun Yoo     }
22821b177e0SEddie James }
22921b177e0SEddie James 
pointerEvent(int buttonMask,int x,int y,rfbClientPtr cl)23021b177e0SEddie James void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl)
23121b177e0SEddie James {
23221b177e0SEddie James     Server::ClientData* cd = (Server::ClientData*)cl->clientData;
23321b177e0SEddie James     Input* input = cd->input;
23421b177e0SEddie James     Server* server = (Server*)cl->screen->screenData;
23521b177e0SEddie James     const Video& video = server->getVideo();
23621b177e0SEddie James 
237673ac2ebSJae Hyun Yoo     if (input->pointerFd < 0)
238673ac2ebSJae Hyun Yoo     {
239673ac2ebSJae Hyun Yoo         return;
240673ac2ebSJae Hyun Yoo     }
241673ac2ebSJae Hyun Yoo 
2423fa0bfbaSTejas Patil     if (buttonMask > 4)
2433fa0bfbaSTejas Patil     {
2443fa0bfbaSTejas Patil         input->pointerReport[0] = 0;
2453fa0bfbaSTejas Patil         if (buttonMask == 8)
2463fa0bfbaSTejas Patil         {
2473fa0bfbaSTejas Patil             input->pointerReport[5] = 1;
2483fa0bfbaSTejas Patil         }
2493fa0bfbaSTejas Patil         else if (buttonMask == 16)
2503fa0bfbaSTejas Patil         {
2513fa0bfbaSTejas Patil             input->pointerReport[5] = 0xff;
2523fa0bfbaSTejas Patil         }
2533fa0bfbaSTejas Patil     }
2543fa0bfbaSTejas Patil     else
2553fa0bfbaSTejas Patil     {
256*94f5f422SPatrick Williams         input->pointerReport[0] =
257*94f5f422SPatrick Williams             ((buttonMask & 0x4) >> 1) | ((buttonMask & 0x2) << 1) |
258f79f6f54SGeorge Liu             (buttonMask & 0x1);
2593fa0bfbaSTejas Patil         input->pointerReport[5] = 0;
2603fa0bfbaSTejas Patil     }
26121b177e0SEddie James 
26221b177e0SEddie James     if (x >= 0 && (unsigned int)x < video.getWidth())
26321b177e0SEddie James     {
2642bc661d3SJae Hyun Yoo         uint16_t xx = (uint16_t)(x * (SHRT_MAX + 1) / video.getWidth());
26521b177e0SEddie James 
2667dfac9ffSJae Hyun Yoo         memcpy(&input->pointerReport[1], &xx, 2);
26721b177e0SEddie James     }
26821b177e0SEddie James 
26921b177e0SEddie James     if (y >= 0 && (unsigned int)y < video.getHeight())
27021b177e0SEddie James     {
2712bc661d3SJae Hyun Yoo         uint16_t yy = (uint16_t)(y * (SHRT_MAX + 1) / video.getHeight());
27221b177e0SEddie James 
2737dfac9ffSJae Hyun Yoo         memcpy(&input->pointerReport[3], &yy, 2);
27421b177e0SEddie James     }
27521b177e0SEddie James 
27621b177e0SEddie James     rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
277673ac2ebSJae Hyun Yoo     input->writePointer(input->pointerReport);
27821b177e0SEddie James }
27921b177e0SEddie James 
sendWakeupPacket()2807dfac9ffSJae Hyun Yoo void Input::sendWakeupPacket()
28121b177e0SEddie James {
282eaf5c5b6SJae Hyun Yoo     uint8_t wakeupReport[KEY_REPORT_LENGTH] = {0};
2837dfac9ffSJae Hyun Yoo 
284eaf5c5b6SJae Hyun Yoo     if (pointerFd >= 0)
2857dfac9ffSJae Hyun Yoo     {
286eaf5c5b6SJae Hyun Yoo         uint16_t xy = SHRT_MAX / 2;
2877dfac9ffSJae Hyun Yoo 
2887dfac9ffSJae Hyun Yoo         memcpy(&wakeupReport[1], &xy, 2);
2897dfac9ffSJae Hyun Yoo         memcpy(&wakeupReport[3], &xy, 2);
2907dfac9ffSJae Hyun Yoo 
2917cf1f1d4SEddie James         writePointer(wakeupReport);
29221b177e0SEddie James     }
29321b177e0SEddie James 
294eaf5c5b6SJae Hyun Yoo     if (keyboardFd >= 0)
295eaf5c5b6SJae Hyun Yoo     {
296eaf5c5b6SJae Hyun Yoo         memset(&wakeupReport[0], 0, KEY_REPORT_LENGTH);
297eaf5c5b6SJae Hyun Yoo 
298eaf5c5b6SJae Hyun Yoo         wakeupReport[0] = keyToMod(XK_Shift_L);
299eaf5c5b6SJae Hyun Yoo 
3007cf1f1d4SEddie James         if (!writeKeyboard(wakeupReport))
301eaf5c5b6SJae Hyun Yoo         {
302eaf5c5b6SJae Hyun Yoo             return;
303eaf5c5b6SJae Hyun Yoo         }
304eaf5c5b6SJae Hyun Yoo 
305eaf5c5b6SJae Hyun Yoo         wakeupReport[0] = 0;
306eaf5c5b6SJae Hyun Yoo 
3077cf1f1d4SEddie James         writeKeyboard(wakeupReport);
308eaf5c5b6SJae Hyun Yoo     }
309eaf5c5b6SJae Hyun Yoo }
310eaf5c5b6SJae Hyun Yoo 
keyToMod(rfbKeySym key)3117dfac9ffSJae Hyun Yoo uint8_t Input::keyToMod(rfbKeySym key)
31221b177e0SEddie James {
3137dfac9ffSJae Hyun Yoo     uint8_t mod = 0;
31421b177e0SEddie James 
31521b177e0SEddie James     if (key >= XK_Shift_L && key <= XK_Control_R)
31621b177e0SEddie James     {
31721b177e0SEddie James         mod = shiftCtrlMap[key - XK_Shift_L];
31821b177e0SEddie James     }
31921b177e0SEddie James     else if (key >= XK_Meta_L && key <= XK_Alt_R)
32021b177e0SEddie James     {
32121b177e0SEddie James         mod = metaAltMap[key - XK_Meta_L];
32221b177e0SEddie James     }
32321b177e0SEddie James 
32421b177e0SEddie James     return mod;
32521b177e0SEddie James }
32621b177e0SEddie James 
keyToScancode(rfbKeySym key)3277dfac9ffSJae Hyun Yoo uint8_t Input::keyToScancode(rfbKeySym key)
32821b177e0SEddie James {
3297dfac9ffSJae Hyun Yoo     uint8_t scancode = 0;
33021b177e0SEddie James 
33121b177e0SEddie James     if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'))
33221b177e0SEddie James     {
33321b177e0SEddie James         scancode = USBHID_KEY_A + ((key & 0x5F) - 'A');
33421b177e0SEddie James     }
33521b177e0SEddie James     else if (key >= '1' && key <= '9')
33621b177e0SEddie James     {
33721b177e0SEddie James         scancode = USBHID_KEY_1 + (key - '1');
33821b177e0SEddie James     }
33921b177e0SEddie James     else if (key >= XK_F1 && key <= XK_F12)
34021b177e0SEddie James     {
34121b177e0SEddie James         scancode = USBHID_KEY_F1 + (key - XK_F1);
34221b177e0SEddie James     }
343513d95efSJae Hyun Yoo     else if (key >= XK_KP_F1 && key <= XK_KP_F4)
344513d95efSJae Hyun Yoo     {
345513d95efSJae Hyun Yoo         scancode = USBHID_KEY_F1 + (key - XK_KP_F1);
346513d95efSJae Hyun Yoo     }
347513d95efSJae Hyun Yoo     else if (key >= XK_KP_1 && key <= XK_KP_9)
348513d95efSJae Hyun Yoo     {
349513d95efSJae Hyun Yoo         scancode = USBHID_KEY_KP_1 + (key - XK_KP_1);
350513d95efSJae Hyun Yoo     }
35121b177e0SEddie James     else
35221b177e0SEddie James     {
35321b177e0SEddie James         switch (key)
35421b177e0SEddie James         {
35521b177e0SEddie James             case XK_exclam:
35621b177e0SEddie James                 scancode = USBHID_KEY_1;
35721b177e0SEddie James                 break;
35821b177e0SEddie James             case XK_at:
35921b177e0SEddie James                 scancode = USBHID_KEY_2;
36021b177e0SEddie James                 break;
36121b177e0SEddie James             case XK_numbersign:
36221b177e0SEddie James                 scancode = USBHID_KEY_3;
36321b177e0SEddie James                 break;
36421b177e0SEddie James             case XK_dollar:
36521b177e0SEddie James                 scancode = USBHID_KEY_4;
36621b177e0SEddie James                 break;
36721b177e0SEddie James             case XK_percent:
36821b177e0SEddie James                 scancode = USBHID_KEY_5;
36921b177e0SEddie James                 break;
37021b177e0SEddie James             case XK_asciicircum:
37121b177e0SEddie James                 scancode = USBHID_KEY_6;
37221b177e0SEddie James                 break;
37321b177e0SEddie James             case XK_ampersand:
37421b177e0SEddie James                 scancode = USBHID_KEY_7;
37521b177e0SEddie James                 break;
37621b177e0SEddie James             case XK_asterisk:
37721b177e0SEddie James                 scancode = USBHID_KEY_8;
37821b177e0SEddie James                 break;
37921b177e0SEddie James             case XK_parenleft:
38021b177e0SEddie James                 scancode = USBHID_KEY_9;
38121b177e0SEddie James                 break;
38221b177e0SEddie James             case XK_0:
38321b177e0SEddie James             case XK_parenright:
38421b177e0SEddie James                 scancode = USBHID_KEY_0;
38521b177e0SEddie James                 break;
38621b177e0SEddie James             case XK_Return:
38721b177e0SEddie James                 scancode = USBHID_KEY_RETURN;
38821b177e0SEddie James                 break;
38921b177e0SEddie James             case XK_Escape:
39021b177e0SEddie James                 scancode = USBHID_KEY_ESC;
39121b177e0SEddie James                 break;
39221b177e0SEddie James             case XK_BackSpace:
39321b177e0SEddie James                 scancode = USBHID_KEY_BACKSPACE;
39421b177e0SEddie James                 break;
39521b177e0SEddie James             case XK_Tab:
396513d95efSJae Hyun Yoo             case XK_KP_Tab:
39721b177e0SEddie James                 scancode = USBHID_KEY_TAB;
39821b177e0SEddie James                 break;
39921b177e0SEddie James             case XK_space:
400513d95efSJae Hyun Yoo             case XK_KP_Space:
40121b177e0SEddie James                 scancode = USBHID_KEY_SPACE;
40221b177e0SEddie James                 break;
40321b177e0SEddie James             case XK_minus:
40421b177e0SEddie James             case XK_underscore:
40521b177e0SEddie James                 scancode = USBHID_KEY_MINUS;
40621b177e0SEddie James                 break;
40721b177e0SEddie James             case XK_plus:
40821b177e0SEddie James             case XK_equal:
40921b177e0SEddie James                 scancode = USBHID_KEY_EQUAL;
41021b177e0SEddie James                 break;
41121b177e0SEddie James             case XK_bracketleft:
41221b177e0SEddie James             case XK_braceleft:
41321b177e0SEddie James                 scancode = USBHID_KEY_LEFTBRACE;
41421b177e0SEddie James                 break;
41521b177e0SEddie James             case XK_bracketright:
41621b177e0SEddie James             case XK_braceright:
41721b177e0SEddie James                 scancode = USBHID_KEY_RIGHTBRACE;
41821b177e0SEddie James                 break;
41921b177e0SEddie James             case XK_backslash:
42021b177e0SEddie James             case XK_bar:
42121b177e0SEddie James                 scancode = USBHID_KEY_BACKSLASH;
42221b177e0SEddie James                 break;
42321b177e0SEddie James             case XK_colon:
42421b177e0SEddie James             case XK_semicolon:
42521b177e0SEddie James                 scancode = USBHID_KEY_SEMICOLON;
42621b177e0SEddie James                 break;
42721b177e0SEddie James             case XK_quotedbl:
42821b177e0SEddie James             case XK_apostrophe:
42921b177e0SEddie James                 scancode = USBHID_KEY_APOSTROPHE;
43021b177e0SEddie James                 break;
43121b177e0SEddie James             case XK_grave:
43221b177e0SEddie James             case XK_asciitilde:
43321b177e0SEddie James                 scancode = USBHID_KEY_GRAVE;
43421b177e0SEddie James                 break;
43521b177e0SEddie James             case XK_comma:
43621b177e0SEddie James             case XK_less:
43721b177e0SEddie James                 scancode = USBHID_KEY_COMMA;
43821b177e0SEddie James                 break;
43921b177e0SEddie James             case XK_period:
44021b177e0SEddie James             case XK_greater:
44121b177e0SEddie James                 scancode = USBHID_KEY_DOT;
44221b177e0SEddie James                 break;
44321b177e0SEddie James             case XK_slash:
44421b177e0SEddie James             case XK_question:
44521b177e0SEddie James                 scancode = USBHID_KEY_SLASH;
44621b177e0SEddie James                 break;
44721b177e0SEddie James             case XK_Caps_Lock:
44821b177e0SEddie James                 scancode = USBHID_KEY_CAPSLOCK;
44921b177e0SEddie James                 break;
45021b177e0SEddie James             case XK_Print:
45121b177e0SEddie James                 scancode = USBHID_KEY_PRINT;
45221b177e0SEddie James                 break;
45321b177e0SEddie James             case XK_Scroll_Lock:
45421b177e0SEddie James                 scancode = USBHID_KEY_SCROLLLOCK;
45521b177e0SEddie James                 break;
45621b177e0SEddie James             case XK_Pause:
45721b177e0SEddie James                 scancode = USBHID_KEY_PAUSE;
45821b177e0SEddie James                 break;
45921b177e0SEddie James             case XK_Insert:
460513d95efSJae Hyun Yoo             case XK_KP_Insert:
46121b177e0SEddie James                 scancode = USBHID_KEY_INSERT;
46221b177e0SEddie James                 break;
46321b177e0SEddie James             case XK_Home:
464513d95efSJae Hyun Yoo             case XK_KP_Home:
46521b177e0SEddie James                 scancode = USBHID_KEY_HOME;
46621b177e0SEddie James                 break;
46721b177e0SEddie James             case XK_Page_Up:
468513d95efSJae Hyun Yoo             case XK_KP_Page_Up:
46921b177e0SEddie James                 scancode = USBHID_KEY_PAGEUP;
47021b177e0SEddie James                 break;
47121b177e0SEddie James             case XK_Delete:
472513d95efSJae Hyun Yoo             case XK_KP_Delete:
47321b177e0SEddie James                 scancode = USBHID_KEY_DELETE;
47421b177e0SEddie James                 break;
47521b177e0SEddie James             case XK_End:
476513d95efSJae Hyun Yoo             case XK_KP_End:
47721b177e0SEddie James                 scancode = USBHID_KEY_END;
47821b177e0SEddie James                 break;
47921b177e0SEddie James             case XK_Page_Down:
480513d95efSJae Hyun Yoo             case XK_KP_Page_Down:
48121b177e0SEddie James                 scancode = USBHID_KEY_PAGEDOWN;
48221b177e0SEddie James                 break;
48321b177e0SEddie James             case XK_Right:
484513d95efSJae Hyun Yoo             case XK_KP_Right:
48521b177e0SEddie James                 scancode = USBHID_KEY_RIGHT;
48621b177e0SEddie James                 break;
48721b177e0SEddie James             case XK_Left:
488513d95efSJae Hyun Yoo             case XK_KP_Left:
48921b177e0SEddie James                 scancode = USBHID_KEY_LEFT;
49021b177e0SEddie James                 break;
49121b177e0SEddie James             case XK_Down:
492513d95efSJae Hyun Yoo             case XK_KP_Down:
49321b177e0SEddie James                 scancode = USBHID_KEY_DOWN;
49421b177e0SEddie James                 break;
49521b177e0SEddie James             case XK_Up:
496513d95efSJae Hyun Yoo             case XK_KP_Up:
49721b177e0SEddie James                 scancode = USBHID_KEY_UP;
49821b177e0SEddie James                 break;
49921b177e0SEddie James             case XK_Num_Lock:
50021b177e0SEddie James                 scancode = USBHID_KEY_NUMLOCK;
50121b177e0SEddie James                 break;
502513d95efSJae Hyun Yoo             case XK_KP_Enter:
503513d95efSJae Hyun Yoo                 scancode = USBHID_KEY_KP_ENTER;
504513d95efSJae Hyun Yoo                 break;
505513d95efSJae Hyun Yoo             case XK_KP_Equal:
506513d95efSJae Hyun Yoo                 scancode = USBHID_KEY_KP_EQUAL;
507513d95efSJae Hyun Yoo                 break;
508513d95efSJae Hyun Yoo             case XK_KP_Multiply:
509513d95efSJae Hyun Yoo                 scancode = USBHID_KEY_KP_MULTIPLY;
510513d95efSJae Hyun Yoo                 break;
511513d95efSJae Hyun Yoo             case XK_KP_Add:
512513d95efSJae Hyun Yoo                 scancode = USBHID_KEY_KP_ADD;
513513d95efSJae Hyun Yoo                 break;
514513d95efSJae Hyun Yoo             case XK_KP_Subtract:
515513d95efSJae Hyun Yoo                 scancode = USBHID_KEY_KP_SUBTRACT;
516513d95efSJae Hyun Yoo                 break;
517513d95efSJae Hyun Yoo             case XK_KP_Decimal:
518513d95efSJae Hyun Yoo                 scancode = USBHID_KEY_KP_DECIMAL;
519513d95efSJae Hyun Yoo                 break;
520513d95efSJae Hyun Yoo             case XK_KP_Divide:
521513d95efSJae Hyun Yoo                 scancode = USBHID_KEY_KP_DIVIDE;
522513d95efSJae Hyun Yoo                 break;
523513d95efSJae Hyun Yoo             case XK_KP_0:
524513d95efSJae Hyun Yoo                 scancode = USBHID_KEY_KP_0;
525513d95efSJae Hyun Yoo                 break;
52621b177e0SEddie James         }
52721b177e0SEddie James     }
52821b177e0SEddie James 
52921b177e0SEddie James     return scancode;
53021b177e0SEddie James }
53121b177e0SEddie James 
writeKeyboard(const uint8_t * report)5327cf1f1d4SEddie James bool Input::writeKeyboard(const uint8_t* report)
5337cf1f1d4SEddie James {
534673ac2ebSJae Hyun Yoo     std::unique_lock<std::mutex> lk(keyMutex);
535673ac2ebSJae Hyun Yoo     uint retryCount = HID_REPORT_RETRY_MAX;
536673ac2ebSJae Hyun Yoo 
537673ac2ebSJae Hyun Yoo     while (retryCount > 0)
5387cf1f1d4SEddie James     {
539673ac2ebSJae Hyun Yoo         if (write(keyboardFd, report, KEY_REPORT_LENGTH) == KEY_REPORT_LENGTH)
540673ac2ebSJae Hyun Yoo         {
54140fd5429SZev Weiss             return true;
542673ac2ebSJae Hyun Yoo         }
543673ac2ebSJae Hyun Yoo 
544673ac2ebSJae Hyun Yoo         if (errno != EAGAIN)
545673ac2ebSJae Hyun Yoo         {
546673ac2ebSJae Hyun Yoo             if (errno != ESHUTDOWN)
5477a89cd23SJae Hyun Yoo             {
5487cf1f1d4SEddie James                 log<level::ERR>("Failed to write keyboard report",
5497cf1f1d4SEddie James                                 entry("ERROR=%s", strerror(errno)));
5507cf1f1d4SEddie James             }
5517cf1f1d4SEddie James 
552673ac2ebSJae Hyun Yoo             break;
553673ac2ebSJae Hyun Yoo         }
554673ac2ebSJae Hyun Yoo 
555673ac2ebSJae Hyun Yoo         lk.unlock();
556673ac2ebSJae Hyun Yoo         std::this_thread::sleep_for(std::chrono::milliseconds(10));
557673ac2ebSJae Hyun Yoo         lk.lock();
558673ac2ebSJae Hyun Yoo         retryCount--;
559673ac2ebSJae Hyun Yoo     }
560673ac2ebSJae Hyun Yoo 
5617cf1f1d4SEddie James     return false;
5627cf1f1d4SEddie James }
5637cf1f1d4SEddie James 
writePointer(const uint8_t * report)5647cf1f1d4SEddie James void Input::writePointer(const uint8_t* report)
5657cf1f1d4SEddie James {
566673ac2ebSJae Hyun Yoo     std::unique_lock<std::mutex> lk(ptrMutex);
567673ac2ebSJae Hyun Yoo     uint retryCount = HID_REPORT_RETRY_MAX;
568673ac2ebSJae Hyun Yoo 
569673ac2ebSJae Hyun Yoo     while (retryCount > 0)
5707cf1f1d4SEddie James     {
571673ac2ebSJae Hyun Yoo         if (write(pointerFd, report, PTR_REPORT_LENGTH) == PTR_REPORT_LENGTH)
572673ac2ebSJae Hyun Yoo         {
573673ac2ebSJae Hyun Yoo             break;
574673ac2ebSJae Hyun Yoo         }
575673ac2ebSJae Hyun Yoo 
576673ac2ebSJae Hyun Yoo         if (errno != EAGAIN)
577673ac2ebSJae Hyun Yoo         {
578673ac2ebSJae Hyun Yoo             if (errno != ESHUTDOWN)
5797cf1f1d4SEddie James             {
5807cf1f1d4SEddie James                 log<level::ERR>("Failed to write pointer report",
5817cf1f1d4SEddie James                                 entry("ERROR=%s", strerror(errno)));
5827cf1f1d4SEddie James             }
583673ac2ebSJae Hyun Yoo 
584673ac2ebSJae Hyun Yoo             break;
585673ac2ebSJae Hyun Yoo         }
586673ac2ebSJae Hyun Yoo 
587673ac2ebSJae Hyun Yoo         lk.unlock();
588673ac2ebSJae Hyun Yoo         std::this_thread::sleep_for(std::chrono::milliseconds(10));
589673ac2ebSJae Hyun Yoo         lk.lock();
590673ac2ebSJae Hyun Yoo         retryCount--;
5917cf1f1d4SEddie James     }
5927cf1f1d4SEddie James }
5937cf1f1d4SEddie James 
59421b177e0SEddie James } // namespace ikvm
595