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