xref: /openbmc/obmc-ikvm/ikvm_input.cpp (revision 7dfac9ff)
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