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> 35 inline static void SetBit(Type &val, int bit) {val |= Type(1) << bit;} 36 37 template<typename Type> 38 inline static void ClearBit(Type &val, int bit) {val &= ~(Type(1) << bit);} 39 40 template<typename Type> 41 inline static void InvertBit(Type &val, int bit) {val ^= Type(1) << bit;} 42 43 template<typename Type> 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> 48 inline static bool IsBitSet(Type val, int bit) { 49 return (val & (Type(1) << bit)) != 0;} 50 51 52 #ifdef TRACE_VIRTIO_INPUT_DEVICE 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 146 VirtioInputDevice::VirtioInputDevice() 147 { 148 } 149 150 VirtioInputDevice::~VirtioInputDevice() 151 { 152 } 153 154 155 status_t 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 195 VirtioInputDevice::Start(const char* name, void* cookie) 196 { 197 return ((VirtioInputHandler*)cookie)->Start(); 198 } 199 200 201 status_t 202 VirtioInputDevice::Stop(const char* name, void* cookie) 203 { 204 return ((VirtioInputHandler*)cookie)->Stop(); 205 } 206 207 208 status_t 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 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 232 VirtioInputHandler::~VirtioInputHandler() 233 { 234 235 } 236 237 238 void 239 VirtioInputHandler::SetFd(int fd) 240 { 241 fDeviceFd.SetTo(fd); 242 } 243 244 245 status_t 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 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 284 VirtioInputHandler::Control(uint32 command, BMessage* message) 285 { 286 return B_OK; 287 } 288 289 290 int32 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 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 338 KeyboardHandler::~KeyboardHandler() 339 { 340 _StopRepeating(); 341 } 342 343 344 void 345 KeyboardHandler::Reset() 346 { 347 memset(&fNewState, 0, sizeof(KeyboardState)); 348 memcpy(&fState, &fNewState, sizeof(KeyboardState)); 349 _StopRepeating(); 350 } 351 352 353 status_t 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 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 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 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 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 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 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 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 623 TabletHandler::TabletHandler(VirtioInputDevice* dev, const char* name) 624 : 625 VirtioInputHandler(dev, name, B_POINTING_DEVICE) 626 { 627 } 628 629 630 void 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(&fClickSpeed); 641 TRACE(" fClickSpeed: %" B_PRIdBIGTIME "\n", fClickSpeed); 642 } 643 644 645 status_t 646 TabletHandler::Control(uint32 command, BMessage* message) 647 { 648 switch (command) { 649 case B_CLICK_SPEED_CHANGED: { 650 get_click_speed(&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 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 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* 790 instantiate_input_device() 791 { 792 return new(std::nothrow) VirtioInputDevice(); 793 } 794