xref: /haiku/src/add-ons/input_server/devices/virtio/VirtioInputDevice.cpp (revision caed67a8cba83913b9c21ac2b06ebc6bd1cb3111)
1 /*
2  * Copyright 2021, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "VirtioInputDevice.h"
8 
9 #include <virtio_input_driver.h>
10 #include <virtio_defs.h>
11 
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include <Application.h>
16 #include <String.h>
17 
18 
19 //#define TRACE_VIRTIO_INPUT_DEVICE
20 #ifdef TRACE_VIRTIO_INPUT_DEVICE
21 #       define TRACE(x...) debug_printf("virtio_input_device: " x)
22 #else
23 #       define TRACE(x...) ;
24 #endif
25 #define ERROR(x...) debug_printf("virtio_input_device: " x)
26 #define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
27 
28 
29 enum {
30 	kWatcherThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4,
31 };
32 
33 
34 template<typename Type>
SetBit(Type & val,int bit)35 inline static void SetBit(Type &val, int bit) {val |= Type(1) << bit;}
36 
37 template<typename Type>
ClearBit(Type & val,int bit)38 inline static void ClearBit(Type &val, int bit) {val &= ~(Type(1) << bit);}
39 
40 template<typename Type>
InvertBit(Type & val,int bit)41 inline static void InvertBit(Type &val, int bit) {val ^= Type(1) << bit;}
42 
43 template<typename Type>
SetBitTo(Type & val,int bit,bool isSet)44 inline static void SetBitTo(Type &val, int bit, bool isSet) {
45 	val ^= ((isSet? -1: 0) ^ val) & (Type(1) << bit);}
46 
47 template<typename Type>
IsBitSet(Type val,int bit)48 inline static bool IsBitSet(Type val, int bit) {
49 	return (val & (Type(1) << bit)) != 0;}
50 
51 
52 #ifdef TRACE_VIRTIO_INPUT_DEVICE
WriteInputPacket(const VirtioInputPacket & pkt)53 static void WriteInputPacket(const VirtioInputPacket &pkt)
54 {
55 	switch (pkt.type) {
56 		case kVirtioInputEvSyn:
57 			TRACE("syn");
58 			break;
59 		case kVirtioInputEvKey:
60 			TRACE("key, ");
61 			switch (pkt.code) {
62 				case kVirtioInputBtnLeft:
63 					TRACE("left");
64 					break;
65 				case kVirtioInputBtnRight:
66 					TRACE("middle");
67 					break;
68 				case kVirtioInputBtnMiddle:
69 					TRACE("right");
70 					break;
71 				case kVirtioInputBtnGearDown:
72 					TRACE("gearDown");
73 					break;
74 				case kVirtioInputBtnGearUp:
75 					TRACE("gearUp");
76 					break;
77 				default:
78 					TRACE("%d", pkt.code);
79 			}
80 			break;
81 		case kVirtioInputEvRel:
82 			TRACE("rel, ");
83 			switch (pkt.code) {
84 				case kVirtioInputRelX:
85 					TRACE("relX");
86 					break;
87 				case kVirtioInputRelY:
88 					TRACE("relY");
89 					break;
90 				case kVirtioInputRelZ:
91 					TRACE("relZ");
92 					break;
93 				case kVirtioInputRelWheel:
94 					TRACE("relWheel");
95 					break;
96 				default:
97 					TRACE("%d", pkt.code);
98 			}
99 			break;
100 		case kVirtioInputEvAbs:
101 			TRACE("abs, ");
102 			switch (pkt.code) {
103 				case kVirtioInputAbsX:
104 					TRACE("absX");
105 					break;
106 				case kVirtioInputAbsY:
107 					TRACE("absY");
108 					break;
109 				case kVirtioInputAbsZ:
110 					TRACE("absZ");
111 					break;
112 				default:
113 					TRACE("%d", pkt.code);
114 			}
115 			break;
116 		case kVirtioInputEvRep:
117 			TRACE("rep");
118 			break;
119 		default:
120 			TRACE("?(%d)", pkt.type);
121 	}
122 	switch (pkt.type) {
123 		case kVirtioInputEvSyn:
124 			break;
125 		case kVirtioInputEvKey:
126 			TRACE(", ");
127 			if (pkt.value == 0) {
128 				TRACE("up");
129 			} else if (pkt.value == 1) {
130 				TRACE("down");
131 			} else {
132 				TRACE("%d", pkt.value);
133 			}
134 			break;
135 		default:
136 			TRACE(", ");
137 			TRACE("%d", pkt.value);
138 	}
139 }
140 #endif /* TRACE_VIRTIO_INPUT_DEVICE */
141 
142 
143 //#pragma mark VirtioInputDevice
144 
145 
VirtioInputDevice()146 VirtioInputDevice::VirtioInputDevice()
147 {
148 }
149 
~VirtioInputDevice()150 VirtioInputDevice::~VirtioInputDevice()
151 {
152 }
153 
154 
155 status_t
InitCheck()156 VirtioInputDevice::InitCheck()
157 {
158 	static input_device_ref *devices[3];
159 	input_device_ref **devicesEnd = devices;
160 
161 	FileDescriptorCloser fd;
162 
163 	// TODO: dynamically scan and detect device type
164 
165 	ObjectDeleter<VirtioInputHandler> tablet(
166 		new TabletHandler(this, "VirtIO tablet"));
167 	fd.SetTo(open("/dev/input/virtio/0/raw", O_RDWR));
168 	if (fd.IsSet()) {
169 		tablet->SetFd(fd.Detach());
170 		*devicesEnd++ = tablet->Ref();
171 		tablet.Detach();
172 	} else {
173 		TRACE("Unable to detect tablet device!");
174 	}
175 
176 	ObjectDeleter<VirtioInputHandler> keyboard(
177 		new KeyboardHandler(this, "VirtIO keyboard"));
178 	fd.SetTo(open("/dev/input/virtio/1/raw", O_RDWR));
179 	if (fd.IsSet()) {
180 		keyboard->SetFd(fd.Detach());
181 		*devicesEnd++ = keyboard->Ref();
182 		keyboard.Detach();
183 	} else {
184 		TRACE("Unable to detect keyboard device!");
185 	}
186 
187 	*devicesEnd = NULL;
188 
189 	RegisterDevices(devices);
190 	return B_OK;
191 }
192 
193 
194 status_t
Start(const char * name,void * cookie)195 VirtioInputDevice::Start(const char* name, void* cookie)
196 {
197 	return ((VirtioInputHandler*)cookie)->Start();
198 }
199 
200 
201 status_t
Stop(const char * name,void * cookie)202 VirtioInputDevice::Stop(const char* name, void* cookie)
203 {
204 	return ((VirtioInputHandler*)cookie)->Stop();
205 }
206 
207 
208 status_t
Control(const char * name,void * cookie,uint32 command,BMessage * message)209 VirtioInputDevice::Control(const char* name, void* cookie, uint32 command,
210 	BMessage* message)
211 {
212 	return ((VirtioInputHandler*)cookie)->Control(command, message);
213 }
214 
215 
216 //#pragma mark VirtioInputHandler
217 
218 
VirtioInputHandler(VirtioInputDevice * dev,const char * name,input_device_type type)219 VirtioInputHandler::VirtioInputHandler(VirtioInputDevice* dev, const char* name,
220 	input_device_type type)
221 	:
222 	fDev(dev),
223 	fWatcherThread(B_ERROR),
224 	fRun(false)
225 {
226 	fRef.name = (char*)name; // NOTE: name should be constant data
227 	fRef.type = type;
228 	fRef.cookie = this;
229 }
230 
231 
~VirtioInputHandler()232 VirtioInputHandler::~VirtioInputHandler()
233 {
234 
235 }
236 
237 
238 void
SetFd(int fd)239 VirtioInputHandler::SetFd(int fd)
240 {
241 	fDeviceFd.SetTo(fd);
242 }
243 
244 
245 status_t
Start()246 VirtioInputHandler::Start()
247 {
248 	char threadName[B_OS_NAME_LENGTH];
249 	snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fRef.name);
250 
251 	if (fWatcherThread < 0) {
252 		fWatcherThread = spawn_thread(Watcher, threadName,
253 			kWatcherThreadPriority, this);
254 
255 		if (fWatcherThread < B_OK)
256 			return fWatcherThread;
257 
258 		fRun = true;
259 		resume_thread(fWatcherThread);
260 	}
261 	return B_OK;
262 }
263 
264 
265 status_t
Stop()266 VirtioInputHandler::Stop()
267 {
268 	// TODO: Use condition variable to sync access? suspend_thread
269 	// avoids a race condition so it doesn't exit before wait_for_thread
270 
271 	if (fWatcherThread >= B_OK) {
272 		// ioctl(fDeviceFd.Get(), virtioInputCancelIO, NULL, 0);
273 		suspend_thread(fWatcherThread);
274 		fRun = false;
275 		status_t res;
276 		wait_for_thread(fWatcherThread, &res);
277 		fWatcherThread = B_ERROR;
278 	}
279 	return B_OK;
280 }
281 
282 
283 status_t
Control(uint32 command,BMessage * message)284 VirtioInputHandler::Control(uint32 command, BMessage* message)
285 {
286 	return B_OK;
287 }
288 
289 
290 int32
Watcher(void * arg)291 VirtioInputHandler::Watcher(void *arg)
292 {
293 	VirtioInputHandler &handler = *((VirtioInputHandler*)arg);
294 	handler.Reset();
295 	while (handler.fRun) {
296 		VirtioInputPacket pkt;
297 		status_t res = ioctl(handler.fDeviceFd.Get(), virtioInputRead, &pkt,
298 			sizeof(pkt));
299 		// if (res == B_CANCELED) return B_OK;
300 		if (res < B_OK)
301 			continue;
302 		handler.PacketReceived(pkt);
303 	}
304 	return B_OK;
305 }
306 
307 
308 //#pragma mark KeyboardHandler
309 
310 
KeyboardHandler(VirtioInputDevice * dev,const char * name)311 KeyboardHandler::KeyboardHandler(VirtioInputDevice* dev, const char* name)
312 	:
313 	VirtioInputHandler(dev, name, B_KEYBOARD_DEVICE),
314 	fRepeatThread(-1),
315 	fRepeatThreadSem(-1)
316 {
317 	TRACE("+KeyboardHandler()\n");
318 	{
319 		// TODO: Similar to B_KEY_MAP_CHANGED below?
320 		key_map *keyMap = NULL;
321 		char *chars = NULL;
322 		get_key_map(&keyMap, &chars);
323 		fKeyMap.SetTo(keyMap);
324 		fChars.SetTo(chars);
325 	}
326 	TRACE("  fKeymap: %p\n", fKeyMap.Get());
327 	TRACE("  fChars: %p\n", fChars.Get());
328 	get_key_repeat_delay(&fRepeatDelay);
329 	get_key_repeat_rate (&fRepeatRate);
330 	TRACE("  fRepeatDelay: %" B_PRIdBIGTIME "\n", fRepeatDelay);
331 	TRACE("  fRepeatRate: % " B_PRId32 "\n", fRepeatRate);
332 
333 	if (fRepeatRate < 1)
334 		fRepeatRate = 1;
335 }
336 
337 
~KeyboardHandler()338 KeyboardHandler::~KeyboardHandler()
339 {
340 	_StopRepeating();
341 }
342 
343 
344 void
Reset()345 KeyboardHandler::Reset()
346 {
347 	memset(&fNewState, 0, sizeof(KeyboardState));
348 	memcpy(&fState, &fNewState, sizeof(KeyboardState));
349 	_StopRepeating();
350 }
351 
352 
353 status_t
Control(uint32 command,BMessage * message)354 KeyboardHandler::Control(uint32 command, BMessage* message)
355 {
356 	switch (command) {
357 		case B_KEY_MAP_CHANGED: {
358 			key_map *keyMap = NULL;
359 			char *chars = NULL;
360 			get_key_map(&keyMap, &chars);
361 			if (keyMap == NULL || chars == NULL)
362 				return B_NO_MEMORY;
363 			fKeyMap.SetTo(keyMap);
364 			fChars.SetTo(chars);
365 			return B_OK;
366 		}
367 		case B_KEY_REPEAT_DELAY_CHANGED:
368 			get_key_repeat_delay(&fRepeatDelay);
369 			TRACE("  fRepeatDelay: %" B_PRIdBIGTIME "\n", fRepeatDelay);
370 			return B_OK;
371 		case B_KEY_REPEAT_RATE_CHANGED:
372 			get_key_repeat_rate(&fRepeatRate);
373 			TRACE("  fRepeatRate: %" B_PRId32 "\n", fRepeatRate);
374 			if (fRepeatRate < 1) fRepeatRate = 1;
375 			return B_OK;
376 	}
377 	return VirtioInputHandler::Control(command, message);
378 }
379 
380 
381 void
PacketReceived(const VirtioInputPacket & pkt)382 KeyboardHandler::PacketReceived(const VirtioInputPacket &pkt)
383 {
384 #ifdef TRACE_VIRTIO_INPUT_DEVICE
385 	TRACE("keyboard: ");
386 	WriteInputPacket(pkt);
387 	TRACE("\n");
388 #endif
389 	switch (pkt.type) {
390 		case kVirtioInputEvKey: {
391 			if (pkt.code < 256)
392 				SetBitTo(fNewState.keys[pkt.code / 8], pkt.code % 8,
393 					pkt.value != 0);
394 			break;
395 		}
396 		case kVirtioInputEvSyn: {
397 			fState.when = system_time();
398 			_StateChanged();
399 		}
400 	}
401 }
402 
403 
404 bool
_IsKeyPressed(const KeyboardState & state,uint32 key)405 KeyboardHandler::_IsKeyPressed(const KeyboardState &state, uint32 key)
406 {
407 	return key < 256 && IsBitSet(state.keys[key / 8], key % 8);
408 }
409 
410 
411 void
_KeyString(uint32 code,char * str,size_t len)412 KeyboardHandler::_KeyString(uint32 code, char *str, size_t len)
413 {
414 	char *ch;
415 	switch (fNewState.modifiers & (
416 		B_SHIFT_KEY | B_CONTROL_KEY | B_OPTION_KEY | B_CAPS_LOCK)) {
417 		case B_OPTION_KEY | B_CAPS_LOCK | B_SHIFT_KEY:
418 			ch = fChars.Get() + fKeyMap->option_caps_shift_map[code];
419 			break;
420 		case B_OPTION_KEY | B_CAPS_LOCK:
421 			ch = fChars.Get() + fKeyMap->option_caps_map[code];
422 			break;
423 		case B_OPTION_KEY | B_SHIFT_KEY:
424 			ch = fChars.Get() + fKeyMap->option_shift_map[code];
425 			break;
426 		case B_OPTION_KEY:
427 			ch = fChars.Get() + fKeyMap->option_map[code];
428 			break;
429 		case B_CAPS_LOCK  | B_SHIFT_KEY:
430 			ch = fChars.Get() + fKeyMap->caps_shift_map[code];
431 			break;
432 		case B_CAPS_LOCK:
433 			ch = fChars.Get() + fKeyMap->caps_map[code];
434 			break;
435 		case B_SHIFT_KEY:
436 			ch = fChars.Get() + fKeyMap->shift_map[code];
437 			break;
438 		default:
439 			if ((fNewState.modifiers & B_CONTROL_KEY) != 0)
440 				ch = fChars.Get() + fKeyMap->control_map[code];
441 			else
442 				ch = fChars.Get() + fKeyMap->normal_map[code];
443 	}
444 	if (len > 0) {
445 		uint32 i;
446 		for (i = 0; (i < (uint32)ch[0]) && (i < len - 1); i++)
447 			str[i] = ch[i + 1];
448 		str[i] = '\0';
449 	}
450 }
451 
452 
453 void
_StartRepeating(BMessage * msg)454 KeyboardHandler::_StartRepeating(BMessage* msg)
455 {
456 	if (fRepeatThread >= B_OK)
457 		_StopRepeating();
458 
459 	fRepeatMsg = *msg;
460 	fRepeatThread = spawn_thread(_RepeatThread, "repeat thread",
461 		B_REAL_TIME_DISPLAY_PRIORITY + 4, this);
462 	fRepeatThreadSem = create_sem(0, "repeat thread sem");
463 	if (fRepeatThread >= B_OK)
464 		resume_thread(fRepeatThread);
465 }
466 
467 
468 void
_StopRepeating()469 KeyboardHandler::_StopRepeating()
470 {
471 	if (fRepeatThread >= B_OK) {
472 		status_t res;
473 		release_sem(fRepeatThreadSem);
474 		wait_for_thread(fRepeatThread, &res);
475 		fRepeatThread = -1;
476 		delete_sem(fRepeatThreadSem);
477 		fRepeatThreadSem = -1;
478 	}
479 }
480 
481 
482 status_t
_RepeatThread(void * arg)483 KeyboardHandler::_RepeatThread(void *arg)
484 {
485 	status_t res;
486 	KeyboardHandler *h = (KeyboardHandler*)arg;
487 
488 	res = acquire_sem_etc(h->fRepeatThreadSem, 1, B_RELATIVE_TIMEOUT,
489 		h->fRepeatDelay);
490 	if (res >= B_OK)
491 		return B_OK;
492 
493 	while (true) {
494 		int32 count;
495 
496 		h->fRepeatMsg.ReplaceInt64("when", system_time());
497 		h->fRepeatMsg.FindInt32("be:key_repeat", &count);
498 		h->fRepeatMsg.ReplaceInt32("be:key_repeat", count + 1);
499 
500 		ObjectDeleter<BMessage> msg(new(std::nothrow) BMessage(h->fRepeatMsg));
501 		if (msg.IsSet() && h->Device()->EnqueueMessage(msg.Get()) >= B_OK)
502 			msg.Detach();
503 
504 		res = acquire_sem_etc(h->fRepeatThreadSem, 1, B_RELATIVE_TIMEOUT,
505 			(bigtime_t)10000000 / h->fRepeatRate);
506 		if (res >= B_OK)
507 			return B_OK;
508 	}
509 }
510 
511 
512 void
_StateChanged()513 KeyboardHandler::_StateChanged()
514 {
515 	uint32 i, j;
516 
517 	fNewState.modifiers = fState.modifiers
518 		& (B_CAPS_LOCK | B_SCROLL_LOCK | B_NUM_LOCK);
519 	if (_IsKeyPressed(fNewState, fKeyMap->left_shift_key))
520 		fNewState.modifiers |= B_SHIFT_KEY   | B_LEFT_SHIFT_KEY;
521 	if (_IsKeyPressed(fNewState, fKeyMap->right_shift_key))
522 		fNewState.modifiers |= B_SHIFT_KEY   | B_RIGHT_SHIFT_KEY;
523 	if (_IsKeyPressed(fNewState, fKeyMap->left_command_key))
524 		fNewState.modifiers |= B_COMMAND_KEY | B_LEFT_COMMAND_KEY;
525 	if (_IsKeyPressed(fNewState, fKeyMap->right_command_key))
526 		fNewState.modifiers |= B_COMMAND_KEY | B_RIGHT_COMMAND_KEY;
527 	if (_IsKeyPressed(fNewState, fKeyMap->left_control_key))
528 		fNewState.modifiers |= B_CONTROL_KEY | B_LEFT_CONTROL_KEY;
529 	if (_IsKeyPressed(fNewState, fKeyMap->right_control_key))
530 		fNewState.modifiers |= B_CONTROL_KEY | B_RIGHT_CONTROL_KEY;
531 	if (_IsKeyPressed(fNewState, fKeyMap->caps_key))
532 		fNewState.modifiers ^= B_CAPS_LOCK;
533 	if (_IsKeyPressed(fNewState, fKeyMap->scroll_key))
534 		fNewState.modifiers ^= B_SCROLL_LOCK;
535 	if (_IsKeyPressed(fNewState, fKeyMap->num_key))
536 		fNewState.modifiers ^= B_NUM_LOCK;
537 	if (_IsKeyPressed(fNewState, fKeyMap->left_option_key))
538 		fNewState.modifiers |= B_OPTION_KEY  | B_LEFT_OPTION_KEY;
539 	if (_IsKeyPressed(fNewState, fKeyMap->right_option_key))
540 		fNewState.modifiers |= B_OPTION_KEY  | B_RIGHT_OPTION_KEY;
541 	if (_IsKeyPressed(fNewState, fKeyMap->menu_key))
542 		fNewState.modifiers |= B_MENU_KEY;
543 
544 	if (fState.modifiers != fNewState.modifiers) {
545 		ObjectDeleter<BMessage> msg(
546 			new(std::nothrow) BMessage(B_MODIFIERS_CHANGED));
547 		if (msg.IsSet()) {
548 			msg->AddInt64("when", system_time());
549 			msg->AddInt32("modifiers", fNewState.modifiers);
550 			msg->AddInt32("be:old_modifiers", fState.modifiers);
551 			msg->AddData("states", B_UINT8_TYPE, fNewState.keys, 16);
552 
553 			if (Device()->EnqueueMessage(msg.Get()) >= B_OK) {
554 				msg.Detach();
555 				fState.modifiers = fNewState.modifiers;
556 			}
557 		}
558 	}
559 
560 
561 	uint8 diff[16];
562 	char rawCh;
563 	char str[5];
564 
565 	for (i = 0; i < 16; ++i)
566 		diff[i] = fState.keys[i] ^ fNewState.keys[i];
567 
568 	for (i = 0; i < 128; ++i) {
569 		if (diff[i/8] & (1 << (i % 8))) {
570 			ObjectDeleter<BMessage> msg(new(std::nothrow) BMessage());
571 			if (msg.IsSet()) {
572 				_KeyString(i, str, sizeof(str));
573 
574 				msg->AddInt64("when", system_time());
575 				msg->AddInt32("key", i);
576 				msg->AddInt32("modifiers", fNewState.modifiers);
577 				msg->AddData("states", B_UINT8_TYPE, fNewState.keys, 16);
578 
579 				if (str[0] != '\0') {
580 					if (fChars.Get()[fKeyMap->normal_map[i]] != 0)
581 						rawCh = fChars.Get()[fKeyMap->normal_map[i] + 1];
582 					else
583 						rawCh = str[0];
584 
585 					for (j = 0; str[j] != '\0'; ++j)
586 						msg->AddInt8("byte", str[j]);
587 
588 					msg->AddString("bytes", str);
589 					msg->AddInt32("raw_char", rawCh);
590 				}
591 
592 				if (fNewState.keys[i / 8] & (1 << (i % 8))) {
593 					if (str[0] != '\0')
594 						msg->what = B_KEY_DOWN;
595 					else
596 						msg->what = B_UNMAPPED_KEY_DOWN;
597 
598 					msg->AddInt32("be:key_repeat", 1);
599 					_StartRepeating(msg.Get());
600 				} else {
601 					if (str[0] != '\0')
602 						msg->what = B_KEY_UP;
603 					else
604 						msg->what = B_UNMAPPED_KEY_UP;
605 
606 					_StopRepeating();
607 				}
608 
609 				if (Device()->EnqueueMessage(msg.Get()) >= B_OK) {
610 					msg.Detach();
611 					for (j = 0; j < 16; ++j)
612 						fState.keys[j] = fNewState.keys[j];
613 				}
614 			}
615 		}
616 	}
617 }
618 
619 
620 //#pragma mark TabletHandler
621 
622 
TabletHandler(VirtioInputDevice * dev,const char * name)623 TabletHandler::TabletHandler(VirtioInputDevice* dev, const char* name)
624 	:
625 	VirtioInputHandler(dev, name, B_POINTING_DEVICE)
626 {
627 }
628 
629 
630 void
Reset()631 TabletHandler::Reset()
632 {
633 	memset(&fNewState, 0, sizeof(TabletState));
634 	fNewState.x = 0.5f;
635 	fNewState.y = 0.5f;
636 	memcpy(&fState, &fNewState, sizeof(TabletState));
637 	fLastClick = -1;
638 	fLastClickBtn = -1;
639 
640 	get_click_speed(Ref()->name, &fClickSpeed);
641 	TRACE("  fClickSpeed: %" B_PRIdBIGTIME "\n", fClickSpeed);
642 }
643 
644 
645 status_t
Control(uint32 command,BMessage * message)646 TabletHandler::Control(uint32 command, BMessage* message)
647 {
648 	switch (command) {
649 		case B_CLICK_SPEED_CHANGED: {
650 			get_click_speed(Ref()->name, &fClickSpeed);
651 			TRACE("  fClickSpeed: %" B_PRIdBIGTIME "\n", fClickSpeed);
652 			return B_OK;
653 		}
654 	}
655 	return VirtioInputHandler::Control(command, message);
656 }
657 
658 
659 void
PacketReceived(const VirtioInputPacket & pkt)660 TabletHandler::PacketReceived(const VirtioInputPacket &pkt)
661 {
662 	switch (pkt.type) {
663 		case kVirtioInputEvAbs: {
664 			switch (pkt.code) {
665 				case kVirtioInputAbsX:
666 					fNewState.x = float(pkt.value) / 32768.0f;
667 					break;
668 				case kVirtioInputAbsY:
669 					fNewState.y = float(pkt.value) / 32768.0f;
670 					break;
671 			}
672 			break;
673 		}
674 		case kVirtioInputEvRel: {
675 			switch (pkt.code) {
676 				case kVirtioInputRelWheel:
677 					fNewState.wheelY -= pkt.value;
678 					break;
679 			}
680 			break;
681 		}
682 		case kVirtioInputEvKey: {
683 			switch (pkt.code) {
684 				case kVirtioInputBtnLeft:
685 					SetBitTo(fNewState.buttons, 0, pkt.value != 0);
686 					break;
687 				case kVirtioInputBtnRight:
688 					SetBitTo(fNewState.buttons, 1, pkt.value != 0);
689 					break;
690 				case kVirtioInputBtnMiddle:
691 					SetBitTo(fNewState.buttons, 2, pkt.value != 0);
692 					break;
693 			}
694 			break;
695 		}
696 		case kVirtioInputEvSyn: {
697 			fState.when = system_time();
698 
699 			// update pos
700 			if (fState.x != fNewState.x || fState.y != fNewState.y
701 				|| fState.pressure != fNewState.pressure) {
702 				fState.x = fNewState.x;
703 				fState.y = fNewState.y;
704 				fState.pressure = fNewState.pressure;
705 				ObjectDeleter<BMessage> msg(
706 					new(std::nothrow) BMessage(B_MOUSE_MOVED));
707 				if (!msg.IsSet() || !_FillMessage(*msg.Get(), fState))
708 					return;
709 
710 				if (Device()->EnqueueMessage(msg.Get()) >= B_OK)
711 					msg.Detach();
712 			}
713 
714 			// update buttons
715 			for (int i = 0; i < 32; i++) {
716 				if ((IsBitSet(fState.buttons, i)
717 					!= IsBitSet(fNewState.buttons, i))) {
718 					InvertBit(fState.buttons, i);
719 
720 					// TODO: new B_MOUSE_DOWN for every button clicked together?
721 					// should be refactored to look like other input drivers.
722 
723 					ObjectDeleter<BMessage> msg(new(std::nothrow) BMessage());
724 					if (!msg.IsSet() || !_FillMessage(*msg.Get(), fState))
725 						return;
726 
727 					if (IsBitSet(fState.buttons, i)) {
728 						msg->what = B_MOUSE_DOWN;
729 						if (i == fLastClickBtn
730 							&& fState.when - fLastClick <= fClickSpeed)
731 							fState.clicks++;
732 						else
733 							fState.clicks = 1;
734 						fLastClickBtn = i;
735 						fLastClick = fState.when;
736 						msg->AddInt32("clicks", fState.clicks);
737 					} else
738 						msg->what = B_MOUSE_UP;
739 
740 					if (Device()->EnqueueMessage(msg.Get()) >= B_OK)
741 						msg.Detach();
742 				}
743 			}
744 
745 			// update wheel
746 			if (fState.wheelX != fNewState.wheelX
747 				|| fState.wheelY != fNewState.wheelY) {
748 				ObjectDeleter<BMessage> msg(
749 					new(std::nothrow) BMessage(B_MOUSE_WHEEL_CHANGED));
750 				if (!msg.IsSet()
751 					|| msg->AddInt64("when", fState.when) < B_OK
752 					|| msg->AddFloat("be:wheel_delta_x",
753 						fNewState.wheelX - fState.wheelX) < B_OK
754 					|| msg->AddFloat("be:wheel_delta_y",
755 						fNewState.wheelY - fState.wheelY) < B_OK) {
756 					return;
757 				}
758 
759 				fState.wheelX = fNewState.wheelX;
760 				fState.wheelY = fNewState.wheelY;
761 				if (Device()->EnqueueMessage(msg.Get()) >= B_OK)
762 					msg.Detach();
763 			}
764 			break;
765 		}
766 	}
767 }
768 
769 
770 bool
_FillMessage(BMessage & msg,const TabletState & s)771 TabletHandler::_FillMessage(BMessage &msg, const TabletState &s)
772 {
773 	if (msg.AddInt64("when", s.when) < B_OK
774 		|| msg.AddInt32("buttons", s.buttons) < B_OK
775 		|| msg.AddFloat("x", s.x) < B_OK
776 		|| msg.AddFloat("y", s.y) < B_OK) {
777 		return false;
778 	}
779 	msg.AddFloat("be:tablet_x", s.x);
780 	msg.AddFloat("be:tablet_y", s.y);
781 	msg.AddFloat("be:tablet_pressure", s.pressure);
782 	return true;
783 }
784 
785 
786 //#pragma mark -
787 
788 
789 extern "C" BInputServerDevice*
instantiate_input_device()790 instantiate_input_device()
791 {
792 	return new(std::nothrow) VirtioInputDevice();
793 }
794