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