blob: 31a7be4e793eeb40623a06eed1b4c39f929aac1b [file] [log] [blame]
Eddie James21b177e2018-12-11 13:14:46 -06001#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.h"
18
19namespace ikvm
20{
21
22using namespace phosphor::logging;
23using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
24
25const char Input::keyboardID = 1;
26const char Input::pointerID = 2;
27
28const char Input::shiftCtrlMap[NUM_MODIFIER_BITS] = {
29 0x02, // left shift
30 0x20, // right shift
31 0x01, // left control
32 0x10 // right control
33};
34
35const char Input::metaAltMap[NUM_MODIFIER_BITS] = {
36 0x08, // left meta
37 (char)0x80, // right meta
38 0x04, // left alt
39 0x40 // right alt
40};
41
42Input::Input(const std::string& p) :
43 keyboardReport{0}, pointerReport{0}, path(p)
44{
45 fd = open(path.c_str(), O_RDWR);
46 if (fd < 0)
47 {
48 log<level::ERR>("Failed to open input device",
49 entry("PATH=%s", path.c_str()),
50 entry("ERROR=%s", strerror(errno)));
51 elog<Open>(
52 xyz::openbmc_project::Common::File::Open::ERRNO(errno),
53 xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
54 }
55
56 // set the HID identifier byte because device is combined pointer/keyboard
57 keyboardReport[0] = keyboardID;
58 pointerReport[0] = pointerID;
59}
60
61Input::~Input()
62{
63 close(fd);
64}
65
66void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl)
67{
68 Server::ClientData* cd = (Server::ClientData*)cl->clientData;
69 Input* input = cd->input;
70
71 if (down)
72 {
73 char sc = keyToScancode(key);
74
75 if (sc)
76 {
77 if (input->keysDown.find(key) == input->keysDown.end())
78 {
79 for (unsigned int i = 3; i < REPORT_LENGTH; ++i)
80 {
81 if (!input->keyboardReport[i])
82 {
83 input->keyboardReport[i] = sc;
84 input->keysDown.insert(std::make_pair(key, i));
85 input->sendKeyboard = true;
86 break;
87 }
88 }
89 }
90 }
91 else
92 {
93 char mod = keyToMod(key);
94
95 if (mod)
96 {
97 input->keyboardReport[1] |= mod;
98 input->sendKeyboard = true;
99 }
100 }
101 }
102 else
103 {
104 auto it = input->keysDown.find(key);
105
106 if (it != input->keysDown.end())
107 {
108 input->keyboardReport[it->second] = 0;
109 input->keysDown.erase(it);
110 input->sendKeyboard = true;
111 }
112 else
113 {
114 char mod = keyToMod(key);
115
116 if (mod)
117 {
118 input->keyboardReport[1] &= ~mod;
119 input->sendKeyboard = true;
120 }
121 }
122 }
123}
124
125void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl)
126{
127 Server::ClientData* cd = (Server::ClientData*)cl->clientData;
128 Input* input = cd->input;
129 Server* server = (Server*)cl->screen->screenData;
130 const Video& video = server->getVideo();
131
132 input->pointerReport[1] = buttonMask & 0xFF;
133
134 if (x >= 0 && (unsigned int)x < video.getWidth())
135 {
136 unsigned short xx = x * ((SHRT_MAX + 1) / video.getWidth());
137
138 memcpy(&input->pointerReport[2], &xx, 2);
139 }
140
141 if (y >= 0 && (unsigned int)y < video.getHeight())
142 {
143 unsigned short yy = y * ((SHRT_MAX + 1) / video.getHeight());
144
145 memcpy(&input->pointerReport[4], &yy, 2);
146 }
147
148 input->sendPointer = true;
149 rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
150}
151
152void Input::sendRaw(char* data, int size)
153{
154 if (write(fd, data, size) != size)
155 {
156 log<level::ERR>("Failed to write report",
157 entry("ERROR=%s", strerror(errno)));
158 }
159}
160
161void Input::sendReport()
162{
163 if (sendKeyboard)
164 {
165 if (write(fd, keyboardReport, REPORT_LENGTH) != REPORT_LENGTH)
166 {
167 log<level::ERR>("Failed to write keyboard report",
168 entry("ERROR=%s", strerror(errno)));
169 }
170
171 sendKeyboard = false;
172 }
173
174 if (sendPointer)
175 {
176 if (write(fd, pointerReport, POINTER_LENGTH) != POINTER_LENGTH)
177 {
178 log<level::ERR>("Failed to write pointer report",
179 entry("ERROR=%s", strerror(errno)));
180 }
181
182 sendPointer = false;
183 }
184}
185
186char Input::keyToMod(rfbKeySym key)
187{
188 char mod = 0;
189
190 if (key >= XK_Shift_L && key <= XK_Control_R)
191 {
192 mod = shiftCtrlMap[key - XK_Shift_L];
193 }
194 else if (key >= XK_Meta_L && key <= XK_Alt_R)
195 {
196 mod = metaAltMap[key - XK_Meta_L];
197 }
198
199 return mod;
200}
201
202char Input::keyToScancode(rfbKeySym key)
203{
204 char scancode = 0;
205
206 if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'))
207 {
208 scancode = USBHID_KEY_A + ((key & 0x5F) - 'A');
209 }
210 else if (key >= '1' && key <= '9')
211 {
212 scancode = USBHID_KEY_1 + (key - '1');
213 }
214 else if (key >= XK_F1 && key <= XK_F12)
215 {
216 scancode = USBHID_KEY_F1 + (key - XK_F1);
217 }
218 else
219 {
220 switch (key)
221 {
222 case XK_exclam:
223 scancode = USBHID_KEY_1;
224 break;
225 case XK_at:
226 scancode = USBHID_KEY_2;
227 break;
228 case XK_numbersign:
229 scancode = USBHID_KEY_3;
230 break;
231 case XK_dollar:
232 scancode = USBHID_KEY_4;
233 break;
234 case XK_percent:
235 scancode = USBHID_KEY_5;
236 break;
237 case XK_asciicircum:
238 scancode = USBHID_KEY_6;
239 break;
240 case XK_ampersand:
241 scancode = USBHID_KEY_7;
242 break;
243 case XK_asterisk:
244 scancode = USBHID_KEY_8;
245 break;
246 case XK_parenleft:
247 scancode = USBHID_KEY_9;
248 break;
249 case XK_0:
250 case XK_parenright:
251 scancode = USBHID_KEY_0;
252 break;
253 case XK_Return:
254 scancode = USBHID_KEY_RETURN;
255 break;
256 case XK_Escape:
257 scancode = USBHID_KEY_ESC;
258 break;
259 case XK_BackSpace:
260 scancode = USBHID_KEY_BACKSPACE;
261 break;
262 case XK_Tab:
263 scancode = USBHID_KEY_TAB;
264 break;
265 case XK_space:
266 scancode = USBHID_KEY_SPACE;
267 break;
268 case XK_minus:
269 case XK_underscore:
270 scancode = USBHID_KEY_MINUS;
271 break;
272 case XK_plus:
273 case XK_equal:
274 scancode = USBHID_KEY_EQUAL;
275 break;
276 case XK_bracketleft:
277 case XK_braceleft:
278 scancode = USBHID_KEY_LEFTBRACE;
279 break;
280 case XK_bracketright:
281 case XK_braceright:
282 scancode = USBHID_KEY_RIGHTBRACE;
283 break;
284 case XK_backslash:
285 case XK_bar:
286 scancode = USBHID_KEY_BACKSLASH;
287 break;
288 case XK_colon:
289 case XK_semicolon:
290 scancode = USBHID_KEY_SEMICOLON;
291 break;
292 case XK_quotedbl:
293 case XK_apostrophe:
294 scancode = USBHID_KEY_APOSTROPHE;
295 break;
296 case XK_grave:
297 case XK_asciitilde:
298 scancode = USBHID_KEY_GRAVE;
299 break;
300 case XK_comma:
301 case XK_less:
302 scancode = USBHID_KEY_COMMA;
303 break;
304 case XK_period:
305 case XK_greater:
306 scancode = USBHID_KEY_DOT;
307 break;
308 case XK_slash:
309 case XK_question:
310 scancode = USBHID_KEY_SLASH;
311 break;
312 case XK_Caps_Lock:
313 scancode = USBHID_KEY_CAPSLOCK;
314 break;
315 case XK_Print:
316 scancode = USBHID_KEY_PRINT;
317 break;
318 case XK_Scroll_Lock:
319 scancode = USBHID_KEY_SCROLLLOCK;
320 break;
321 case XK_Pause:
322 scancode = USBHID_KEY_PAUSE;
323 break;
324 case XK_Insert:
325 scancode = USBHID_KEY_INSERT;
326 break;
327 case XK_Home:
328 scancode = USBHID_KEY_HOME;
329 break;
330 case XK_Page_Up:
331 scancode = USBHID_KEY_PAGEUP;
332 break;
333 case XK_Delete:
334 scancode = USBHID_KEY_DELETE;
335 break;
336 case XK_End:
337 scancode = USBHID_KEY_END;
338 break;
339 case XK_Page_Down:
340 scancode = USBHID_KEY_PAGEDOWN;
341 break;
342 case XK_Right:
343 scancode = USBHID_KEY_RIGHT;
344 break;
345 case XK_Left:
346 scancode = USBHID_KEY_LEFT;
347 break;
348 case XK_Down:
349 scancode = USBHID_KEY_DOWN;
350 break;
351 case XK_Up:
352 scancode = USBHID_KEY_UP;
353 break;
354 case XK_Num_Lock:
355 scancode = USBHID_KEY_NUMLOCK;
356 break;
357 }
358 }
359
360 return scancode;
361}
362
363} // namespace ikvm