1 /* 2 * Copyright 2004-2011, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stefano Ceccherini (stefano.ceccherini@gmail.com) 7 * Jérôme Duval 8 * Axel Dörfler, axeld@pinc-software.de 9 * Clemens Zeidler, haiku@clemens-zeidler.de 10 * Stephan Aßmus, superstippi@gmx.de 11 */ 12 13 14 #include "MouseInputDevice.h" 15 16 #include <errno.h> 17 #include <new> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <unistd.h> 21 22 #include <Autolock.h> 23 #include <Debug.h> 24 #include <Directory.h> 25 #include <Entry.h> 26 #include <File.h> 27 #include <FindDirectory.h> 28 #include <NodeMonitor.h> 29 #include <Path.h> 30 #include <String.h> 31 #include <View.h> 32 33 #include <kb_mouse_settings.h> 34 #include <keyboard_mouse_driver.h> 35 #include <touchpad_settings.h> 36 37 #include "movement_maker.h" 38 39 40 #undef TRACE 41 //#define TRACE_MOUSE_DEVICE 42 #ifdef TRACE_MOUSE_DEVICE 43 44 class FunctionTracer { 45 public: 46 FunctionTracer(const void* pointer, const char* className, 47 const char* functionName, 48 int32& depth) 49 : fFunctionName(), 50 fPrepend(), 51 fFunctionDepth(depth), 52 fPointer(pointer) 53 { 54 fFunctionDepth++; 55 fPrepend.Append(' ', fFunctionDepth * 2); 56 fFunctionName << className << "::" << functionName << "()"; 57 58 debug_printf("%p -> %s%s {\n", fPointer, fPrepend.String(), 59 fFunctionName.String()); 60 } 61 62 ~FunctionTracer() 63 { 64 debug_printf("%p -> %s}\n", fPointer, fPrepend.String()); 65 fFunctionDepth--; 66 } 67 68 private: 69 BString fFunctionName; 70 BString fPrepend; 71 int32& fFunctionDepth; 72 const void* fPointer; 73 }; 74 75 76 static int32 sFunctionDepth = -1; 77 # define MD_CALLED(x...) FunctionTracer _ft(this, "MouseDevice", \ 78 __FUNCTION__, sFunctionDepth) 79 # define MID_CALLED(x...) FunctionTracer _ft(this, "MouseInputDevice", \ 80 __FUNCTION__, sFunctionDepth) 81 # define TRACE(x...) do { BString _to; \ 82 _to.Append(' ', (sFunctionDepth + 1) * 2); \ 83 debug_printf("%p -> %s", this, _to.String()); \ 84 debug_printf(x); } while (0) 85 # define LOG_EVENT(text...) do {} while (0) 86 # define LOG_ERR(text...) TRACE(text) 87 #else 88 # define TRACE(x...) do {} while (0) 89 # define MD_CALLED(x...) TRACE(x) 90 # define MID_CALLED(x...) TRACE(x) 91 # define LOG_ERR(x...) debug_printf(x) 92 # define LOG_EVENT(x...) TRACE(x) 93 #endif 94 95 96 const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4; 97 const static char* kMouseDevicesDirectory = "/dev/input/mouse"; 98 const static char* kTouchpadDevicesDirectory = "/dev/input/touchpad"; 99 100 101 class MouseDevice { 102 public: 103 MouseDevice(MouseInputDevice& target, 104 const char* path); 105 ~MouseDevice(); 106 107 status_t Start(); 108 void Stop(); 109 110 status_t UpdateSettings(); 111 status_t UpdateTouchpadSettings(const BMessage* message); 112 113 const char* Path() const { return fPath.String(); } 114 input_device_ref* DeviceRef() { return &fDeviceRef; } 115 116 private: 117 char* _BuildShortName() const; 118 119 static status_t _ControlThreadEntry(void* arg); 120 void _ControlThread(); 121 void _ControlThreadCleanup(); 122 void _UpdateSettings(); 123 124 status_t _GetTouchpadSettingsPath(BPath& path); 125 status_t _UpdateTouchpadSettings(BMessage* message); 126 127 BMessage* _BuildMouseMessage(uint32 what, 128 uint64 when, uint32 buttons, 129 int32 deltaX, int32 deltaY) const; 130 void _ComputeAcceleration( 131 const mouse_movement& movements, 132 int32& deltaX, int32& deltaY, 133 float& historyDeltaX, 134 float& historyDeltaY) const; 135 uint32 _RemapButtons(uint32 buttons) const; 136 137 private: 138 MouseInputDevice& fTarget; 139 BString fPath; 140 int fDevice; 141 142 input_device_ref fDeviceRef; 143 mouse_settings fSettings; 144 bool fDeviceRemapsButtons; 145 146 thread_id fThread; 147 volatile bool fActive; 148 volatile bool fUpdateSettings; 149 150 bool fIsTouchpad; 151 TouchpadMovement fTouchpadMovementMaker; 152 BMessage* fTouchpadSettingsMessage; 153 BLocker fTouchpadSettingsLock; 154 }; 155 156 157 extern "C" BInputServerDevice* 158 instantiate_input_device() 159 { 160 return new(std::nothrow) MouseInputDevice(); 161 } 162 163 164 // #pragma mark - 165 166 167 MouseDevice::MouseDevice(MouseInputDevice& target, const char* driverPath) 168 : 169 fTarget(target), 170 fPath(driverPath), 171 fDevice(-1), 172 fDeviceRemapsButtons(false), 173 fThread(-1), 174 fActive(false), 175 fUpdateSettings(false), 176 fIsTouchpad(false), 177 fTouchpadSettingsMessage(NULL), 178 fTouchpadSettingsLock("Touchpad settings lock") 179 { 180 MD_CALLED(); 181 182 fDeviceRef.name = _BuildShortName(); 183 fDeviceRef.type = B_POINTING_DEVICE; 184 fDeviceRef.cookie = this; 185 186 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 187 for (int i = 0; i < B_MAX_MOUSE_BUTTONS; i++) 188 fSettings.map.button[i] = B_MOUSE_BUTTON(i + 1); 189 #endif 190 }; 191 192 193 MouseDevice::~MouseDevice() 194 { 195 MD_CALLED(); 196 TRACE("delete\n"); 197 198 if (fActive) 199 Stop(); 200 201 free(fDeviceRef.name); 202 delete fTouchpadSettingsMessage; 203 } 204 205 206 status_t 207 MouseDevice::Start() 208 { 209 MD_CALLED(); 210 211 fDevice = open(fPath.String(), O_RDWR); 212 // let the control thread handle any error on opening the device 213 214 char threadName[B_OS_NAME_LENGTH]; 215 snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fDeviceRef.name); 216 217 fThread = spawn_thread(_ControlThreadEntry, threadName, 218 kMouseThreadPriority, (void*)this); 219 220 status_t status; 221 if (fThread < 0) 222 status = fThread; 223 else { 224 fActive = true; 225 status = resume_thread(fThread); 226 } 227 228 if (status < B_OK) { 229 LOG_ERR("%s: can't spawn/resume watching thread: %s\n", 230 fDeviceRef.name, strerror(status)); 231 if (fDevice >= 0) 232 close(fDevice); 233 234 return status; 235 } 236 237 return fDevice >= 0 ? B_OK : B_ERROR; 238 } 239 240 241 void 242 MouseDevice::Stop() 243 { 244 MD_CALLED(); 245 246 fActive = false; 247 // this will stop the thread as soon as it reads the next packet 248 249 close(fDevice); 250 fDevice = -1; 251 252 if (fThread >= 0) { 253 // unblock the thread, which might wait on a semaphore. 254 suspend_thread(fThread); 255 resume_thread(fThread); 256 257 status_t dummy; 258 wait_for_thread(fThread, &dummy); 259 } 260 } 261 262 263 status_t 264 MouseDevice::UpdateSettings() 265 { 266 MD_CALLED(); 267 268 if (fThread < 0) 269 return B_ERROR; 270 271 // trigger updating the settings in the control thread 272 fUpdateSettings = true; 273 274 return B_OK; 275 } 276 277 278 status_t 279 MouseDevice::UpdateTouchpadSettings(const BMessage* message) 280 { 281 if (!fIsTouchpad) 282 return B_BAD_TYPE; 283 if (fThread < 0) 284 return B_ERROR; 285 286 BAutolock _(fTouchpadSettingsLock); 287 288 // trigger updating the settings in the control thread 289 fUpdateSettings = true; 290 291 delete fTouchpadSettingsMessage; 292 fTouchpadSettingsMessage = new BMessage(*message); 293 if (fTouchpadSettingsMessage == NULL) 294 return B_NO_MEMORY; 295 296 return B_OK; 297 } 298 299 300 char* 301 MouseDevice::_BuildShortName() const 302 { 303 // TODO It would be simpler and better to use B_GET_DEVICE_NAME, but... 304 // - This is currently called before the device is open 305 // - We need to implement that in our input drivers first 306 BString string(fPath); 307 BString deviceName; 308 BString name; 309 310 int32 slash = string.FindLast("/"); 311 string.CopyInto(deviceName, slash + 1, string.Length() - slash); 312 // FIXME the device name may be more than just a number (for example 313 // ibm_trackpoint_0) 314 int32 index = atoi(deviceName.String()) + 1; 315 316 int32 previousSlash = string.FindLast("/", slash); 317 string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1); 318 319 if (name == "ps2") 320 name = "PS/2"; 321 322 if (name.Length() <= 4) 323 name.ToUpper(); 324 else 325 name.Capitalize(); 326 327 // Check the whole string for "touchpad" because it's a different directory 328 // FIXME use MS_IS_TOUCHPAD ioctl instead (or fIsTouchpad which caches its 329 // result) but this can only be done after the control thread is running 330 if (string.FindFirst("touchpad") >= 0) { 331 name << " Touchpad "; 332 } else if (deviceName.FindFirst("trackpoint") >= 0) { 333 // That's always PS/2, so don't keep the bus name 334 name = "Trackpoint "; 335 } else { 336 if (deviceName.FindFirst("intelli") >= 0) 337 name.Prepend("Extended "); 338 339 name << " Mouse "; 340 } 341 name << index; 342 343 return strdup(name.String()); 344 } 345 346 347 // #pragma mark - control thread 348 349 350 status_t 351 MouseDevice::_ControlThreadEntry(void* arg) 352 { 353 MouseDevice* device = (MouseDevice*)arg; 354 device->_ControlThread(); 355 return B_OK; 356 } 357 358 359 void 360 MouseDevice::_ControlThread() 361 { 362 MD_CALLED(); 363 364 if (fDevice < 0) { 365 _ControlThreadCleanup(); 366 // TOAST! 367 return; 368 } 369 370 // touchpad settings 371 touchpad_specs touchpadSpecs; 372 if (ioctl(fDevice, MS_IS_TOUCHPAD, &touchpadSpecs, sizeof(touchpadSpecs)) == B_OK) { 373 TRACE("is touchpad %s\n", fPath.String()); 374 fIsTouchpad = true; 375 376 touchpad_settings settings; 377 settings = kDefaultTouchpadSettings; 378 379 BPath path; 380 status_t status = _GetTouchpadSettingsPath(path); 381 BFile settingsFile(path.Path(), B_READ_ONLY); 382 if (status == B_OK && settingsFile.InitCheck() == B_OK) { 383 if (settingsFile.Read(&settings, sizeof(touchpad_settings)) 384 != sizeof(touchpad_settings)) { 385 TRACE("failed to load settings\n"); 386 } 387 } 388 389 fTouchpadMovementMaker.SetSpecs(touchpadSpecs); 390 fTouchpadMovementMaker.SetSettings(settings); 391 } 392 393 _UpdateSettings(); 394 395 uint32 lastButtons = 0; 396 float historyDeltaX = 0.0; 397 float historyDeltaY = 0.0; 398 399 static const bigtime_t kTransferDelay = 1000000 / 125; 400 // 125 transfers per second should be more than enough 401 #define USE_REGULAR_INTERVAL 1 402 #if USE_REGULAR_INTERVAL 403 bigtime_t nextTransferTime = system_time() + kTransferDelay; 404 #endif 405 406 // touchpads only 407 touchpad_movement lastTouchpadMovement; 408 bigtime_t touchpadEventTimeout = B_INFINITE_TIMEOUT; 409 410 while (fActive) { 411 mouse_movement movements; 412 413 #if USE_REGULAR_INTERVAL 414 snooze_until(nextTransferTime, B_SYSTEM_TIMEBASE); 415 nextTransferTime += kTransferDelay; 416 #endif 417 418 if (!fIsTouchpad) { 419 if (ioctl(fDevice, MS_READ, &movements, sizeof(movements)) != B_OK) { 420 LOG_ERR("Mouse device exiting, %s\n", strerror(errno)); 421 _ControlThreadCleanup(); 422 // TOAST! 423 return; 424 } 425 } else { 426 touchpad_read read; 427 read.timeout = touchpadEventTimeout; 428 429 status_t status = ioctl(fDevice, MS_READ_TOUCHPAD, &read, sizeof(read)); 430 if (status < 0) 431 status = errno; 432 if (status != B_OK && status != B_TIMED_OUT) { 433 LOG_ERR("Mouse (touchpad) device exiting, %s\n", strerror(errno)); 434 _ControlThreadCleanup(); 435 // TOAST! 436 return; 437 } else if (status == B_TIMED_OUT) { 438 read.event = MS_READ_TOUCHPAD; 439 read.u.touchpad = lastTouchpadMovement; 440 } 441 442 if (read.event == MS_READ_TOUCHPAD) { 443 lastTouchpadMovement = read.u.touchpad; 444 status = fTouchpadMovementMaker.EventToMovement(&read.u.touchpad, 445 &movements, touchpadEventTimeout); 446 } else if (read.event == MS_READ) { 447 movements = read.u.mouse; 448 touchpadEventTimeout = -1; 449 } 450 451 if (status != B_OK) 452 continue; 453 } 454 455 // take care of updating the settings first, if necessary 456 if (fUpdateSettings) { 457 fUpdateSettings = false; 458 if (fIsTouchpad) { 459 BAutolock _(fTouchpadSettingsLock); 460 if (fTouchpadSettingsMessage != NULL) { 461 _UpdateTouchpadSettings(fTouchpadSettingsMessage); 462 delete fTouchpadSettingsMessage; 463 fTouchpadSettingsMessage = NULL; 464 } else 465 _UpdateSettings(); 466 } else 467 _UpdateSettings(); 468 } 469 470 uint32 buttons = lastButtons ^ movements.buttons; 471 472 uint32 remappedButtons = _RemapButtons(movements.buttons); 473 int32 deltaX, deltaY; 474 _ComputeAcceleration(movements, deltaX, deltaY, historyDeltaX, 475 historyDeltaY); 476 477 LOG_EVENT("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, " 478 "wheel_x:%ld, wheel_y:%ld\n", 479 fDeviceRef.name, movements.buttons, 480 movements.xdelta, movements.ydelta, movements.clicks, 481 movements.wheel_xdelta, movements.wheel_ydelta); 482 LOG_EVENT("%s: x: %ld, y: %ld (%.4f, %.4f)\n", fDeviceRef.name, 483 deltaX, deltaY, historyDeltaX, historyDeltaY); 484 485 // Send single messages for each event 486 487 if (buttons != 0) { 488 bool pressedButton = (buttons & movements.buttons) > 0; 489 BMessage* message = _BuildMouseMessage( 490 pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, 491 movements.timestamp, remappedButtons, deltaX, deltaY); 492 if (message != NULL) { 493 if (pressedButton) { 494 message->AddInt32("clicks", movements.clicks); 495 LOG_EVENT("B_MOUSE_DOWN\n"); 496 } else 497 LOG_EVENT("B_MOUSE_UP\n"); 498 499 fTarget.EnqueueMessage(message); 500 lastButtons = movements.buttons; 501 } 502 } 503 504 if (movements.xdelta != 0 || movements.ydelta != 0) { 505 BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, 506 movements.timestamp, remappedButtons, deltaX, deltaY); 507 if (message != NULL) 508 fTarget.EnqueueMessage(message); 509 } 510 511 if (movements.wheel_ydelta != 0 || movements.wheel_xdelta != 0) { 512 BMessage* message = new BMessage(B_MOUSE_WHEEL_CHANGED); 513 if (message == NULL) 514 continue; 515 516 if (message->AddInt64("when", movements.timestamp) == B_OK 517 && message->AddFloat("be:wheel_delta_x", 518 movements.wheel_xdelta) == B_OK 519 && message->AddFloat("be:wheel_delta_y", 520 movements.wheel_ydelta) == B_OK 521 && message->AddInt32("be:device_subtype", 522 fIsTouchpad 523 ? B_TOUCHPAD_DEVICE_SUBTYPE 524 : B_MOUSE_DEVICE_SUBTYPE) == B_OK) 525 fTarget.EnqueueMessage(message); 526 else 527 delete message; 528 } 529 530 #if !USE_REGULAR_INTERVAL 531 snooze(kTransferDelay); 532 #endif 533 } 534 } 535 536 537 void 538 MouseDevice::_ControlThreadCleanup() 539 { 540 // NOTE: Only executed when the control thread detected an error 541 // and from within the control thread! 542 543 if (fActive) { 544 fThread = -1; 545 fTarget._RemoveDevice(fPath.String()); 546 } else { 547 // In case active is already false, another thread 548 // waits for this thread to quit, and may already hold 549 // locks that _RemoveDevice() wants to acquire. In other 550 // words, the device is already being removed, so we simply 551 // quit here. 552 } 553 } 554 555 556 void 557 MouseDevice::_UpdateSettings() 558 { 559 MD_CALLED(); 560 // retrieve current values 561 562 if (get_mouse_map(fDeviceRef.name, &fSettings.map) != B_OK) 563 LOG_ERR("error when get_mouse_map\n"); 564 else 565 fDeviceRemapsButtons = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK; 566 567 if (get_click_speed(fDeviceRef.name, &fSettings.click_speed) == B_OK) { 568 if (fIsTouchpad) 569 fTouchpadMovementMaker.click_speed = fSettings.click_speed; 570 ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed); 571 } else 572 LOG_ERR("error when get_click_speed\n"); 573 574 if (get_mouse_speed(fDeviceRef.name, &fSettings.accel.speed) != B_OK) 575 LOG_ERR("error when get_mouse_speed\n"); 576 else { 577 if (get_mouse_acceleration(fDeviceRef.name, &fSettings.accel.accel_factor) != B_OK) 578 LOG_ERR("error when get_mouse_acceleration\n"); 579 else { 580 mouse_accel accel; 581 ioctl(fDevice, MS_GET_ACCEL, &accel); 582 accel.speed = fSettings.accel.speed; 583 accel.accel_factor = fSettings.accel.accel_factor; 584 ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel); 585 } 586 } 587 588 if (get_mouse_type(fDeviceRef.name, &fSettings.type) != B_OK) 589 LOG_ERR("error when get_mouse_type\n"); 590 else 591 ioctl(fDevice, MS_SET_TYPE, &fSettings.type); 592 } 593 594 595 status_t 596 MouseDevice::_GetTouchpadSettingsPath(BPath& path) 597 { 598 status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); 599 if (status < B_OK) 600 return status; 601 return path.Append(TOUCHPAD_SETTINGS_FILE); 602 } 603 604 605 status_t 606 MouseDevice::_UpdateTouchpadSettings(BMessage* message) 607 { 608 touchpad_settings settings; 609 message->FindBool("scroll_twofinger", &settings.scroll_twofinger); 610 message->FindBool("scroll_twofinger_horizontal", 611 &settings.scroll_twofinger_horizontal); 612 message->FindFloat("scroll_rightrange", 613 &settings.scroll_rightrange); 614 message->FindFloat("scroll_bottomrange", 615 &settings.scroll_bottomrange); 616 617 message->FindInt16("scroll_xstepsize", 618 (int16*)&settings.scroll_xstepsize); 619 message->FindInt16("scroll_ystepsize", 620 (int16*)&settings.scroll_ystepsize); 621 message->FindInt8("scroll_acceleration", 622 (int8*)&settings.scroll_acceleration); 623 message->FindInt8("tapgesture_sensibility", 624 (int8*)&settings.tapgesture_sensibility); 625 626 if (fIsTouchpad) 627 fTouchpadMovementMaker.SetSettings(settings); 628 629 return B_OK; 630 } 631 632 633 BMessage* 634 MouseDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, 635 int32 deltaX, int32 deltaY) const 636 { 637 BMessage* message = new BMessage(what); 638 if (message == NULL) 639 return NULL; 640 641 if (message->AddInt64("when", when) < B_OK 642 || message->AddInt32("buttons", buttons) < B_OK 643 || message->AddInt32("x", deltaX) < B_OK 644 || message->AddInt32("y", deltaY) < B_OK 645 || message->AddInt32("be:device_subtype", 646 fIsTouchpad ? B_TOUCHPAD_DEVICE_SUBTYPE : B_MOUSE_DEVICE_SUBTYPE) < B_OK) { 647 delete message; 648 return NULL; 649 } 650 651 return message; 652 } 653 654 655 void 656 MouseDevice::_ComputeAcceleration(const mouse_movement& movements, 657 int32& _deltaX, int32& _deltaY, float& historyDeltaX, 658 float& historyDeltaY) const 659 { 660 // basic mouse speed 661 float deltaX = (float)movements.xdelta * fSettings.accel.speed / 65536.0 662 + historyDeltaX; 663 float deltaY = (float)movements.ydelta * fSettings.accel.speed / 65536.0 664 + historyDeltaY; 665 666 // acceleration 667 double acceleration = 1; 668 if (fSettings.accel.accel_factor) { 669 acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY) 670 * fSettings.accel.accel_factor / 524288.0; 671 } 672 673 deltaX *= acceleration; 674 deltaY *= acceleration; 675 676 if (deltaX >= 0) 677 _deltaX = (int32)floorf(deltaX); 678 else 679 _deltaX = (int32)ceilf(deltaX); 680 681 if (deltaY >= 0) 682 _deltaY = (int32)floorf(deltaY); 683 else 684 _deltaY = (int32)ceilf(deltaY); 685 686 historyDeltaX = deltaX - _deltaX; 687 historyDeltaY = deltaY - _deltaY; 688 } 689 690 691 uint32 692 MouseDevice::_RemapButtons(uint32 buttons) const 693 { 694 if (fDeviceRemapsButtons) 695 return buttons; 696 697 uint32 newButtons = 0; 698 for (int32 i = 0; buttons; i++) { 699 if (buttons & 0x1) { 700 #if defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(HAIKU_TARGET_PLATFORM_DANO) 701 newButtons |= fSettings.map.button[i]; 702 #else 703 if (i == 0) 704 newButtons |= fSettings.map.left; 705 if (i == 1) 706 newButtons |= fSettings.map.right; 707 if (i == 2) 708 newButtons |= fSettings.map.middle; 709 #endif 710 } 711 buttons >>= 1; 712 } 713 714 return newButtons; 715 } 716 717 718 // #pragma mark - 719 720 721 MouseInputDevice::MouseInputDevice() 722 : 723 fDevices(2, true), 724 fDeviceListLock("MouseInputDevice list") 725 { 726 MID_CALLED(); 727 728 StartMonitoringDevice(kMouseDevicesDirectory); 729 StartMonitoringDevice(kTouchpadDevicesDirectory); 730 _RecursiveScan(kMouseDevicesDirectory); 731 _RecursiveScan(kTouchpadDevicesDirectory); 732 } 733 734 735 MouseInputDevice::~MouseInputDevice() 736 { 737 MID_CALLED(); 738 739 StopMonitoringDevice(kTouchpadDevicesDirectory); 740 StopMonitoringDevice(kMouseDevicesDirectory); 741 fDevices.MakeEmpty(); 742 } 743 744 745 status_t 746 MouseInputDevice::InitCheck() 747 { 748 MID_CALLED(); 749 750 return BInputServerDevice::InitCheck(); 751 } 752 753 754 status_t 755 MouseInputDevice::Start(const char* name, void* cookie) 756 { 757 MID_CALLED(); 758 759 MouseDevice* device = (MouseDevice*)cookie; 760 761 return device->Start(); 762 } 763 764 765 status_t 766 MouseInputDevice::Stop(const char* name, void* cookie) 767 { 768 TRACE("%s(%s)\n", __PRETTY_FUNCTION__, name); 769 770 MouseDevice* device = (MouseDevice*)cookie; 771 device->Stop(); 772 773 return B_OK; 774 } 775 776 777 status_t 778 MouseInputDevice::Control(const char* name, void* cookie, 779 uint32 command, BMessage* message) 780 { 781 TRACE("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command); 782 783 MouseDevice* device = (MouseDevice*)cookie; 784 785 if (command == B_NODE_MONITOR) 786 return _HandleMonitor(message); 787 788 if (command == B_SET_TOUCHPAD_SETTINGS) 789 return device->UpdateTouchpadSettings(message); 790 791 if (command >= B_MOUSE_TYPE_CHANGED 792 && command <= B_MOUSE_ACCELERATION_CHANGED) 793 return device->UpdateSettings(); 794 795 return B_BAD_VALUE; 796 } 797 798 799 status_t 800 MouseInputDevice::_HandleMonitor(BMessage* message) 801 { 802 MID_CALLED(); 803 804 const char* path; 805 int32 opcode; 806 if (message->FindInt32("opcode", &opcode) != B_OK 807 || (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED) 808 || message->FindString("path", &path) != B_OK) 809 return B_BAD_VALUE; 810 811 if (opcode == B_ENTRY_CREATED) 812 return _AddDevice(path); 813 814 #if 0 815 return _RemoveDevice(path); 816 #else 817 // Don't handle B_ENTRY_REMOVED, let the control thread take care of it. 818 return B_OK; 819 #endif 820 } 821 822 823 void 824 MouseInputDevice::_RecursiveScan(const char* directory) 825 { 826 MID_CALLED(); 827 828 BEntry entry; 829 BDirectory dir(directory); 830 while (dir.GetNextEntry(&entry) == B_OK) { 831 BPath path; 832 entry.GetPath(&path); 833 834 if (!strcmp(path.Leaf(), "serial")) { 835 // skip serial 836 continue; 837 } 838 839 if (entry.IsDirectory()) 840 _RecursiveScan(path.Path()); 841 else 842 _AddDevice(path.Path()); 843 } 844 } 845 846 847 MouseDevice* 848 MouseInputDevice::_FindDevice(const char* path) const 849 { 850 MID_CALLED(); 851 852 for (int32 i = fDevices.CountItems() - 1; i >= 0; i--) { 853 MouseDevice* device = fDevices.ItemAt(i); 854 if (strcmp(device->Path(), path) == 0) 855 return device; 856 } 857 858 return NULL; 859 } 860 861 862 status_t 863 MouseInputDevice::_AddDevice(const char* path) 864 { 865 MID_CALLED(); 866 867 BAutolock _(fDeviceListLock); 868 869 _RemoveDevice(path); 870 871 MouseDevice* device = new(std::nothrow) MouseDevice(*this, path); 872 if (device == NULL) { 873 TRACE("No memory\n"); 874 return B_NO_MEMORY; 875 } 876 877 if (!fDevices.AddItem(device)) { 878 TRACE("No memory in list\n"); 879 delete device; 880 return B_NO_MEMORY; 881 } 882 883 input_device_ref* devices[2]; 884 devices[0] = device->DeviceRef(); 885 devices[1] = NULL; 886 887 TRACE("adding path: %s, name: %s\n", path, devices[0]->name); 888 889 return RegisterDevices(devices); 890 } 891 892 893 status_t 894 MouseInputDevice::_RemoveDevice(const char* path) 895 { 896 MID_CALLED(); 897 898 BAutolock _(fDeviceListLock); 899 900 MouseDevice* device = _FindDevice(path); 901 if (device == NULL) { 902 TRACE("%s not found\n", path); 903 return B_ENTRY_NOT_FOUND; 904 } 905 906 input_device_ref* devices[2]; 907 devices[0] = device->DeviceRef(); 908 devices[1] = NULL; 909 910 TRACE("removing path: %s, name: %s\n", path, devices[0]->name); 911 912 UnregisterDevices(devices); 913 914 fDevices.RemoveItem(device); 915 916 return B_OK; 917 } 918