xref: /openbmc/obmc-ikvm/ikvm_input.cpp (revision 2bc661d3)
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 = (uint16_t)(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 = (uint16_t)(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[KEY_REPORT_LENGTH] = {0};
160 
161     if (pointerFd >= 0)
162     {
163         uint16_t xy = SHRT_MAX / 2;
164 
165         memcpy(&wakeupReport[1], &xy, 2);
166         memcpy(&wakeupReport[3], &xy, 2);
167 
168         if (write(pointerFd, wakeupReport, PTR_REPORT_LENGTH) !=
169             PTR_REPORT_LENGTH)
170         {
171             log<level::ERR>("Failed to write pointer report",
172                             entry("ERROR=%s", strerror(errno)));
173         }
174     }
175 
176     if (keyboardFd >= 0)
177     {
178         memset(&wakeupReport[0], 0, KEY_REPORT_LENGTH);
179 
180         wakeupReport[0] = keyToMod(XK_Shift_L);
181 
182         if (write(keyboardFd, wakeupReport, KEY_REPORT_LENGTH) !=
183             KEY_REPORT_LENGTH)
184         {
185             log<level::ERR>("Failed to write keyboard report",
186                             entry("ERROR=%s", strerror(errno)));
187             return;
188         }
189 
190         wakeupReport[0] = 0;
191 
192         if (write(keyboardFd, wakeupReport, KEY_REPORT_LENGTH) !=
193             KEY_REPORT_LENGTH)
194         {
195             log<level::ERR>("Failed to write keyboard report",
196                             entry("ERROR=%s", strerror(errno)));
197         }
198     }
199 }
200 
201 void Input::sendReport()
202 {
203     if (sendKeyboard && keyboardFd >= 0)
204     {
205         if (write(keyboardFd, keyboardReport, KEY_REPORT_LENGTH) !=
206             KEY_REPORT_LENGTH)
207         {
208             log<level::ERR>("Failed to write keyboard report",
209                             entry("ERROR=%s", strerror(errno)));
210         }
211 
212         sendKeyboard = false;
213     }
214 
215     if (sendPointer && pointerFd >= 0)
216     {
217         if (write(pointerFd, pointerReport, PTR_REPORT_LENGTH) !=
218             PTR_REPORT_LENGTH)
219         {
220             log<level::ERR>("Failed to write pointer report",
221                             entry("ERROR=%s", strerror(errno)));
222         }
223 
224         sendPointer = false;
225     }
226 }
227 
228 uint8_t Input::keyToMod(rfbKeySym key)
229 {
230     uint8_t mod = 0;
231 
232     if (key >= XK_Shift_L && key <= XK_Control_R)
233     {
234         mod = shiftCtrlMap[key - XK_Shift_L];
235     }
236     else if (key >= XK_Meta_L && key <= XK_Alt_R)
237     {
238         mod = metaAltMap[key - XK_Meta_L];
239     }
240 
241     return mod;
242 }
243 
244 uint8_t Input::keyToScancode(rfbKeySym key)
245 {
246     uint8_t scancode = 0;
247 
248     if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'))
249     {
250         scancode = USBHID_KEY_A + ((key & 0x5F) - 'A');
251     }
252     else if (key >= '1' && key <= '9')
253     {
254         scancode = USBHID_KEY_1 + (key - '1');
255     }
256     else if (key >= XK_F1 && key <= XK_F12)
257     {
258         scancode = USBHID_KEY_F1 + (key - XK_F1);
259     }
260     else
261     {
262         switch (key)
263         {
264             case XK_exclam:
265                 scancode = USBHID_KEY_1;
266                 break;
267             case XK_at:
268                 scancode = USBHID_KEY_2;
269                 break;
270             case XK_numbersign:
271                 scancode = USBHID_KEY_3;
272                 break;
273             case XK_dollar:
274                 scancode = USBHID_KEY_4;
275                 break;
276             case XK_percent:
277                 scancode = USBHID_KEY_5;
278                 break;
279             case XK_asciicircum:
280                 scancode = USBHID_KEY_6;
281                 break;
282             case XK_ampersand:
283                 scancode = USBHID_KEY_7;
284                 break;
285             case XK_asterisk:
286                 scancode = USBHID_KEY_8;
287                 break;
288             case XK_parenleft:
289                 scancode = USBHID_KEY_9;
290                 break;
291             case XK_0:
292             case XK_parenright:
293                 scancode = USBHID_KEY_0;
294                 break;
295             case XK_Return:
296                 scancode = USBHID_KEY_RETURN;
297                 break;
298             case XK_Escape:
299                 scancode = USBHID_KEY_ESC;
300                 break;
301             case XK_BackSpace:
302                 scancode = USBHID_KEY_BACKSPACE;
303                 break;
304             case XK_Tab:
305                 scancode = USBHID_KEY_TAB;
306                 break;
307             case XK_space:
308                 scancode = USBHID_KEY_SPACE;
309                 break;
310             case XK_minus:
311             case XK_underscore:
312                 scancode = USBHID_KEY_MINUS;
313                 break;
314             case XK_plus:
315             case XK_equal:
316                 scancode = USBHID_KEY_EQUAL;
317                 break;
318             case XK_bracketleft:
319             case XK_braceleft:
320                 scancode = USBHID_KEY_LEFTBRACE;
321                 break;
322             case XK_bracketright:
323             case XK_braceright:
324                 scancode = USBHID_KEY_RIGHTBRACE;
325                 break;
326             case XK_backslash:
327             case XK_bar:
328                 scancode = USBHID_KEY_BACKSLASH;
329                 break;
330             case XK_colon:
331             case XK_semicolon:
332                 scancode = USBHID_KEY_SEMICOLON;
333                 break;
334             case XK_quotedbl:
335             case XK_apostrophe:
336                 scancode = USBHID_KEY_APOSTROPHE;
337                 break;
338             case XK_grave:
339             case XK_asciitilde:
340                 scancode = USBHID_KEY_GRAVE;
341                 break;
342             case XK_comma:
343             case XK_less:
344                 scancode = USBHID_KEY_COMMA;
345                 break;
346             case XK_period:
347             case XK_greater:
348                 scancode = USBHID_KEY_DOT;
349                 break;
350             case XK_slash:
351             case XK_question:
352                 scancode = USBHID_KEY_SLASH;
353                 break;
354             case XK_Caps_Lock:
355                 scancode = USBHID_KEY_CAPSLOCK;
356                 break;
357             case XK_Print:
358                 scancode = USBHID_KEY_PRINT;
359                 break;
360             case XK_Scroll_Lock:
361                 scancode = USBHID_KEY_SCROLLLOCK;
362                 break;
363             case XK_Pause:
364                 scancode = USBHID_KEY_PAUSE;
365                 break;
366             case XK_Insert:
367                 scancode = USBHID_KEY_INSERT;
368                 break;
369             case XK_Home:
370                 scancode = USBHID_KEY_HOME;
371                 break;
372             case XK_Page_Up:
373                 scancode = USBHID_KEY_PAGEUP;
374                 break;
375             case XK_Delete:
376                 scancode = USBHID_KEY_DELETE;
377                 break;
378             case XK_End:
379                 scancode = USBHID_KEY_END;
380                 break;
381             case XK_Page_Down:
382                 scancode = USBHID_KEY_PAGEDOWN;
383                 break;
384             case XK_Right:
385                 scancode = USBHID_KEY_RIGHT;
386                 break;
387             case XK_Left:
388                 scancode = USBHID_KEY_LEFT;
389                 break;
390             case XK_Down:
391                 scancode = USBHID_KEY_DOWN;
392                 break;
393             case XK_Up:
394                 scancode = USBHID_KEY_UP;
395                 break;
396             case XK_Num_Lock:
397                 scancode = USBHID_KEY_NUMLOCK;
398                 break;
399         }
400     }
401 
402     return scancode;
403 }
404 
405 } // namespace ikvm
406